INTERACTION PROCEDURES

To compliment Interaction Configurations you can create Interaction Procedures. These are essentially Input Events which are not necessarily linked to a specific interaction, and using them can be a good way to have an "Interaction Manager" when several interactions can potentially affect each other, or when the state of multiple things need to be checked.

 

To give an example, say your landing lights depend on the state of 2 different switches - the "normal" way to do it would be to have an input event for each switch, and every time the position of one of these switches is changed, they need to verify the state of the other switch to figure out if the light needs to be on or not. An alternative for this using a procedure is to have these switches only control their own state which is tracked by a variable for each switch. We then have a procedure that is watching these variables so that it updates when either is changed, with the update deciding on the state of the light based on these two variables. This means that you isolate the whole logic within the procedure rather than having two separate switches with two different logic setups regarding the state of the lights.

 

Another thing that procedures facilitates is binding an input - like a keyboard press - such that instead of having to bind two or three interactions with complex logic in each, you only need 1. We can also use procedures for things that go beyond a single interaction, for example, overriding the normal auto-start behavior. If your aircraft has some specific logic which means that the normal Ctrl+E behavior would not start it, you can use a procedure to intercept that Ctrl+E input and add some extra interactions to it.

 

 

Creating A Procedure

To create a procedure we will use the model behavior template ASOBO_Procedure_Template. When using this template the first thing we need to do is give it a unique identifier, like this:

<UseTemplate Name="ASOBO_Procedure_Template">
    <PROCEDURE_ID>Wipers_Simulation</PROCEDURE_ID>
</UseTemplate>

 

With this setup, the <UseTemplate> element will look for a Parameter Function helper named after your procedure following this pattern:

Get_Procedure_#PROCEDURE_ID#_Parameters

 

So - with the example code above and following the naming pattern - we would have to define a parameter function called Get_Procedure_Wipers_Simulation_Parameters:

<ParametersFn Name="Get_Procedure_Wipers_Simulation_Parameters">
    <!-- (...) -->
</ParametersFn>

 

To define the code that should be executed by the procedure we do not use ASOBO_Append_Init_Code_Helper (as we would have for interaction configurations), but instead we simply return the parameter ON_VALUE_CHANGED with, as content, the code you wish to execute when a watched variable changes value:

<ParametersFn Name="Get_Procedure_Wipers_Simulation_Parameters">
    <ReturnParameters>
        <UseParametersFn Name="ASOBO_Watch_Simvar_Helper">
            <SIMVAR>CIRCUIT SWITCH ON:1</SIMVAR>
        </UseParametersFn>
        <ON_VALUE_CHANGED>(A:CIRCUIT SWITCH ON:1, Bool) (O:_IsOn) != if{ (O:_IsOn) ! (&gt;O:_IsOn) }</ON_VALUE_CHANGED>
    </ReturnParameters>
</ParametersFn>

 

 

Ticking

If your procedure relies on a lot of variables or needs to act on a system over time, you’ll want your code to execute every frame to watch for any relevant changes. To achieve this we use the parameter TICK_EVERY_FRAME, eg:

<TICK_EVERY_FRAME>True</TICK_EVERY_FRAME>

 

This will configure the procedure for continuous updates, once per frame. You don’t need to (and shouldn’t) have any watched variables in this case. Note that delta time since last update is stored inside the macro variable @TICK_Get_Delta_Time. You can use this delta to apply changes to the system based on the elapsed simulation time. Since the ticking is based on simulation time, you can use the macro variable @E_SimulationTime to get the current time.

 

 

Helper Functions

