CREATING A CHECKLIST

Rather than try and take you through the creation of a checklist from start to finish, we are going to present to you a number of examples that go from the very simple to the extremely complicated, and in each example explain what we are doing and why. This is because checklists are very much a unique element in every aircraft package and to try to give a single example would miss out on the nuances and complexities that can be associated with them.

 

Note that each of the examples will highlight specific parts of the XML that should be used and link to the specific description on the main documentation page for checklists, which you can find here:

 

Also note that all files should be contained within the "SimBase" element, with the Type attribute specifying which type of file it is:

  • For checklist files:
    <?xml version="1.0" encoding="Windows-1252"?>
    <SimBase.Document Type="Checklist" version="1,0">
        // CONTENTS
    </SimBase.Document>
  • For checkpoint libarary files:
    <?xml version="1.0" encoding="Windows-1252"?>
    <SimBase.Document Type="CheckpointLibrary" version="1,0">
        // CONTENTS
    </SimBase.Document>

 

 

Checkpoint Checklist Examples

The example below shows a minimal checkpoint that will only display a subject and expectation and will be automatically skipped in all modes except Manual:

<?xml version="1.0" encoding="Windows-1252"?>
<SimBase.Document Type="Checklist" version="1,0">
    <Checkpoint>
        <CheckpointDesc SubjectTT="TT:GAME.CHECKLIST_PARKING_BRAKE" ExpectationTT="TT:GAME.CHECKLIST_SET"/>
    </Checkpoint>
</SimBase.Document>

 

Next, we show a similar checkpoint that will enable highlighting of an instrument as a visual assistance. It will still be skipped in all modes except Manual, like the previous example:

<?xml version="1.0" encoding="Windows-1252"?>
<SimBase.Document Type="Checklist" version="1,0">
    <Checkpoint>
        <CheckpointDesc SubjectTT="TT:GAME.CHECKLIST_PARKING_BRAKE" ExpectationTT="TT:GAME.CHECKLIST_SET"/>
        <Test>
            <Instrument id="PARKING_BRAKE"/>
        </Test>
    </Checkpoint>
</SimBase.Document>

 

Now we show a similar checkpoint with a test to automatically validate it in Automatic mode as soon as the user meets the requirement. In this case the SimVar "BRAKE PARKING POSITION" must be TRUE (1) for the requirements to be fulfilled. In Copilot mode this checkpoint will be skipped, because no Copilot action is defined:

<?xml version="1.0" encoding="Windows-1252"?>
<SimBase.Document Type="Checklist" version="1,0">
    <Checkpoint>
        <!-- You can also add XML comments anywhere you want -->
        <CheckpointDesc SubjectTT="TT:GAME.CHECKLIST_PARKING_BRAKE" ExpectationTT="TT:GAME.CHECKLIST_SET"/>
        <Test>
            <TestValue>
                <Val SimVarName="BRAKE PARKING POSITION" Units="Boolean"/>
            </TestValue>
            <Instrument id="PARKING_BRAKE"/>
        </Test>
    </Checkpoint>
</SimBase.Document>

 

The final checkpoint example is of a similar checkpoint with a Copilot-only action. This Action will be automatically executed in Copilot mode - and only in this mode - if the testValue is FALSE (0), i.e: if the parking brake is not set. This action will only be performed once. The action sends the event of EventID "PARKING_BRAKES", which will activate the parking brake of the aircraft. This checkpoint will still wait until the testValue is TRUE (1) before being automatically validated, i.e: setting an unrelated action will cause the Copilot mode to wait until the user resolves the issue by themselves.

<?xml version="1.0" encoding="Windows-1252"?>
<SimBase.Document Type="Checklist" version="1,0">
    <Checkpoint>
        <CheckpointDesc SubjectTT="TT:GAME.CHECKLIST_PARKING_BRAKE" ExpectationTT="TT:GAME.CHECKLIST_SET"/>
        <Test>
            <TestValue>
                <Val SimVarName="BRAKE PARKING POSITION" Units="Boolean"/>
            </TestValue>
            <Action Copilot="True" Condition="TestValueFalse" Once="true" EventID="PARKING_BRAKES"/>
            <Instrument id="PARKING_BRAKE"/>
        </Test>
    </Checkpoint>
</SimBase.Document>

 

 

Checkpoint Library Examples

A checkpoint library is a file that contain one or more checkpoints that can be shared across various aircrafts. Below is a minimal example of a library containing a single checkpoint:

<?xml version="1.0" encoding="Windows-1252"?>
<SimBase.Document Type="CheckpointLibrary" version="1,0">
    <Checklist.CheckpointLibrary>
        <Checkpoint Id="Parking_Brake_Set">
            <CheckpointDesc SubjectTT="TT:GAME.CHECKLIST_PARKING_BRAKE" ExpectationTT="TT:GAME.CHECKLIST_SET"/>
        </Checkpoint>
    </Checklist.CheckpointLibrary>
</SimBase.Document>

 

Our next example is a bit more advanced and shows a library with two checkpoints:

