Obviously one of the core components of the Making History Expansion is the Missions themselves. Here you can read some information and get some insight (I hope) about building missions and how the MissionSystem manages these behind the scenes.
This blog did end up a bit long, but it hopefully is all interesting
What makes a Mission?
In a nutshell (love that term) a mission is a series of nodes and connections where the player starts at the origin and can follow the paths from node to node until they hit an ending. For the programmatically inclined this is, in essence, a Finite State Machine (or FSM).
...warning dev type words ahead…
In the mission system we do something a little different to a traditional FSM in that we don’t store every transition in the persistence. We added some logic to the nodes so that a node can be flagged as a “catch all” - which means that the mission can transition to this node from any other node. This means we can store more information in a mission file without needing to store every transition individually, and yet still unpack it to be used like an FSM in the game itself.
So in FSM parlance the Nodes are a state and Connectors are the transitions. The game then has a parsing engine that keeps track of each mission and handles the update loops that are used to progress each mission between nodes. And the Active Node is the active state.
It’s at the core of how a mission is played once its put together, and below well get into some of these details.
What is the MissionSystem?
The MissionSystem is that parsing engine I mentioned just before, It is the main class that manages missions and technically it’s what’s called a Scenario module in KSP. It loads the mission components from a save and then handles processing them and tracking where the mission is up to, when it should change nodes and when to trigger actions. Other Scenario modules in KSP include the ContractSystem, the FundingSystem, CommNetScenario, hopefully your seeing a pattern here - all things that run as components of a game and are used to load and save persistent data - then handle it during game play.
Travelling between Nodes
So let’s keep that terminology (of an FSM) in mind as we progress a bit further. At any point in our mission there is always a single Active Node (like states in an FSM) - it’s like highlander in that “there can be only one”.
The MissionSystem then needs to check whether it is time to move to a new node from this one. To do this the mission system sequentially checks the nodes that the ActiveNode is connected to - this includes the nodes directly connected and any catch all nodes.
How does the mission system know when it’s time to change nodes? Each node can have a number of modules attached to it and these help it to understand when that transition should happen as well as anything to do after the active node changes:
The checks for when to change node are handled by the TestModule:
A TestModule is a class that defines logic that is tested and returns True when the test passes.
- Each Node can have one or more TestGroups, and each TestGroup contains TestModules.
- Once all the TestModules in any TestGroup return True that node will activate and the missions Active Node changes.
- If a Node has no TestGroups/Modules it will be true immediately
The actions that occur when a node activates are handled by the ActionModule:
- Each node can have one or more ActionModules attached.
- These “Fire” when the node activates - but this doesn’t mean you can’t use programming structure like co-routines to have these fire immediately and perform long running actions.
Now that we’ve seen the Nodes and Connectors we need the third leg of our milking stool - the Active Node. The MissionSystem looks at the active node in each update loop and checks all of the nodes that it can move to. This means any node that has a connection from the active node and any catch all nodes.
Other Bits and Pieces
But what about these other things I see in the Builder? what is a docked node? how do I see whats a catch all node? Well as they say a picture is worth a thousand words (although with localization that number is probably rounded) so here’s some points of things I’ve found helpful and interesting:
The Start Node:
Hopefully the name gives it away, but in any case this is the Active Node when a mission first starts. The mission system always starts here and then tests the connected nodes.
Spawnable nodes can be docked to the Start Node (only these types of nodes and no others). The first spawn vessel node docked to the start node is the starting vessel for the mission
This is a special kind of connection in that the docked node will be tested once only when the parent node (the one it is docked to) is activated. It’s a great construct to help you do things like give various scoring adjustments when a node is activated, or change the path of a mission at a specific point in time.
So let me give you an example of that one:
Assuming that the Go to node shown as 1 is connected to the active node, then when “My Other Vessel” reaches that location:
- The GoTo Node will become the active node.
- The system will then check if the MET is less than 2h, if it is that node becomes active and no other docked nodes are tested
- If not then the MET < 3h30m is tested, if thats true then that node becomes active and so one
- If any of the docked nodes is true then the connected action nodes will fire immediately adjusting the score
- then the player needs to get to 5000m above sea level to proceed further.
Catch All Nodes:
These are nodes that have no specific connection to their input pin. They will be tested regardless of which node is the Active Node.
From our original annotated image you can see the catch all node there - a Vessel destroyed - which means that if at any time in the mission “Trigger’s Vessel” is destroyed then that node will activate.
Connection Test Orders:
How do you know what order the MissionSystem will check which node is next? For docked nodes it should (hopefully) be visually obvious - its the order they are docked, but when there are multiple connections the order can be found (and adjusted) in the node Options in the Settings Action Pane (the SAP - in the top right of the Builder)
We’ll combine this idea with the next ones...
Some other Node things:
Activate Once Only - This setting is on by default, to help prevent infinite loops, but with careful work you can disable this to use some rudimentary loops in missions.
Always True Nodes - These nodes can be used for logic structures to make things move along
Always False Nodes - You can use these to mislead your players - yeah I said it - to change what they think the goal may be.
This one needs explanation I know - I’ve color coded the paths to help. Let’s say you want to direct a player to EVA from one vessel and then get into the Mk1Pod in a nearby vessel. But, you want to add some pressure by blowing solar panels off the vessel until they get there (dont ask me why, maybe your that kind of kerbal). Heres how this solution for that works:
- Your player gets to Node A by EVAing a kerbal
- The mission moves immediately to Node B (cause its always true) and we have also set it to be able to activate multiple times so we can loop back to it.
From B it tests the nodes according to the order configured in Node B via its Node Connections Order (as below)
- So it tests if the Crew boarded the target part, then tests if its been 120 secs since we EVA’d, and so on..
- Let’s assume we reach the 31 second mark.. The mission then moves to node C (via the blue line) and then explodes one of the solar panels off the vessel
- It then activates Node B again and starts testing again.
So every thirty seconds we blow a panel off the vessel until either a) they reach and board the Mk1 pod, or b) they take too long and we find something else nasty to do.
I know this one has been a bit long, but hopefully I’ve given you some insight and information into some of the workings and possibilities with the Making History Expansion and Missions. Catch you next time.
Edited by TriggerAu