OXP mission offering

From Elite Wiki
Revision as of 20:12, 8 June 2010 by Eric Walch (talk | contribs) (Added a message of the old missionscreen creation being outdated and replaced with a new method.)

How mission offering should be done with Legacy script

Location for offering

Missions should only be offered while being docked. To prevent offering on special stations make sure you are docked at the main station:

conditions = ("dockedAtMainStation_bool equal YES")

Only if you are offering something on a special station you can check for just being docked, but then you should also check the station name.

 conditions = ("status_string equal STATUS_DOCKED", "dockedStationName_string equal Your Station Name")

Here is " Your Station Name" the name of the station as defined in shipyard.plist under "name". You could skip the first test for being docked as dockedStationName_string only has the stationname if you are docked.

Conditions for offering

Before placing text also check if the missionscreen is not in use. (See the documents in the downloadeble package below for more info)

For Oollite versions up to 1.68 that do not know the "notequal" condition or for compatibillity with those versions use:

conditions = (gui_screen_string oneof GUI_SCREEN_MAIN, GUI_SCREEN_STATUS).

At the end of the docking procedure the script runs immediately for one time with gui_screen_string = GUI_SCREEN_MAIN but already with status_string = STATUD_DOCKED. All following moments the script runs with as gui_screen_string the screen you are looking at. When you do nothing further this will be the GUI_SCREEN_STATUS . (= F5) You could also explicit check for the mission screen and put your whole action in the else line.

conditions = (gui_screen_string equal GUI_SCREEN_MISSION); do = (); else = (your stuff);

But this involves an extra nested condition, so most people will probably prefer the first method. Versions 1.69 and newer will have a not-equal option.

conditions = (gui_screen_string notequal GUI_SCREEN_MISSION).

Setting up the message

In the do part you must set a mission image. If you have no image set it to "none", otherwise you can get an image from a previous offer. Be aware that some computers are case sensitive so use the same casing as the actual picture. The pictures are placed in a folder called "images", inside the OXP.

setMissionImage: none
       or
setMissionImage: my_pict.png

Then set the output to the MissionScreen with

setGuiToMissionScreen

This command creates an empty missionscreen and any text after this will go to this missionscreen. The text is then placed with:

addMissionText: entryname

"Entryname" is a key value in the file missiontext.plist If you use a second addMissionText commands the text is added below the previous. If you add to much text it runs off the screen and is lost. So make sure you don't use to much text. The system automatic puts a "hit space to continue" message at the bottom. On hitting this space key the MissionScreen will clear and the StatusScreen is put up. There exists also a command to put up the StatusScreen but you don't need that with offering.

Offering with Choices

When you in addition use the command:

setMissionChoices: entryname

the "hit space to continue" message is replaced by your choices. Your choices is in this case a key entry in the missiontext.plist file with as contents an array. On the bottom of your screen you see the contents of the array and if you select one, the variable "missionChoice_string" contains the name of the chosen entry-string. When you are offering choices first make clear that:

conditions = ("missionChoice_string undefined")

And in the following conditions:

conditions = ("missionChoice_string equal Your String")

And make sure that on all possible choices that the player can make, the choice is reseted: "resetMissionChoice"

Some excisting missions reset the choices just before the offering itself, but in that case it is possible that the choices of another active mission that is offered on the same station is reset before it can act on the choices. If you want to play save, just reset the choices on launching so they are clear on the next docking. Also use distinctive text for "Your String" and not just "YES" or "NO" as other badly written OXP could react on those often used responses.

Setting up the mission desciption

If you start a mission it is wise to add a short description and or a location for later reference by the player with:

setMissionDescription: entryname
addMissionDestination: planet_number

Entryname is a key value in the missiontext.plist file. This must be a short description as long text won't wrap around but runs off the screen at the right side. For planet_numbet you ca use a plain number between 0 and 255 or a variable between square brackets. The destination is visible as a red cross in the galactic chart. If the mission is over you clear this description and the location with:

clearMissionDescription
removeMissionDestination: planet_number

Notice that you do not need to specify the mission name in setting and clearing the missionDescription. The system automatic uses the name of the missionscript that uses this command to store the description. This also means that you can not use these two commands outside the missionscript like inside a death_action of a ship. The best lessons are taken by examining existing scripts. You can download more info and a test OXP here: Mission Offering Protocol

How mission offering should be done with JS

The method described below is only needed with Oolite 1.73 or older. Starting with Oolite 1.74 a new method for displaying a mission screen is introduced that is much easier in use and much less likely to give conflicts between different oxp's. So, when you now start creating a new script, forget the stuff below and start using the new method for displaying a missionscreen. The code samples below is at the best useful to understand older code you might want to alter.