<?xml version="1.0" encoding="Windows-1252"?>
      <SimBase.Document Type="CheckpointLibrary" version="1,0">
          <Checklist.CheckpointLibrary>
          <!-- You can also add XML comments anywhere you want -->
              <Checkpoint Id="Parking_Brake_Set">
                  <CheckpointDesc SubjectTT="TT:GAME.CHECKLIST_PARKING_BRAKE" ExpectationTT="TT:GAME.CHECKLIST_SET"/>
                  <Test>
                      <TestValue>
                          <Val SimVarName="BRAKE PARKING POSITION" Units="Boolean"/>
                      </TestValue>
                      <Action Copilot="True" Condition="TestValueFalse" Once="true" EventID="PARKING_BRAKES"/>
                      <Instrument id="PARKING_BRAKE"/>
                  </Test>
              </Checkpoint>
              <Checkpoint Id="Brakes_Released">
                  <CheckpointDesc SubjectTT="TT:GAME.CHECKLIST_BRAKES" ExpectationTT="TT:GAME.CHECKLIST_RELEASED"/>
                  <Test>
                      <TestValue>
                          <Operator OpType="NOT">
                              <Val SimVarName="BRAKE PARKING POSITION" Units="Boolean"/>
                          </Operator>
                      </TestValue>
                      <Action Copilot="True" Condition="TestValueFalse" Once="true" EventID="PARKING_BRAKES"/>
                      <Instrument id="PARKING_BRAKE"/>
                  </Test>
              </Checkpoint>
          </Checklist.CheckpointLibrary>
      </SimBase.Document>

 

This library file can then be accessed in the checklist file using the <IncludeCheckpointLibrary /> element, and the checkpoint ID (defined using the <Checkpoint> element in the library file) is used to select the required checkpoints - Parking_Brake_Set and Brakes_Released - from it:

<?xml version="1.0" encoding="Windows-1252"?>
<SimBase.Document Type="Checklist" version="1,0">
    <Checklist.Checklist>
        <IncludeCheckpointLibrary FileName="MY_AIRCRAFTCheckpointLibrary.xml"/>
        <Step ChecklistStepId="PREFLIGHT_GATE">
            <Page SubjectTT="TT:GAME.CHECKLIST_PREFLIGHT_1_1">
                <Checkpoint ReferenceId="Parking_Brake_Set"/>
            </Page>
            <Page SubjectTT="TT:GAME.CHECKLIST_PREFLIGHT_1_2">
                <Checkpoint>
                    <CheckpointDesc SubjectTT="TT:GAME.CHECKLIST_NAVIGATION_LIGHTS" ExpectationTT="TT:GAME.CHECKLIST_ON"/>
                    <Test>
                        <TestValue>
                            <Val SimVarName="LIGHT NAV" Units="Boolean"/>
                        </TestValue>
                        <Action Copilot="True" Condition="TestValueFalse" Once="true" EventID="TOGGLE_NAV_LIGHTS"/>
                        <Instrument id="LIGHT_NAV_SWITCH"/>
                    </Test>
                </Checkpoint>
            </Page>
        </Step>
        <Step ChecklistStepId="PREFLIGHT_PUSHBACK">
            <Page SubjectTT = "TT:GAME.CHECKLIST_PUSHBACK">
                <Checkpoint ReferenceId="Brakes_Released"/>
            </Page>
        </Step>
    </Checklist.Checklist>
</SimBase.Document>

 

Default Checkpoint Library

It should also be noted that Microsoft Flight Simulator has a default library of checkpoints that can be included (and even adapted, as explained here) in your own aircraft. To include this file you would have something like the following:

<?xml version="1.0" encoding="Windows-1252"?>
<SimBase.Document Type="Checklist" version="1,0">
    <Checklist.Checklist>
        <IncludeCheckpointLibrary FileName="CheckpointsLibrary\\Asobo_DefaultCheckpointLibrary.xml"/>
        // CONTENTS
    </Checklist.Checklist>
</SimBase.Document>

 

 

Aircraft Checklist File

The example below is a small example of an aircraft checklist, but without using any library. This checklist contains a single step, which is composed of a single page containing two simple checkpoints:

<?xml version="1.0" encoding="Windows-1252"?>
<SimBase.Document Type="Checklist" version="1,0">
    <Checklist.Checklist>
        <Step ChecklistStepId="PREFLIGHT_GATE">
            <Page SubjectTT="TT:GAME.CHECKLIST_PREFLIGHT_1">
                <Checkpoint>
                    <CheckpointDesc SubjectTT="TT:GAME.CHECKLIST_PARKING_BRAKE" ExpectationTT="TT:GAME.CHECKLIST_SET"/>
                </Checkpoint>
                <Checkpoint>
                    <CheckpointDesc SubjectTT="TT:GAME.CHECKLIST_NAVIGATION_LIGHTS" ExpectationTT="TT:GAME.CHECKLIST_ON"/>
                </Checkpoint>
            </Page>
        </Step>
    </Checklist.Checklist>
</SimBase.Document>

 

Now for a bit more of an advanced file, where a library is loaded and the first and third checkpoints are defined in the library to be referenced here, while the second checkpoint is fully defined in this checklist file:

