The TraderMissions tutorial is enough to give the new player a feeling for how the game works, and the tutorial tutorial in the previous section is enough to give you an idea of how to make scenarios. But there are more features to the engine that weren't featured. Note that, unlike in the last section where you could type along with the instructions, this section will only be providing examples of how to set up the various features: it's up to you to implement them the way you want to.
Most of these features come from various tricks you can do in missions( reference), conditions( reference), and actions( reference): consulting the reference as you go along may be helpful.
One of the conditions is 'afterDays', which is only true after a certain number of days have passed (since the player accepted the mission). This can be used to set timeouts; if the player hasn't completed a mission in 10 days, for instance, you can have it fail. Such a setup looks like this:
child conditions.add(timeoutMissionSupplies <condition> { field afterDays = 7; child action.add(timeoutMissionSuppliesAdmonishment <action> { field message = " An angry transmission wakes you from "+ "your lazy slumber. It is, as you had feared, from "+ "Earth.\n\n 'Pilot!' the shipping official on screen "+ "bellows, 'Where are those supplies?'\n\n" + " 'Well, uh...' you start to explain\n\n" + " 'Nevermind. You're fired!'"; child takeCargo.add missionSupplies; field endMission = 1; }); });
Another sort of mission you may run across is a kill quest. This is set up via the spawnFleet action (which spawns whatever fleet or fleets you tell it to) in conjunction with some condition. So you'd have a 'destroy this guy' mission, and the spawnFleet action would take effect when the player was in the sector that the enemy was rumored to be in:
child conditions.add(createKillQuest <condition> { child playerAt.add DeepSpace; child action.add(createKillQuestShips <action> { child spawnFleet.add loneship; }); });
There's a complimentary spawnDead condition which allows us to check whether or not a fleet that we've spawned has been destroyed. For kill quests, this is your victory condition:
child conditions.add(killQuestFinish <condition> { child spawnDead.add loneship; child action.add(killQuestFinishAction <action> { field money = 5500; field endMission = 1; field message = " A transmission comes in from Earth congratulating "+ "you on your victory. And sending you money."; }); });
Escorts are the other side of the coin: you can set up a mission where the player must protect a group of ships. This involves spawning a fleet where the player gets the mission:
child spawnFleet.add(banannaFleet <fleet> { child owner.add Humankind; child ships.add PeacefulTrader; field type = 1.0; # patrol, for now field reaction = 2.0; field greeting = "Following your lead...."; field followPlayer = 1.0; });
Note that the followPlayer field for this fleet is 1.0; this means that this fleet will follow the player when the player jumps to another sector; it's very important to have that for escort missions, otherwise your escorts won't follow you!
The victory condition for an escort fleet is simply getting to wherever it was you needed to go without dying. That's just a simple 'playerAt' condition. We'll end the mission ourselves if our escorts don't make it:
child conditions.add(failEscort <condition> { child spawnDead.add banannaFleet; child action.add(failEscortAction <action> { field message = " You got the guy you were supposed to guard "+ "blown up on a milk run like this. Not exactly the high point "+ "of your career."; field endMission = 1; }); });
Of course, there are many variations on this: You could have escorts that it doesn't matter if they get destroyed, you could have escorts that, if destroyed, penalize you somehow, or you could even mix up the two types and have escorts to help you destroy another ship!
The tutorial faked a multi-stage mission by having you pick up new missions to continue the explanations. It doesn't actually have to be that way: you can have any number of stages in your mission. You could even have a mission that loops infinitely. This is done via the setStage action and complementary onStage condition. The first sets the stage to a certain number, and the second checks to see what stage the player is on. Here's the setup:
child preparation.add(stageTestSetStage1 <action> { field setStage = 1; field changeTitle="Multi-Delivery [Alpha Centauri]"; });
Note that the first setStage call happens in the preparation action when the player first gets the mission. This is because the onStage condition only works with non-zero values, and the default for setStage is 0; If you're having a multi-stage mission, you have to set the stage to something else at the very beginning. You do not, however, have to constantly use setStage; a setStage value of 0 has no effect on the current stage.
Once you've set an initial stage, you can then change it under whatever conditions you want. In this example, we're delivering items to Alpha Centauri and then different items back to Earth (you may have noticed the usage of 'changeTitle' to change the mission's title in order to indicate what stage the mission is currently on). So the code to change the current stage would happen when the player arrived in Alpha Centauri:
child conditions.add(stageTestDelivery1 <condition> { field onStage = 1; child playerAt.add Rock; child action.add(finishStageTest1 <action> { field money = 500; field message = " They're efficient on this planet, you'll have "+ "to give them that. They load up the potassium just as quickly "+ "as they unload the oranges."; field changeTitle="Multi-Delivery [Earth]"; field changeLongdesc = "All that remains is to bring the potassium "+ "back to Earth"; field setStage = 2; }); });
Note that this condition only fires if we're on stage 1, and when it fires it moves the current stage for this mission to 2, so the player can't land back on the planet and get the message again.
Finally, the return trip to Earth ends thusly:
child conditions.add(stageTestDelivery2 <condition> { field onStage = 2; child playerAt.add Earth; child action.add(finishStageTest2 <action> { field money = 500; field message = " The friendly dockworkers unload the potassium and "+ "pay you the other half of your comission."; field endMission = 1; }); });
Being able to create specific missions is nice, but if you had to fill up an entire universe with them, you'd probably go insane. Random missions allow you to create a generic mission and have the computer fill in the details. Currently, you can specify a random destination for a mission as well as random cargo; it's important to note that they are processed in that order.
To signal the computer that this is a mission with a random destination, you need to add sectors to the randomDest child of the mission. When the mission is presented to the player a destination will be chosen at random from the list of sectors specified. You can further modify this list by specifying the randomJumpsMin field, which will exclude those sectors that are too close to the player's current location. Here's an example:
field randomJumpsMin = 1; child randomDest.add Earth; child randomDest.add Rock; child randomDest.add Colonies;
Thus, the destination chosen will be one of the three given, and it must be at least one jump away.
Since the computer doesn't know what you want done when the player arrives at the destination, there is still work for you to do. When generating the random destination, the computer takes the last condition in the list of conditions, and modifies the playerAt list to point to the randomly chosen destination. Whatever you want to take place when the player reaches this destination should be in the 'action' child of that condition. It sounds confusing, but it's actually relatively straightforward:
child conditions.add(randomCargoTestEnd <condition> { child playerAt.add Nowhere; child action.add(finishRandomCargoTest <action> { field money = 1000; field message = " The cargo is unloaded from your ship rapidly."; field endMission = 1; }); });
Since the condition I've shown above was the last condition, the computer will add on to the playerAt list (which currently consists of Nowhere, a dummy sector I created that the player can never get to) with whatever destination was chosen. When the player gets there, they will be rewarded as you've specified.
Random Cargo missions are similarly set up. In order to indicate that this mission involves random cargo, the randomCargoMin field must be greater than zero, and you must have at least one entry in the randomCargo field:
field randomCargoMin = 5; field randomCargoMax = 25; child randomCargo.add Apples; child randomCargo.add Oranges; child randomCargo.add Banannas;
Here, the computer will choose between 5 and 25 Apples, Oranges, or Banannas to be the cargo. It will add a check to ensure you have enough cargo space to the prereqs child on its own. It will also add an action that gives you the cargo to the preparaion child. Finally, it adds on to the actions child of the last condition: it assumes that the last condition listed is a terminal case for the mission, and adds an action that removes the generated cargo. The only thing you need to do is to provide it with cargo to choose from and a range for the amount, and have a final condition for it to add on to.
Of course, your mission descriptions are going to be a little vague if you don't know what cargo the player's going to have. The solution to this is to use certain predefined tokens in your messages. The missions( reference) documentation has the complete list. The tokens will be substituted for the actual amount/cargo/etc once the random variables themselves have been decided. That way you can provide specifics even if you don't know them ahead of time.
The following is an example from another scenario I've written; it uses both random cargo and random destinations (the two were specifically written to complement each other) and serves as an example for both, as well as for substitutions:
randomCargoTest <mission> { field title = "Deliver ^AMOUNT ^CARGONAME to ^DESTINATION"; field longdesc = "And what's even better, we'll pay you to do it!"; field randomCargoMin = 5; field randomCargoMax = 25; field randomJumpsMin = 1; child randomCargo.add Apples; child randomCargo.add Oranges; child randomCargo.add Banannas; child randomDest.add Earth; child randomDest.add Rock; child randomDest.add Colonies; child conditions.add(randomCargoTestEnd <condition> { child playerAt.add Nowhere; child action.add(finishRandomCargoTest <action> { field money = 1000; field message = " The ^CARGONAME is unloaded from your ship rapidly."; field endMission = 1; }); }); }
As you can see, making random missions is easy. You could put four instances of this mission alone on a planet and you'd have enough missions to keep the player busy without making additional work for yourself. Random missions are an excellent way to flesh out your universe.