For java script all above about legacy scripts applies. Just make sure you don't set up a message when there is already a Missionscreen or a Reportscreen on display. Also don't set up your missionscreen when there are valid mission choices they don't belong to you. With JS every oxp can react on an handler and when your handler code is triggered you must verify no other oxp has already reacted on that handler before you.

script example for missionoffering on JS

Below is an example script for clash free mission offering. It should work with Oolite version 1.73 and newer.

this.name        = "demo"; 
this.author      = "eric walch";
this.copyright   = "© 2008 eric walch.";
this.description = "Empty script structure that handles population and mission offering"; 
this.version     = "0.0"; 

// N.B. Works only with 1.73+.

// startUp only runs once at startup before the demoscreen shows up.
this.startUp = function()
{
    this.reset(); // this.reset() fires not for a cmdr Jameson. When needed for a Jameson, call it here.
}

// this runs after loading in a saved game. missionVariables are read in at this point.
this.reset = function()
{
   this.mustPopulate = true;
   /* used for adding ships after a first launch.
   This way you don't have to time consuming check every launch if a ship was already there.
   */
}

this.shipWillDockWithStation = function(station)
{
   if(missionVariables.offering) missionVariables.offering = null;
   /* When using the missionVariables.offering variable in script you need this function to clear the
   variable in case the player launched from within the missionscreen without making choices. By clearing
   this, most scripts that are created acording this layout will automatic do the offer again.
   */
   
   /*
   This is also the place to add your messages to the arrival report with:
   if(condition) player.addMessageToArrivalReport(expandDescription("Your message"));
   */
}

this.shipDockedWithStation = function(station)
{
       // an other eventhandler could have launched the ship already when it fires before this script.
       if(player.ship.docked) this.missionOffers();
}

this.missionScreenEnded = this.missionChoiceWasReset = this.reportScreenEnded = function()
{
   if(!player.ship.docked) return;
   if(mission.choice) this.choiceEvaluation();
   this.missionOffers();
}

this.missionOffers = function()
{
   if (guiScreen == "GUI_SCREEN_MISSION" || guiScreen == "GUI_SCREEN_REPORT") return; 
	// there will be a "missionScreenEnded" or "reportScreenEnded" in future to react uppon.
   if (missionVariables.offering || (mission.choice && mission.choice != "")) return;
	// when "missionVariables.offering" or "mission.choice" are present it means that an other script claimed the mission_screen.
   if (player.ship.dockedStation.isMainStation)
   {
       //  Your stuff for the main station
       /*
       Missionscreens are set up using the command:
       mission.runMissionScreen("mission_text", "backgroundscreen.png", "choices_text", "ship_role", "music")
       You can transfer 5 variables at once that formerly had to set or cleared each seperately.
       When not needed you can transfer a null. nulls at the end can be omitted, in between must be used.
       
       When you do an offer you must set a variable to tell an offer is made. It is not safe to use the main mission
       variable for this. Use missionVariables.offering for this. At the same time you know an other script is busy
       offering when this variable is set. In case the player launched from within a missionscreen without making an
       offer, the missionVariables.offering should be reset by script. Please do it on docking and not launching.
       That way other oxp's that might need the value get an last change on using its content.
       */
   }
   else if (player.ship.dockedStation.shipDescription == "My Station")
   {
       // Your stuff for a special named station
   }
}

this.choiceEvaluation = function()
{
   if (missionVariables.offering == "MY_OFFER")
   {
        /* It is saver to not use a simple YES, but use a YES_MISSION. This just for the case there is
        a conflict with an other bad written oxp that also has a simple YES as answer. */
       if(mission.choice == "YES_MISSION")
       {
           // put your code here. 
           missionVariables.offering = null;
           mission.choice = null;
           /* resetting the mission.choice triggers the "missionChoiceWasReset" handler. 
           therefor this must always happen after other variables are reset to prefent that the script
           tries to run again.  */
       }
       else
       {
           if (mission.choice == "NO_MISSION")
           {
               // put your code here
               missionVariables.offering = null;
               mission.choice = null;
           } else {missionVariables.offering = null} // one should never get here.
       }
   }
}

this.setUpShips = function()
{
   // Put here your code that populates the system.
}

this.shipExitedWitchspace = function()
{
   if(system.isInterstellarSpace) return;
   this.setUpShips();
   // Put here your code else than setting ships up.
}

this.playerEnteredNewGalaxy = function(Galaxy)
{
   // This handler will be rarely needed.
}

this.shipLaunchedFromStation = function()
{
  /* The first launch after a restart the system must be populated after a launch.
  The other times it happens after a WitchspaceJump */
  if(this.mustPopulate) {this.setUpShips(); this.mustPopulate = false}
   // put here your other code.
}