<?xml version="1.0" encoding="Windows-1252"?>
<SimBase.Document Type="Checklist" version="1,0">
    <Checklist.Checklist>
      
        <IncludeCheckpointLibrary FileName="aircrafts\\DefaultCheckpointLibrary.xml"/>
        <Step ChecklistStepId="PREFLIGHT_GATE">
            <Page SubjectTT="TT:GAME.CHECKLIST_PREFLIGHT_1_1">
                <Checkpoint ReferenceId="Parking_Brake_Set"/>
            </Page>
            <Page SubjectTT="TT:GAME.CHECKLIST_PREFLIGHT_1_2">
                <Checkpoint>
                    <CheckpointDesc SubjectTT="TT:GAME.CHECKLIST_NAVIGATION_LIGHTS" ExpectationTT="TT:GAME.CHECKLIST_ON"/>
                    <Test>
                        <TestValue>
                            <Val SimVarName="LIGHT NAV" Units="Boolean"/>
                        </TestValue>
                        <Action Copilot="True" Condition="TestValueFalse" Once="true" EventID="TOGGLE_NAV_LIGHTS"/>
                        <Instrument id="LIGHT_NAV_SWITCH"/>
                    </Test>
                </Checkpoint>
            </Page>
        </Step>
 
        <Step ChecklistStepId="PREFLIGHT_PUSHBACK">
            <Page SubjectTT = "TT:GAME.CHECKLIST_PUSHBACK">
                <Checkpoint ReferenceId="BRAKES_RELEASED"/>
            </Page>
        </Step>
 
    </Checklist.Checklist>
</SimBase.Document>

 

Advanced Checkpoint Examples

Below you can see an example of a checkpoint where 4 switches have to be set to the "ON" position, in any order:

<Checkpoint Id="Generator_Control_Switches_On">
    <CheckpointDesc SubjectTT="TT:GAME.CHECKLIST_GENERATOR_CONTROL_SWITCHES" ExpectationTT="TT:GAME.CHECKLIST_ON"/>
    <Sequence SeqType="Unordered">
        <Test>
            <TestValue>
                <Val SimVarName="GENERAL ENG GENERATOR SWITCH:1" Units="Boolean"/>
            </TestValue>
            <Action Copilot="True" Condition="TestValueFalse" Once="true" EventID="TOGGLE_ALTERNATOR1"/>
            <Instrument id="OVHD_PUSH_ELECTRICS_GEN_CONT_01"/>
        </Test>
        <Test>
            <TestValue>
                <Val SimVarName="GENERAL ENG GENERATOR SWITCH:2" Units="Boolean"/>
            </TestValue>
            <Action Copilot="True" Condition="TestValueFalse" Once="true" EventID="TOGGLE_ALTERNATOR2"/>
            <Instrument id="OVHD_PUSH_ELECTRICS_GEN_CONT_02"/>
        </Test>
        <Test>
            <TestValue>
                <Val SimVarName="GENERAL ENG GENERATOR SWITCH:3" Units="Boolean"/>
            </TestValue>
            <Action Copilot="True" Condition="TestValueFalse" Once="true" EventID="TOGGLE_ALTERNATOR3"/>
            <Instrument id="OVHD_PUSH_ELECTRICS_GEN_CONT_03"/>
        </Test>
        <Test>
            <TestValue>
                <Val SimVarName="GENERAL ENG GENERATOR SWITCH:4" Units="Boolean"/>
            </TestValue>
            <Action Copilot="True" Condition="TestValueFalse" Once="true" EventID="TOGGLE_ALTERNATOR4"/>
            <Instrument id="OVHD_PUSH_ELECTRICS_GEN_CONT_04"/>
        </Test>
    </Sequence>
</Checkpoint>

 

In this second example, a checkpoint tests if rudder controls are functioning properly using the Copilot mode and pacing out the checks over specific timed intervals:

<Checkpoint Id="Rudder_Test">
    <CheckpointDesc SubjectTT="TT:GAME.CHECKLIST_RUDDER" ExpectationTT="TT:GAME.CHECKLIST_TEST"/>
    <Sequence SeqType="Unordered">
        <Test>
            <Once>True</Once>
            <TestValue>
                <Operator OpType="LESS">
                    <Val SimVarName="RUDDER POSITION" Units="percent"/>
                    <Val Value="-66"/>
                </Operator>
            </TestValue>
            <Instrument id="RUDDER_PEDALS"/>
            <Action Copilot="True" Condition="TestValueFalse" Once="true" EventID="RUDDER_SET" EventParam="16383"/>
            <Action Copilot="True" Condition="TestValueTrue" Once="true" SpecialAction="WaitForDuration" Value="0.5"/>
        </Test>
        <Test>
            <Once>True</Once>
            <TestValue>
                <Operator OpType="GREATER">
                    <Val SimVarName="RUDDER POSITION" Units="percent"/>
                    <Val Value = "66"/>
                </Operator>
            </TestValue>
            <Instrument id="RUDDER_PEDALS"/>
            <Action Copilot="True" Condition="TestValueFalse" Once="true" EventID="RUDDER_SET" EventParam="-16383"/>
            <Action Copilot="True" Condition="TestValueTrue" Once="true" SpecialAction="WaitForDuration" Value="0.5"/>
        </Test>
    </Sequence>
    <Action Copilot="True" Condition="End" EventID="RUDDER_SET" EventParam="0"/>
</Checkpoint>

 

Finally, here is an even more complex example of two checkpoints that share variables, and these variables are also being used to ensure that only one of two sequences are being actually executed. A more thorough explanation of the example is given at the end:

