This guide will go over the things I found remaking some FSX missions. I will just list the things I found while using the SDK, which I think is useful with the lack of documentation right now.
Some parts are hidden to improve readability.
Just click the triangles to expand the text.
You got it!
Feel free to suggest changes and additions. This guide can definitely be expanded.
A mission is made up of different parts. The flight file, flight plan, and weather file determine the state of the world, planes and ATC at the spawn. The mission script determines things that happen after spawn such as dialog and changes in the world. The documentation for the mission script is very incomplete and will be the focus of this guide.
To start with mission creation it is a good idea to read this introduction for FSX mission development from FSDeveloper:
And FSX Mission Building Tips by Paul Lange:
To start, here is the file structure I use for my missions. For package name you can use:
Flight, weather, and flightplanWhen you have a general idea of your mission you can start with defining the beginning of the mission (doesn't have to be perfect, but it is necessary for testing the mission). The creation of these files is already in the documentation, so I will brief and refer to the documentation:
You can create a flight plan for your mission. I would create these in the simulator (world map) or with little navmap. Save the .PLN file. The documentation here is pretty complete: Documentation.
You can use the weather presets or configure a custom weather file (.WPR). The documentation is pretty clear: Documentation
Unfortunately the weather is static and covers the entire globe in the same weather.
The documentation here is also pretty complete: Documentation
Your flight file (.FLT) determines the state of the aircraft (location, switches), world (weather, time, assistance), ui (panels), and the sim in general (speed, traffic, multiplayer) at spawn.
It also determines the type of mission (Tutorial, Landing Challenge, Bushtrip, Freeflight) and the briefing screen:
And loading screen:
To create your flight file, you start with loading your flightplan or the starting location in the world map. Choose a plane, livery, etc. Choose a time and weather. Then start your flight. Move your plane to the position you want and change it to the configuration you want (switches etc.). If you want to spawn in the air you should stabilize the planes pitch and altitude so the plane is stable after spawn. You should use trim and throttle or autopilot for this. Keep in mind that changing the weather may change the conditions, so configure the weather first.
If you have the correct configuration, save the flight file with Escape>Save flight>save .FLT .
You now need to configure the .FLT:
[Main] Add title (e.g. Airline emergency) Add description/location (e.g. LIRN, Italy or TT:Telluride.Description) Change MissionType (BushTrip, LandingChallenge) Delete: MissionLocation, OriginalFlight, FlightType, StartingCameraCategory [ResourcePath] and [ObjectFile] Change to your filename for the files (e.g. yourname-mission-missionname) Fix flightplan in [ATC_Aircraft.0], [ATC_ActiveFlightPlan.0], and [GPS_Engine]
[Briefing] BriefingText=TT:FSXCaribbeanLanding.Briefing BriefingImage0=./images/mrliamt-mission-fsx-caribbean-landing_briefing.png [Multiplayer] Status=0 [Airtraffic] Status=0 [TrafficOptions] AllowAbientVehicleTraffic=FALSE [Assistance] Preset=ASSISTANCE_PRESET_TRUE_TO_LIFE
NOTE: You can use ChangeAssistanceItemAction to change specific items.
The mission script defines things that happen after spawn. This is where the documentation is still lacking. I found most of this by trial and error and by using spb2xml for msfs. This tool de-compiles .spb files created from .xml files such as mission scripts. This allowed me to look at the way the scripts were used in the official missions and in freeflight.
The basic parts of a mission script are triggers and actions. When a trigger ‘fires’, it can start different actions and activate other triggers. A bunch of these together makes up a basic mission.
In addition, the scipt contains a mission definition with objectives and scoring. MSFS also introduced some new mission building blocks: (these will be discussed further in their own chapter)
You can use calculators for more advanced logic in your mission. It can take in multiple variables and trigger different actions based on a logic. You can also use this to calculate a score and probably many more applications which you can explore.
Flowstates are the different parts of a mission or freeflight such as intro, approach, and parking. FlowstateEvents are special actions which control ‘meta’ or ‘sim-level’ actions such as enabling the VFR map, pausing the simulation, and changing the camera.
Events are used to notify the user with popups such as flying tips. The event only has to be defined once, and then it can be triggered by the mission script.
The mission script can be viewed and edited through the Script Editor or by manually editing the .xml file. All parts of the mission script (or nodes in the script editor) have a GUID that has to be uniquely generated. All nodes can have an id and description. I recommend to give every node an short, unique id that tells you what it is and does. Nodes can also be activated and deactivated. If they are activated it means they are active from spawn. Nodes can be activated and deactivated throughout the mission with an ObjectActivationAction. This can be used to limit a trigger to only be active after something else has happened first.
Triggers & Actions
The main parts of mission scripts are triggers and actions. I will list all triggers and actions I tried out. I recommend to read through these to get an idea of what can be done with the mission system. MSFS introduced some new mission components such as calculators, events, and flowstates.
Triggers fire when a condition is met. When a trigger fires, the actions referenced in the ObjectReferenceList are played.
Triggers have a few general parameters:
If a trigger is activated it will wait for its condition is met and it can fire. You may not want the trigger to be active at the start of the mission. If you want the trigger to be disabled at the start you should uncheck this property. You can change it throughout the mission with an ObjectActivationAction.
You can change a trigger to be able to fire again and again by unchecking the OneShot property. If this property is set to true, a trigger will only fire once.
When a trigger is latched it means it has fired and will never fire again. This happens when a OneShot trigger fires. When that happens, the Latched property is automatically set to True. You shouldn’t change this property in the script editor.
You can use a Property trigger to check to see if another trigger is “latched.” This is useful in cases where you want to give the user an award after they’ve completed one or multiple parts of a mission.
A timer trigger is a very useful trigger that is often used to start the first actions in the mission.
The time the timer is at, will change when the TimerTrigger is active.
Time that the Timer starts at when a ResetTimerAction is executed.
When the timer reaches the StopTime, the trigger fires.
I have seen this enabled, but I can’t see any effect.
Changes the CurrentTime by the amount specified in DeltaTime (positive or negative).
This trigger detects landings.
You can use either an AirportLandingTrigger or an AreaLandingTrigger.
The LandingType has three types; a ‘touchdown’ happens when the plane is on the ground (While landing, not just a little bounce or one wheel.), a ‘full stop’ happens when the plane slows down to ~25 kts, and ‘any’ means any type of landing.
The landings can be filtered by airport (using ICAO) and runway.
This trigger can have an Area attached. If no area is attached it will work anywhere (also at airports).
The countertrigger waits for the count to reach a specific number.
The StopCount determines the count at which the trigger fires. The count can be increased or decreased with a CountAction.
Fill in the desired change in Count. Add Triggers as a child and connect it with the CounterTrigger.
This trigger lets the user choose from a list of options.
It can be used like the FSX mission ‘Limited Options’:
I haven’t got this to work in MSFS yet.
A propertytrigger is a very useful trigger. It can be triggered by any combination of simvars such as plane altitude and speed.
A property trigger fires when a condition is true. A condition is a formula with Simulation Variables (simvars) such as speed or altitude. For example, if the altitude is greater than 10,000 feet, the condition is true and the trigger will fire.
For a more advanced version, with different actions based on the simvars, use a Calculator.
Reverse Polish Notation
The simvars are used in an equation called a reverse polish condition. This equation uses reverse polish notation where the operators come after the operands. It is explained with examples in the documentation.
If the speed is less than or equal to 135kts, and the plane is on the ground, the condition will become:
So the condition will be true and the trigger fires.
This specifies a duration in which the condition has to be true, before it fires.
This determines if the timer resets when the condition is false. If it set to false, the trigger will fire when the condition has been true for a total amount of time equal to the timer. Else, the trigger will only fire if the condition has been true for an uninterrupted period equal to the timer.
The child ‘Condition’ was used in FSX, but I think it isn’t functional.
A proximity trigger fires when objects enter or exit it. It uses RectangleAreas and CylinderAreas.
You can use one or more RectangleArea or CylinderArea.
Enter, Inside, and Exit
The trigger can fire when an object enters or exits the area. I haven’t tried WhileInside.
You can filter the objects that can fire the trigger with ObjectFilter or for each phase with; OnEnterFilter, WhileInsideFilter, and OnExitFilter.
Each phase also has a condition, that –if used– has to be true for the trigger to fire.
All actions are fired in the order they’re listed in the ObjectReferenceList of the trigger that fired. This is important, because Dialog actions take time to play and will delay any actions that follow them. If a delay is set on a Dialog action, then the next action in the queue will be delayed by that amount.
You can arrange the order in which actions in a given queue fire by changing the order manually in the .xml.
Actions have a few general parameters:
True: This action will start immediately
False: This action will wait for other actions to complete. The order is determined by the order the actions are fired, which is determined by the order the actions are listed in the trigger. This can be changed by manually editing the .xml.
Very useful action to (de)activate objects such as triggers and InGameMarkers.
You can use this for example to activate a trigger when landing clearance is give or to activate a TimerTrigger.
True: Change trigger to be activated
False: Change trigger to be non-activated
This plays dialog for the copilot and atc. It can use sound files or text-to-speech (TTS). The dialogAction can also show subtitles.
The text for the TTS and subtitles. Can be localized.
The file name of the sound to be played. Put your files in the sound folder.
Time to wait before the next action. Useful for pacing your dialog.
Can be; NARRATOR, INSTRUCTOR, COPILOT. But they all sound the same.
The dialog can also trigger an action when it ends. This delay waits before actually firing.
You can change the payload during the flight.
While selecting the weight of the plane in the world map, you can see the different ‘stations’ such as; Co-Pilot, Passenger 1, Baggage 1. Remember the order of the stations. In the AdjustPayloadAction, at StationIndex, fill in the number of the station you want to change starting at 0. So Pilot will be 0 and Co-Pilot will be 1.
Set: Set as the new weight.
Add: Change from the old weight.
Weight in pounds
Set to pounds.
You can change specific assistance items throughout the mission.
Select the item you want to change.
Lock or unlock this assistance item for the player.
None: don’t change value
Off: Turn item off
Reminder: Unknown function
On: Turn item on
Auto: Unknown function
Manual: Unknown function
Use Simconnect for a custom action.
Fades a color over the whole viewport.
Can be used for teleports or as an easy way to know if a trigger is working.
RGB values from 0-255.
True: Color fades in
False: Color fades out
Duration in seconds
Obsolete. Old FSX action.
This action chooses a random action from a list and can have a propability that an action executes.
This is the percentage chance that one of the actions in the Actions list will occur. If you set the probability to 50, there is a 50% chance that none of the actions in the list will occur. The other 50% of the time, one of the actions will occur. The action that is chosen from the list is chosen at random. All are equally likely to be chosen.
When you have only one action in a Random action’s list and set it for 100%, then that action will always fire. If you have two actions in the queue and set it for 100%, then one of the two will always fire.
Flowstates & Events
Flowstates and events are new in MSFS. There isn’t much to find about them, so it isn’t complete. I think this is the area that is most in need of documentation right now.
Flowstates are the state of flight or mission. The flowstates can have attached Actions and FlowEvents at the start and end of the state. You can set the flowstates to be visible in the timeline, but I haven’t found a way to actually view the timeline.
The FlowStates I have found:
FlowEvents are special actions which control ‘meta’ or ‘sim-level’ actions such as enabling the VFR map, pausing the simulation, and changing the camera.
FlowEvents can be triggered like a regular action with a FlowEventAction or as a part of a flow state in a FlowStateAction.
The FlowEvents I have found:
You can do different things with the panels like:
You have to fill in the panelname. Standard panels are:
NOTE: You can find panel names for 3rd party addons in the files. In the addon folder look for an .html file. Open it and search for
Mission Intro & Outro
I have only used flowstates to get an intro and outro with camera movements, and a button to start the mission:
To get a mission intro, just use these nodes in your .xml:
This code will produce some nodes, one of which is an ObjectActivationAction that will fire when the mission is started. You will have to connect it to the TimerAction(s) that you used to start the mission. Un-activate the TimerAction(s) and connect the ObjectActivationAction. This way the timers will start when the mission starts.
To get a mission outro, just copy this node in your .xml:
This code will produce a FlowStateAction node that you will have to trigger when you want to start the outro camera move.
Events show a notification to the player. I haven’t tried it yet.
Edition are aides for developers such as the visual script editor and comments.
If you save a script from the script editor, you will notice an additional file with _edition appended to it. That file contains the positions of the nodes in the script editor. In the script editor you can also add comments to clear up the workings of your script. Comments can be resized to contain nodes. The comment can be used to move all containing nodes, they can also have a title, text, and color.
'Areas' includes two types of volumes and an in-game marker.
There are two types of normal areas (actually 3d volumes); rectangle areas and cylinder areas. Areas have dimensions and a position and rotation. The dimensions are in meters. These areas can be used for example for the ProximityTrigger.
An InGameMarker is the big needle that mark things like points of interest:
The marker has two parts; a 3d ‘pin’, and a 2d pointer. The 3d pin floats above the position and can have a vertical line and an icon. The 2d pointer points to the pin when it isn’t in the field of view of the player.
The 3d pin has three textboxes as shown in the picture. The 2d pointer has one textbox. The text can be set to text (your own text, can be localized), distance (nm), or altitude (ft amsl). You can disable the icon for the 2d and 3d marker. The vertical line of the 3d marker can also be disabled.
NOTE: When saving the script from the script editor, the markers become invisible due to a bug. To fix this, manually edit the .xml and add
<Visible>True</Visible> to the InGameMarkerTemplate2D and InGameMarkerTemplate3D:
Position & rotation
The position and rotation of objects can be defined four ways:
The AttachedWorldPosition is static and has coordinates, an altitude, and can have a rotation. The altitude can be above the mean sea level (AMSL) or above the ground (AGL). You can also move the position with the Gizmo (Script editor>View>Gizmo)
NOTE: When you use the gizmo to move something, the altitude can glitch if you have AltitudeIsAGL enabled.
A position can be attached to a (moving) object like the players plane.
Moving with the Gizmo
First, build your project and move the package to the community folder. Close the project and start the mission. If you can’t see it, restart the sim. When it is loaded, open the project and the script editor. Go to developer camera and double click on the object you want to move. It will be centered and you can move it with the the *Gizmo (Script editor>View>Gizmo).
There are different types of missions, but all of them have Objectives/Goals that will have to be fulfilled to end the mission.
There are different kinds of missions:
Goals / Objectives
You can add Objectives to your mission. Link each objective to a Goal or SubGoal. For a SubGoal add a step to a Goal. The description of the Objective will be the name for the player.
Resolve, fail, or abort the action.
Trigger different actions for different conditions. Useful for checklists, copilot feedback and scoring.
This very useful node can only be added manually. You can create variables and use reverse polish conditions to calculate a score or trigger different actions. You can create variable that measure for instance touchdown speed and use it to give a score or trigger different dialog actions based on how good the landing was.
Useful if you want to get rid of stationary or moving traffic from a road, airport, or water).
You can reference one or multiple areas in which the exclusion is enforced. Then, select types of traffic to exclude:
ExcludeAircraft: Exclude active (not parked) aircraft.
ExcludeAirportVehicles: Exclude airport vehicles and parked planes.
Point of interest
In FSX this was used for the in-game markers (the big green arrows). I think you are better off using the InGameMarker.
Obsolete. This was used in FSX, but now defined in the flight file and with the ChangeAssistanceItemAction.
The CAircraftContainer allows you to add (AI) planes.
Add a ContainerID (just some random numbers). Then, in your .FLT, add a plane with the containerID:
You can define it further like normal, but instead of
something.0 it will be
something.yourContainerID. To spawn it, you need to fill in coordinates and add a SpawnAction connected to a trigger and the container. If you build and load the mission, you can move the plane with the gizmo.
I haven’t examined the AI options yet, but it seems like it could use its own guide.
You can spawn a scenery object in your mission.
This object will disappear when the mission is over. Create a ModelLib asset group (Project Editor>Click on package>Add asset group) and add an object just like you would a regular scenery project. Then add a LibraryObject to your script. Save the script and exit the script editor. Open the script .xml and add the GUID of your object to the script like this:
Then you can move the object with the gizmo or with an animation. You can also attach an effect.
User-facing strings can be localized. This means they can easily be changed and translated.
For this you have to create a new file next to the .FLT. This file has the same name as the other files, and the extension .loc . This file uses a JSON structure (you can use this tool to check if the structure is correct):
The first part has a GUID that you have to generate randomly and a list of the languages. The next part has all the strings. First is the name of the string, then another random GUID, a short description, last changes, and finally the strings for the different languages. You can reference the strings by typing TT:nameofthestring instead of the text:
You can use it in the .FLT and the mission script.
A drawback is that untranslated languages will not default to english, but just show the name of the string.
FSX to MSFS
You can open FSX mission scripts in MSFS.
You can find the .xml files in Mission Samples in the FSX SDK. Or you can use the old spb2xml to convert the .spb in the mission folder.
Just make a mission project in msfs like normal. Copy the sounds folder if you want. Open the script editor. File>Open, open the fsx .xml. If it doesn’t load, look in the console for a xml error.
This will point to a specific part that isn’t recognized. This means that part is not supported, so you have to delete it manually from the .xml . Keep in mind that you may have to replace this with a modern alternative later. When the script loads without error, you will see that all nodes are centered (because FSX had a different script editor):
You will have to move the nodes to create a clear structure for yourself. I prefer to first seperate all unconnected parts:
Remember to save frequently and make regular backups.
And then I sort them in roughly chronological order (you can use the numbers of the dialog and a video or your memory of the mission):
Then I add comments to make the mission easier to understand:
Now that we have a better idea of the mission, we can change some of the things that don't port over accurately.
Update Area rotation
In FSX, the rotation of areas was defined in the Area node itself, but now it has moved to the AttachedWorldPosition. So we need to move the rotation data. For every area and axis:
- Copy the rotation for the axis (e.g. Head).
- Change it to 0 in the Area node.
- Go to AttachedWorldPosition and paste the rotation.
You may also have to change the position of areas at the airport, because the data may have changed.
PropertyTriggers used to have a child with the condition of the trigger. This has changed to a ReversePolishCondition in MSFS. Just click on the child condition. You will see the type like LessThan or Equal. If you click on it you will see LHS (left hand side) and RHS (right hand side). Remember the values. In the ReversePolishCondition, first fill in the LHS, then the RHS, and then the type.
You have to use C# operators like
Instead of, for example
Simvar.AltitudeAGL you will have to use the new notation:
(A:PLANE ALT ABOVE GROUND, feet).
Then remember remove the old child condition. Overall it will look like this:
All old LibraryObjects won’t work. You can replace them with other sceneryobjects or simobjects.
AI planes will need to be updated with a MSFS airplane in the .xml and .flt . The AI may also need to be remade.
You can see an example by downloading the project files of my Telluride landing port.