Setting up procedures can be prone to errors, and so to help limit their occurrence some helper functions have been created in the model behavior templates:

 

  • ASOBO_Procedure_Next_Safe_Jump_Flag_Helper - Whenever your code needs to jump to a given flag you need to make sure not to reuse the same number twice or you’ll end up jumping to the wrong place. To fix that inconvenience jump flags should always be defined using using this helper function:
    <UseParametersFn Name="ASOBO_Procedure_Next_Safe_Jump_Flag_Helper">
        <OUT_PARAM_NAME>AFTER_POS_CHANGED</OUT_PARAM_NAME>
    </UseParametersFn>
    <!-- AFTER_POS_CHANGED = 0 -->
    <UseParametersFn Name="ASOBO_Procedure_Next_Safe_Jump_Flag_Helper">
        <OUT_PARAM_NAME>AFTER_POS_TICK</OUT_PARAM_NAME>
    </UseParametersFn>
    <!-- AFTER_POS_TICK = 1 -->
    <!-- (...) -->
    <ON_VALUE_CHANGED>
        (A:CIRCUIT SWITCH ON:1, Bool) (O:_IsOn) != if{ 
            (O:_IsOn) ! (&gt;O:_IsOn) 
        } els{ g#AFTER_POS_CHANGED# }
        (* Position just changed *)
        :#AFTER_POS_CHANGED#
        (* Position tick *)
        :#AFTER_POS_TICK#
    </ON_VALUE_CHANGED>

    Every time you call this function it will give you a new flag you can use, different to the previous one. By default the value will be output in the parameter NEXT_SAFE_JUMP_FLAG, but you should always name the output parameter differently if you want to call this function several times in a row.

 

  • ASOBO_Procedure_Get_Next_Safe_Var_Helper - In some instances you may want to ensure every stack variable is unique with it’s own unique index. To do so we use helper function. Every time you call this function, it will give you a new flag you can use, different from the one before:
    <UseParametersFn Name="ASOBO_Procedure_Get_Next_Safe_Var_Helper">
        <OUT_PARAM_NAME>VAR_FROM</OUT_PARAM_NAME>
    </UseParametersFn>
    <!-- VAR_FROM = 0 -->
    <UseParametersFn Name="ASOBO_Procedure_Get_Next_Safe_Var_Helper">
        <OUT_PARAM_NAME>VAR_TO</OUT_PARAM_NAME>
    </UseParametersFn>
    <!-- VAR_TO = 1 -->
    <!-- (...) -->
    <ON_VALUE_CHANGED>
        (A:CIRCUIT SWITCH ON:1, Bool) if{
            0 sp#VAR_FROM# 1 sp#VAR_TO#
        } els{
            1 sp#VAR_FROM# 0 sp#VAR_TO#
        }
        (O:_Var) != l#VAR_TO# if{
            (* interpolate *)
        }
    </ON_VALUE_CHANGED>
    By default the value will be output in the parameter NEXT_SAFE_VAR but you should always name the output parameter differently as you want to call this function several times in a row.

 

  • ASOBO_Move_Interpolation_Helper - Interpolation between 2 values can be simplified by using this helper function, which takes 5 parameters:
    • START_VALUE - Where to interpolate from.
    • END_VALUE - Where to interpolate to.
    • SET_NEW_VALUE - Setter for the new computed value.
    • COEFFICIENT - Alpha coefficient (0 to 1) of the desired value.
    • OUT_PARAM_NAME - Name of the parameter containing the generated code snippet.

    Note that this is is usually a calculation you want to do over time to get a smooth interpolation. Here is a concrete example which updates the cabin altitude at a given rate:

    <Parameters Type="Override">
        <UseParametersFn Name="ASOBO_Aircraft_Sim_Parameters"/>
    </Parameters>
    <Parameters Type="Override">
        <!-- altitude is converted back to pressure externally -->
        <UseParametersFn Name="ASOBO_Move_Interpolation_Helper">
            <START_VALUE>(O:_CurrentPlaneAltitude)</START_VALUE>
            <SET_NEW_VALUE>(&gt;O:_CurrentPlaneAltitude)</SET_NEW_VALUE>
            <END_VALUE>#GET_PLANE_ALTITUDE#</END_VALUE>
            <COEFFICIENT>(O:_CabinAltRate) @TICK_Get_Delta_Time *</COEFFICIENT>
            <OUT_PARAM_NAME>LERP_CABIN_ALTITUDE</OUT_PARAM_NAME>
        </UseParametersFn>
    </Parameters>
    <ReturnParameters>
        <TICK_EVERY_FRAME>True</TICK_EVERY_FRAME>
        <ON_VALUE_CHANGED>
            (O:_CurrentPlaneAltitude) (O:_TargetPlaneAltitude) != if{
                (* Check if the target altitude is attainable using outside air pressure *)
                (O:_CurrentPlaneAltitude) (O:_TargetPlaneAltitude) &lt;
                (O:_CurrentPlaneAltitude) #GET_PLANE_ALTITUDE# &lt; == if{
                    #LERP_CABIN_ALTITUDE#
                } els{
                    (* Need to use an other mean to attain the target altitude *)    
                }
            }
        </ON_VALUE_CHANGED>
    </ReturnParameters>

 

 

Creating Custom Input Variables (B: Vars)

Input variables are tied to a specific aircraft but are accessible everywhere. Behind the scenes they are essentially input events (B: vars in RPN), defined using some of the model behavior templates (which one you use depend son the variable type). You can create the following two kinds of custom input variables:

 

  • Boolean - To create a bool variable use the template ASOBO_Bool_Variable_Template. This template takes a VARIABLE_ID and exposes an interface to interact with the variable, for example:
    <!-- Declare the variable -->
    <UseTemplate Name="ASOBO_Bool_Variable_Template">
        <VARIABLE_ID>Pitot_Damage_Visible</VARIABLE_ID>
    </UseTemplate>
    <!-- Check the variable value -->
    (B:VARIABLE_Pitot_Damage_Visible, Bool)
    <!-- Toggle the variable -->
    (&gt;B:VARIABLE_Pitot_Damage_Visible_Toggle)
    <!-- Set the variable -->
    (O:_IsDamageVisible) (&gt;B:VARIABLE_Pitot_Damage_Visible_Set)

 

  • Number - To create a variable with a value other than a boolean we use the template ASOBO_Number_Variable_Template. This template takes a VARIABLE_ID and - optionally - a VALUE_UNITS string (Number, by default) and also exposes an interface to interact with the variable, for example:
    <!-- Declare the variable -->
    <UseTemplate Name="ASOBO_Number_Variable_Template">
        <VARIABLE_ID>Fuel_Temperature</VARIABLE_ID>
        <VALUE_UNITS>celsius</VALUE_UNITS>
    </UseTemplate>
    <!-- Check the variable value -->
    (B:VARIABLE_Fuel_Temperature)
    <!-- Check the variable value in a different unit -->
    (B:VARIABLE_Fuel_Temperature, farenheit)
    <!-- Set the variable -->
    (O:_ComputedFuelTemperature, celsius) (&gt;B:VARIABLE_Fuel_Temperature_Set)
    <!-- Add or remove a value using Inc and Dec -->
    15 (&gt;B:VARIABLE_Fuel_Temperature_Inc) (* +15°C *)
    12.3 (&gt;B:VARIABLE_Fuel_Temperature_Dec) (* -12.3°C