<Checkpoint Id="Magneto_150_RPM_Max_Decrease">
    <CheckpointDesc SubjectTT="TT:GAME.CHECKLIST_MAGNETOS" ExpectationTT="TT:GAME.CHECKLIST_150RPM_MAX_DECREASE"/>
    <Action Condition="Init" StoreVar="Magneto_RPM_BOTH" Value="0"/>
    <Action Condition="Init" StoreVar="Magneto_RPM_LEFT" Value="0"/>
    <Action Condition="Init" StoreVar="Magneto_RPM_RIGHT" Value="0"/>
    <Sequence SeqType="Ordered">
        <Test>
            <TestValue>
                <Operator OpType="And">
                    <Val SimVarName="RECIP ENG LEFT MAGNETO:1" Units="Boolean"/>
                    <Val SimVarName="RECIP ENG RIGHT MAGNETO:1" Units="Boolean"/>
                </Operator>
            </TestValue>
            <Duration Value="1.0" Cumulative="False"/>
            <Once>True</Once>
            <Instrument id="MAGNETO"/>
            <Action Copilot="True" Condition="TestValueFalse" Once="true" EventID="MAGNETO_BOTH"/>
            <Action Condition="TestValueTrue" Once="false" StoreVar="Magneto_RPM_BOTH">
                <Val SimVarName="GENERAL ENG RPM:1" Units="rpm"/>
            </Action>
        </Test>
      
        <Sequence SeqType="Unordered">
            <Sequence SeqType="Ordered">
                <Once>True</Once>
                <Test>
                    <TestValue>
                        <Operator OpType="OR"> <!-- Skips if Magneto_RPM_RIGHT is already set -->
                            <Val ReadVar="Magneto_RPM_RIGHT"/>
                            <Operator OpType="And">
                                <Val SimVarName="RECIP ENG LEFT MAGNETO:1" Units="Boolean"/>
                                <Operator OpType="Not">
                                    <Val SimVarName="RECIP ENG RIGHT MAGNETO:1" Units="Boolean"/>
                                </Operator>
                            </Operator>
                        </Operator>
                    </TestValue>
                    <Duration Value="1.5" Cumulative="False"/>
                    <Instrument id="MAGNETO"/>
                    <Action Copilot="True" Condition="TestValueFalse" Once="true" EventID="MAGNETO_LEFT"/>
                </Test>
                <Test>
                    <TestValue>
                        <Operator OpType="OR"> <!-- Skips if Magneto_RPM_RIGHT is already set -->
                            <Val ReadVar="Magneto_RPM_RIGHT"/>
                            <Operator OpType="Greater">
                                <Val SimVarName="GENERAL ENG RPM:1" Units="rpm"/>
                                <Operator OpType="Minus">
                                    <Val ReadVar="Magneto_RPM_BOTH"/>
                                    <Val Value="150"/>
                                </Operator>
                            </Operator>
                        </Operator>
                    </TestValue>
                </Test>
                <Test> <!-- Store the current rpm in Magneto_RPM_LEFT, unless Magneto_RPM_RIGHT is already set -->
                    <TestValue>
                        <Operator OpType="OR"> <!-- Verifies if one of the var is set -->
                            <Val ReadVar="Magneto_RPM_LEFT"/>
                            <Val ReadVar="Magneto_RPM_RIGHT"/>
                        </Operator>
                    </TestValue>
                    <Action Condition="TestValueFalse" Once="True" StoreVar="Magneto_RPM_LEFT">
                        <Val SimVarName="GENERAL ENG RPM:1" Units="rpm"/>
                    </Action>
                </Test>
           </Sequence>
 
           <Sequence SeqType="Ordered">
                <Once>True</Once>
                <Test>
                    <TestValue>
                        <Operator OpType="OR"> <!-- Skips if Magneto_RPM_LEFT is already set -->
                            <Val ReadVar="Magneto_RPM_LEFT"/>
                            <Operator OpType="And">
                                <Val SimVarName="RECIP ENG RIGHT MAGNETO:1" Units="Boolean"/>
                                <Operator OpType="Not">
                                    <Val SimVarName="RECIP ENG LEFT MAGNETO:1" Units="Boolean"/>
                                </Operator>
                            </Operator>
                        </Operator>
                    </TestValue>
                    <Duration Value="1.5" Cumulative="False"/>
                    <Instrument id="MAGNETO"/>
                    <Action Copilot="True" Condition="TestValueFalse" Once="true" EventID="MAGNETO_RIGHT"/>
                </Test>
                <Test>
                    <TestValue>
                        <Operator OpType="OR"> <!-- Skips if Magneto_RPM_LEFT is already set -->
                            <Val ReadVar="Magneto_RPM_LEFT"/>
                            <Operator OpType="Greater">
                                <Val SimVarName="GENERAL ENG RPM:1" Units="rpm"/>
                                <Operator OpType="Minus">
                                    <Val ReadVar="Magneto_RPM_BOTH"/>
                                    <Val Value="150"/>
                                </Operator>
                            </Operator>
                        </Operator>
                    </TestValue>
                </Test>
                <Test> <!-- Store the current rpm in Magneto_RPM_RIGHT, unless Magneto_RPM_LEFT is already set -->
                    <TestValue>
                        <Operator OpType="OR"> <!-- Verifies if one of the var is set -->
                            <Val ReadVar="Magneto_RPM_LEFT"/>
                            <Val ReadVar="Magneto_RPM_RIGHT"/>
                        </Operator>
                    </TestValue>
                    <Action Condition="TestValueFalse" Once="True" StoreVar="Magneto_RPM_RIGHT">
                        <Val SimVarName="GENERAL ENG RPM:1" Units="rpm"/>
                    </Action>
                </Test>
            </Sequence>
        </Sequence>
    </Sequence>
</Checkpoint>
      
<Checkpoint Id="Magneto_50_RPM_Difference_Max">
    <CheckpointDesc SubjectTT="TT:GAME.CHECKLIST_MAGNETOS" ExpectationTT="TT:GAME.CHECKLIST_50RPM_MAX_DIFFERENCE"/>
    <Sequence SeqType="Ordered">
        <Sequence SeqType="Ordered">
            <Once>True</Once>
            <Test>
                <TestValue>
                    <Operator OpType="OR"> <!-- Skips if Magneto_RPM_RIGHT is already set -->
                        <Val ReadVar="Magneto_RPM_RIGHT"/>
                        <Operator OpType="And">
                            <Val SimVarName="RECIP ENG RIGHT MAGNETO:1" Units="Boolean"/>
                            <Operator OpType="Not">
                                <Val SimVarName="RECIP ENG LEFT MAGNETO:1" Units="Boolean"/>
                            </Operator>
                        </Operator>
                    </Operator>
                </TestValue>
                <Duration Value="1.5" Cumulative="False"/>
                <Instrument id="MAGNETO"/>
                <Action Copilot="True" Condition="TestValueFalse" Once="true" EventID="MAGNETO_RIGHT"/>
            </Test>
            <Test>
                <TestValue>
                    <Val ReadVar="Magneto_RPM_RIGHT"/>
                </TestValue>
                <Action Condition="TestValueFalse" Once="True" StoreVar="Magneto_RPM_RIGHT">
                    <Val SimVarName="GENERAL ENG RPM:1" Units="rpm"/>
                </Action>
            </Test>
        </Sequence>
    
        <Sequence SeqType="Ordered">
            <Once>True</Once>
            <Test>
                <TestValue>
                    <Operator OpType="OR"> <!-- Skips if Magneto_RPM_LEFT is already set -->
                        <Val ReadVar="Magneto_RPM_LEFT"/>
                        <Operator OpType="And">
                            <Val SimVarName="RECIP ENG LEFT MAGNETO:1" Units="Boolean"/>
                            <Operator OpType="Not">
                                <Val SimVarName="RECIP ENG RIGHT MAGNETO:1" Units="Boolean"/>
                            </Operator>
                        </Operator>
                    </Operator>
                </TestValue>
                <Duration Value="1.5" Cumulative="False"/>
                <Instrument id="MAGNETO"/>
                <Action Copilot="True" Condition="TestValueFalse" Once="true" EventID="MAGNETO_LEFT"/>
            </Test>
            <Test>
                <TestValue>
                    <Val ReadVar="Magneto_RPM_LEFT"/>
                </TestValue>
                <Action Condition="TestValueFalse" Once="True" StoreVar="Magneto_RPM_LEFT">
                    <Val SimVarName="GENERAL ENG RPM:1" Units="rpm"/>
                </Action>
            </Test>
        </Sequence>
     
        <Test>
            <TestValue>
                <Operator OpType="Equal" Tolerance="50">
                    <Val ReadVar="Magneto_RPM_LEFT"/>
                    <Val ReadVar="Magneto_RPM_RIGHT"/>
                </Operator>
            </TestValue>
        </Test>
    </Sequence>
</Checkpoint>

So, how does this last example work? The user is supposed to set the magneto to "Both", then wait some time for the RPM to stabilize, then measure the current RPM. They then do the same for "Left" and "Right", in any order. The RPM for "Left" or "Right" should be no less than 150 RPM below the RPM for "Both". The RPM for "Left" and "Right" should not be further apart than 50 RPM.

 

Here, the first checkpoint starts by initializing variables to 0, to avoid possible side-effects. Then, the first test measures the RPM for the "Both" setting. The following un-ordered sequence is composed of two ordered sequences, each set up so that only one actually needs to be properly executed: one for "Left" and the other for "Right". The sequence waits 1.5 seconds in the correct settings, and measures the RPM. The difference between RPM "Both" and "Left/Right" is computed, and if small enough, the corresponding RPM is stored in the appropriate variable. The other "Right/Left" variable will keep a value of 0.

 

In the second checkpoint, only one of the first two ordered sub-sequences is actually executed, and the other is skipped, based on which variable among "Left" and "Right" is set, and which still contains 0. The correct sequence will set the corresponding "Left/Right" settings, and measure the RPM. Finally, the last test verifies that the two "Left" and "Right" variables are close enough.

 

 

Generic Library Checkpoints With Aircraft-Specific Modifications

Libraries are useful to share checkpoint definitions across various aircraft checklists, without having to copy-paste a whole block of XML. But sometimes, two aircraft checklists have almost the same checkpoint with only a minor difference. In such situation, it could be useful to be able to reference a checkpoint from a library, but also specify a minor modification, without having to copy-paste the whole block. This is possible for a variety of fields, as detailed in the following sections.

 

Changing Subject, Expectation, Feedback, and Clue

It is possible to replace the <CheckpointDesc /> while loading a library checkpoint through its ReferenceId. The resulting checklist's checkpoint will have identical code (<Action />, <Test>, etc...), but with a new SubjectTT and ExpectationTT instead of those from the library:

<Checkpoint ReferenceId="Taxi_Light_On">
    <CheckpointDesc SubjectTT="Insert_here_a_new_subject" ExpectationTT="Insert_here_a_new_expectation"/>
</Checkpoint>

 

Similarly, it is possible to replace <Feedback> and/or <Clue /> by specifying them in the checklist file. Note that it is also possible to add a feedback or clue to a checkpoint that did not have any in its library definition.

<Checkpoint ReferenceId="Aux_Fuel_Pump_On_3-5Sec_Then_Off">
    <Feedback name="Insert_here_a_feedback_TT" Copilot="True" DurationTimer="True"/>
</Checkpoint>

 

Forcing A Camera And Adding Instrument Highlights

Instruments to be highlighted can be added to a library checkpoint after loading it through its ReferenceId. They will not replace the instruments previously defined (if any), but invalid instruments are always ignored.

<Checkpoint ReferenceId="Flight_Control_Move_Against_AP">
    <Instrument id="YOKE1"/>
    <Instrument id="YOKE2"/>
</Checkpoint>

 

When multiple instruments are to be highlighted, sometimes the camera associated with them is not suitable to be able to see them all. In this case, a <ForceCamera /> element can be added to ignore instruments cameras, and use the one specified instead:

<Checkpoint ReferenceId="TBM_THROTTLE_SET_LOIDLE_WHEN_NG_13">
    <ForceCamera name="Yokes"/>
</Checkpoint>

 

Using Templates To Replace Values Or Actions

If template values are used in the referenced library checkpoint, they can be overridden a similar way in the checklist checkpoint. When writing a library checkpoint that would probably benefit from values that can be overridden (such as aircraft-specific numbers), a good practice is to define some template values (with default values).

 

Here are a couple of examples. The first is a checkpoint that is in a library file, while the second is a checklist checkpoint that overrides only some of the template values defined by the first:

<Checkpoint Id="OIL_PRESS_TEMP_CHECK">
    <CheckpointDesc SubjectTT="TT:GAME.CHECKLIST_OIL_PRESS_TEMP" ExpectationTT="TT:GAME.CHECKLIST_CHECK"/>
    <!-- Those default values are the correct ones for TBM930, but might change for another aircraft -->
    <SetTemplateValue Id="Min Oil Pressure" Value="60"/>
    <SetTemplateValue Id="Max Oil Pressure" Value="135"/>
    <SetTemplateValue Id="Min Oil Temperature" Value="0"/>
    <SetTemplateValue Id="Max Oil Temperature">
        <Val Value="104"/> <!-- More complex expression can be done this way, but for constant values both forms are identical. -->
    </SetTemplateValue>
    <Sequence SeqType="Unordered">
        <Test>
            <TestValue>
                <Operator OpType="BETWEEN">
                    <Val SimVarName="ENG OIL PRESSURE:1" Units="psi"/>
                    <Val UseTemplateValue="Min Oil Pressure"/> <!-- Instead of using the constants directly, template values are referenced, with possibly overwritten values -->
                    <Val UseTemplateValue="Max Oil Pressure"/>
                </Operator>
            </TestValue>
            <Instrument id="HIGHLIGHT_OIL_PRESS"/>
            <Action Copilot="True" Condition="TestValueFalse" Once="false" SpecialAction="WaitUntilTestValueValidated"/>
        </Test>
        <Test>
            <TestValue>
                <Operator OpType="BETWEEN">
                    <Val SimVarName="ENG OIL TEMPERATURE:1" Units="celsius"/>
                    <Val UseTemplateValue="Min Oil Temperature"/>
                    <Val UseTemplateValue="Max Oil Temperature"/>
                </Operator>
            </TestValue>
            <Action Copilot="True" Condition="TestValueFalse" Once="false" SpecialAction="WaitUntilTestValueValidated"/>
        </Test>
    </Sequence>
</Checkpoint>
<Checkpoint ReferenceId="OIL_PRESS_TEMP_CHECK">
    <!-- Overwrite some of the template values, while keeping default values for others -->
    <SetTemplateValue Id="Min Oil Pressure" Value="50"/>
    <SetTemplateValue Id="Max Oil Pressure">
        <Val Value="150"/> <!-- More complex expression can be done this way, but for constant values both forms are identical. -->
    </SetTemplateValue>
</Checkpoint>

 

Similarly, <SetTemplateAction> and UseTemplateAction (an <Action /> attribute) can be used to introduce generic actions in a library checkpoint, for example to set the throttle lever to a specific position in a checkpoint wanting to reach a specific airspeed. This <SetTemplateAction> can then be overridden in the checklist file.

 

The following example presents a library checkpoint and a checklist reference to this checkpoint, for an aircraft with stronger engines (throttle needs to be pushed less to reach same RPM):

<Checkpoint Id="Throttle_Set_1800_RPM">
    <CheckpointDesc SubjectTT="TT:GAME.CHECKLIST_THROTTLE" ExpectationTT="TT:GAME.CHECKLIST_SET_1800RPM"/>
    <SetTemplateAction Id="SetThrottle" Copilot="True" Condition="TestValueFalse" Once="true" EventID="THROTTLE1_SET" EventParam="9997"/>
    <Test>
        <TestValue>
            <Operator OpType="EQUAL" Tolerance="50">
                <Val SimVarName="GENERAL ENG RPM:1" Units="rpm"/>
                <Val Value="1800"/>
            </Operator>
        </TestValue>
        <Duration Value="0.2" Cumulative="False"/>
        <Instrument id="THROTTLE"/>
        <Instrument id="THROTTLE_COPILOT"/>
        <Instrument id="THROTTLE1"/>
        <Instrument id="THROTTLE2"/>
        <Action UseTemplateAction="SetThrottle"/> <!-- Executes the action defined by SetTemplateAction -->
    </Test>
</Checkpoint>
<Checkpoint ReferenceId="Throttle_Set_1800_RPM">
    <SetTemplateAction Id="SetThrottle" Copilot="True" Condition="TestValueFalse" Once="true" EventID="THROTTLE1_SET" EventParam="9200"/>
</Checkpoint>

 

 

Cleaning State After Copilot Mode

Some checkpoints might require temporarily moving some controls into a non-idle state to verify their proper behavior. To avoid finishing the checkpoint while keeping said controls in such state, additional tests could be added to check if they are properly returned to idle. While one may expect the User to do this on their own, forcing them to do this is not very user-friendly. In Copilot mode, controls should usually be returned back to normal upon exiting a checkpoint. To this end, it is recommended to add the following action, changing the attributes to the required ones:

<Action Copilot="True" Condition="TestValueTrue" Once="True" SpecialAction="WaitForDuration" Value="1.5"/>

 

As the element of a test, this action will trigger once the testValue is true, only in Copilot mode, and it will add a delay of 1.5 seconds. This way, Copilot checklist progression may appear more natural.

 

Here is a complex example using this technique:

<Checkpoint Id="Flight_Control_Free_And_Correct">
    <CheckpointDesc SubjectTT="TT:GAME.CHECKLIST_FLIGHT_CONTROLS" ExpectationTT="TT:GAME.CHECKLIST_FREE_AND_CORRECT"/>
    <Sequence SeqType="Unordered">
        <Test>
            <Once>True</Once>
            <TestValue>
                <Operator OpType="LESS">
                    <Val SimVarName="YOKE X POSITION" Units="percent"/>
                    <Val Value="-95"/>
                </Operator>
            </TestValue>
            <Action Copilot="True" Condition="TestValueFalse" Once="true" EventID="AILERON_SET" EventParam="16383"/>
            <Action Copilot="True" Condition="TestValueTrue" Once="true" SpecialAction="WaitForDuration" Value="1.0"/>
            <Instrument id="YOKE_X"/>
        </Test>
        <Test>
            <Once>True</Once>
            <TestValue>
                <Operator OpType="GREATER">
                    <Val SimVarName="YOKE X POSITION" Units="percent"/>
                    <Val Value="95"/>
                </Operator>
            </TestValue>
            <Action Copilot="True" Condition="TestValueFalse" Once="true" EventID="AILERON_SET" EventParam="-16383"/>
            <Action Copilot="True" Condition="TestValueTrue" Once="true" SpecialAction="WaitForDuration" Value="1.0"/>
            <Instrument id="YOKE_X"/>
        </Test>
        <Test>
            <Once>True</Once>
            <TestValue>
                <Operator OpType="LESS">
                    <Val SimVarName="YOKE Y POSITION" Units="percent"/>
                    <Val Value="-90"/>
                </Operator>
           </TestValue>
           <Action Copilot="True" Condition="TestValueFalse" Once="true" EventID="AILERON_SET" EventParam="0"/>
           <Action Copilot="True" Condition="TestValueFalse" Once="true" EventID="ELEVATOR_SET"  EventParam="16383"/>
           <Action Copilot="True" Condition="TestValueTrue" Once="true" SpecialAction="WaitForDuration" Value="1.0"/>
           <Instrument id="YOKE_Y"/>
        </Test>
        <Test>
            <Once>True</Once>
            <TestValue>
                <Operator OpType="GREATER">
                    <Val SimVarName="YOKE Y POSITION" Units="percent"/>
                    <Val Value="90"/>
                </Operator>
            </TestValue>
            <Action Copilot="True" Condition="TestValueFalse" Once="true" EventID="ELEVATOR_SET" EventParam="-16383"/>
            <Action Copilot="True" Condition="TestValueTrue" Once="true" SpecialAction="WaitForDuration" Value="1.0"/>
            <Instrument id="YOKE_Y"/>
        </Test>
        <Test>
            <Once>True</Once>
            <TestValue>
                <Operator OpType="LESS">
                    <Val SimVarName="RUDDER POSITION" Units="percent"/>
                    <Val Value="-66"/>
                </Operator>
            </TestValue>
            <Instrument id="RUDDER_PEDALS"/>
            <Action Copilot="True" Condition="TestValueFalse" Once="true" EventID="ELEVATOR_SET" EventParam="0"/>
            <Action Copilot="True" Condition="TestValueFalse" Once="true" EventID="RUDDER_SET" EventParam="16383"/>
            <Action Copilot="True" Condition="TestValueTrue" Once="true" SpecialAction="WaitForDuration" Value="1.0"/>
        </Test>
        <Test>
            <Once>True</Once>
            <TestValue>
                <Operator OpType="GREATER">
                    <Val SimVarName="RUDDER POSITION" Units="percent"/>
                    <Val Value="66"/>
                </Operator>
            </TestValue>
            <Instrument id="RUDDER_PEDALS"/>
            <Action Copilot="True" Condition="TestValueFalse" Once="true" EventID="RUDDER_SET" EventParam="-16383"/>
            <Action Copilot="True" Condition="TestValueTrue" Once="true" SpecialAction="WaitForDuration" Value="1.0"/>
        </Test>
    </Sequence>
    <Action Copilot="True" Condition="End" EventID="AILERON_SET" EventParam="0"/>
    <Action Copilot="True" Condition="End" EventID="ELEVATOR_SET" EventParam="0"/>
    <Action Copilot="True" Condition="End" EventID="RUDDER_SET" EventParam="0"/>
</Checkpoint>

 

 

Nesting Operators

Whether used to store a value in a variable with storeVar or just to evaluate some testValue, operators can be nested (almost) infinitely to compute complex values using various SimVars, variables, and constants.

 

Here is a pseudo-example, that evaluates the code equivalent of:

(MyFakeVariable || ((FirstFakeSimVar-SecondFakeSimVar < 10) && (FirstFakeSimVar-SecondFakeSimVar > -10)):

<Operator OpType="OR">
    <Val ReadVar="MyFakeVariable"/>
    <Operator OpType="AND">
        <Operator OpType="LESS">
            <Operator OpType="MINUS">
                <Val SimVarName="FirstFakeSimVar" Units="feet"/>
                <Val SimVarName="SecondFakeSimVar" Units="feet"/>
            </Operator>
            <Val Value="10.0"/>
        </Operator>
        <Operator OpType="GREATER">
            <Operator OpType="MINUS">
                <Val SimVarName="FirstFakeSimVar" Units="feet"/>
                <Val SimVarName="SecondFakeSimVar" Units="feet"/>
            </Operator>
            <Val Value="-10.0"/>
        </Operator>
    </Operator>
</Operator>

 

 

Nesting Sequences

Although in most cases it is not necessary to nest <Sequence> elements - because a sequence can contain any number of tests - sequences can be nested, and this can enable more complex behavior. For example, a checkpoint could be composed of 2 sequences of actions (e.g: some actions on a Right device, and the same on a Left device), and each of these sequences will require their action(s) to be executed in order, yet the 2 sequences could be done one after the other in any order. Such a case could be handled as follows:

<Sequence SeqType="Unordered">
    <Sequence SeqType="Ordered">
        <Test>
            <!-- Insert here the first part for Right device -->
        </Test>
        <Test>
            <!-- Insert here the second part for Right device -->
        </Test>
    </Sequence>
    <Sequence SeqType="Ordered">
        <Test>
            <!-- Insert here the first part for Left device -->
        </Test>
        <Test>
            <!-- Insert here the second part for Left device -->
        </Test>
    </Sequence>
</Sequence>

 

 

Executing Only One Of Two Sequences

Executing only one out of two <Test> elements can usually be solved by having only one test for which the testValue contains an operator OR between the two tests required. However, if one out of two ordered <Sequence> elements has to be chosen, the solution is trickier.

 

To resolve this, a trick that works well is to create two variables (one for each sequence) and initialize them to 0. Then, every TestValue in a sequence verifies if the variable for the other sequence is set or if they are the normal TestValue. Finally, each sequence contains a last test that verifies if any of these two variables is set, and then sets one variable. Here's an example:

<Action Condition="Init" StoreVar="Seq1Finished" Value="0"/>
<Action Condition="Init" StoreVar="Seq2Finished" Value="0"/>
<Sequence SeqType="Unordered">
    <Sequence SeqType="Ordered">
        <Test>
            <TestValue>
                <Operator OpType="OR">
                    <Val ReadVar="Seq2Finished"/>
                    <!-- Insert here the Val or Operator for this "normal" Test -->
                </Operator>
            </TestValue>
            <!-- Insert here possible actions -->
        </Test>
        <!-- Similarly, other Tests ... -->
        <Test>
            <TestValue>
                <Operator OpType="OR">
                    <Val ReadVar="Seq1Finished"/>
                    <Val ReadVar="Seq2Finished"/>
                </Operator>
            </TestValue>
            <Action Condition="TestValueFalse" StoreVar="Seq1Finished" Value="1"/>
        </Test>
    </Sequence>
    <Sequence SeqType="Ordered">
        <Test>
            <TestValue>
                <Operator OpType="OR">
                    <Val ReadVar="Seq1Finished"/>
                    <!-- Insert here the Val or Operator for this "normal" Test -->
                </Operator>
            </TestValue>
            <!-- Insert here possible actions -->
        </Test>
        <!-- Similarly, other Tests ... -->
        <Test>
            <TestValue>
                <Operator OpType="OR">
                    <Val ReadVar="Seq1Finished"/>
                    <Val ReadVar="Seq2Finished"/>
                </Operator>
            </TestValue>
            <Action Condition="TestValueFalse" StoreVar="Seq2Finished" Value="1"/>
        </Test>
    </Sequence>
</Sequence>

 

 

Automatic Action (Copilot) Example

In this example, the two WaitUntilTestValueValidated are what is most important. Without them, in Copilot mode, both Tests would be automatically skipped - because they would have no Copilot Action - and they would have a TestValue "True" for the Sequence, which in turn means the Sequence Action with Condition="TestValueFalse" would not trigger:

<Checkpoint Id="SPEED_BRAKES_TEST">
    <CheckpointDesc SubjectTT="TT:GAME.CHECKLIST_SPEED_BRAKES" ExpectationTT="TT:GAME.CHECKLIST_CHECK"/>
    <Sequence SeqType="PARALLEL">
        <Test>
            <TestValue>
                <Operator OpType="EQUAL" Tolerance="2">
                    <Val Code="(A:SPOILERS LEFT POSITION, percent)"/>
                    <Val Value="100"/>
                </Operator>
            </TestValue>
            <Action Copilot="True" Condition="TestValueFalse" SpecialAction="WaitUntilTestValueValidated"/>
        </Test>
        <Test>
            <TestValue>
                <Operator OpType="EQUAL" Tolerance="2">
                    <Val Code="(A:SPOILERS RIGHT POSITION, percent)"/>
                    <Val Value="100"/>
                </Operator>
            </TestValue>
            <Action Copilot="True" Condition="TestValueFalse" SpecialAction="WaitUntilTestValueValidated"/>
        </Test>
        <Action Copilot="True" Condition="TestValueFalse" Once="False" Code="(&gt;B:HANDLING_Spoilers_Deploy)"/>
    </Sequence>
</Checkpoint>