Skip to main content

Interaction with DCS

This section explains the mechanism prepared to control DCS World from fsmapper.

Changing DCS's Internal State

fsmapper provides several methods to interact with cockpit controls within DCS World, such as cockpit switches, buttons, and knobs. One method is to specify the ID of the clickable control and a numerical value representing its position to change the control’s state. The other method is to execute user-defined Lua code directly within DCS. The former provides a straightforward way to express the desired action, while the latter offers users more flexibility and advanced control capabilities.

Setting position of cockpit controls

To change the state of clickable controls within the cockpit, dcs.perform_clickable_action() and dcs.clickable_action_performer(), which generates a native action performing the same operation, are available. These functions applies the same effect to the aircraft in flight as the ‘X: COCKPIT PERFORM CLICKABLE ACTION’ in the DCS World Mission Editor. Each argument provided to the function corresponds to the same parameters as in ‘X: COCKPIT PERFORM CLICKABLE ACTION'.

Note

The device ID and command value to be specified in the above functions for identifying the clickable controls to be operated need to be extracted from the Lua scripts of each aircraft module. For information on which files contain these definitions and how they are defined, refer to the 'X: COCKPIT PERFORM CLICKABLE ACTION' section of the DCS User Manual.

Here is an example of setting the altitude display on the F/A-18 HUD to BARO.

-- Device ID = 34, Command = 3008
dcs.perform_clickable_action(34, 3008, 1)

You can also specify multiple values in a sequence for a clickable control. In the following example, the F-16C’s ICP button 1 is pressed and then released.

-- Device ID = 17, Command = 3003
dcs.perform_clickable_action(17, 3003, 1, 0)

Executing a Lua chunk

You can also instruct fsmapper to execute any Lua chunk within the DCS World process. To facilitate this, fsmapper provides the following functions.

In the following example, A Lua chunk that toggles the Stores Config Switch on the F-16C is registered and executed.

-- Register a Lua chunk to toggle the Stores Config Switch
local toggle_stores_config = dcs.register_chunk([[
local current = GetDevice(0):get_argument_value(358)
GetDevice(2):performClickableAction(3011, current == 0 and 1 or 0)
]])

-- Execute the registered Lua chunk
dcs.execute_chunk(toggle_stores_config)

Retrieving DCS's Internal State

fsmapper provides a mechanism to observe DCS World's cockpit data and notify the change of the cockpit data as an Event. The Event Value of the triggered event is exactly the value of the observed cockpit data.

You can start observing cockpit data by calling dcs.add_observed_data() with an array of Observed Data Definition tables as the argument. To stop the observation and event triggering, you can call dcs.clear_observed_data().

Observable data types

There are three ways to specify the observed cockpit data as below.

  • Position of cockpit controls
    By specifying the argument_number parameter in the Observed Data Definition, you can observe elements such as switch positions, button press states, and indicator lamp statuses. The observation targets you can specify are the same as those covered by the ‘X: COCKPIT ARGUMENT IN RANGE’ trigger in the DCS Mission Editor.

  • Indication text
    By specifying the indicator_id parameter in the Observed Data Definition, you can observe the display content of indicators such as the IFEI in the F/A-18C or the DED in the F-16C. The indicators you can observe are the same as those covered by the ‘X: COCKPIT INDICATION TEXT IS EQUAL TO’ trigger in the DCS Mission Editor.

  • Data generated by executing Lua chunk
    When you specify a Lua chunk as a string in the chunk parameter of the Observed Data Definition, the return value of the chunk is observed. This method allows for complex behaviors, such as creating an Event Value that combines the states of multiple controls. Unless you specify a filter to change the type of the value, the return value of the chunk must be either a string or a number.

Here is an example of registering three types of observed data for the F/A-18C.

-- Register events to notify the change of F/A-18C cockpit data
local change_master_caution_light = mapper.register_event('Master Caution Light')
local change_ufc = mapper.register_event('UFC')
local change_total_fuel = mapper.register_event('Total Fuel')

-- Register observed data definitions
dcs.add_observed_data{
-- Observing the master caution light state
{event=change_master_caution_light, argument_number=13},

-- Observing the indication text of UFC
{event=change_ufc, indicator_id=6},

-- Observing total amount of fuel retrieved from IFEI
{event=change_total_fuel, chunk=[[
local IFEI = list_indication(5)
if IFEI then
local fuel = IFEI:gmatch('\ntxt_FUEL_UP\n([^\nT]*)')
return tonumber(fuel())
end
]]}
}
Note

To find the corresponding values for the argument_number or indicator_id parameters for cockpit instruments of each aircraft module, refer to the 'X: COCKPIT ARGUMENT IN RANGE' trigger and the 'X: COCKPIT INDICATION TEXT IS EQUAL TO' trigger sections in the DCS User Manual.

Filter

By specifying the filter parameter in the Observed Data Definition, you can limit event triggering to only when the observed cockpit data has a specific value or transform the data into another value to be used as the Event Value.

If an array table is specified for the filter parameter, the event is triggered when the observed value changes to one of the values in the table. In the following example, a filter of this form is used to prevent triggering an event when a 3-position switch is in an intermediate position.

-- Register an event to notify the change of AP ROLL switch on F-16C
local change_ap_roll_switch = mapper.register_event('AP_ROLL_SW')

-- Register observed data definition
dcs.add_observed_data{
{
event = change_ap_roll_switch,
argument_number = 108, -- Observing the F-16C AP ROLL switch
-- Only trigger the event if the switch is in one of the three stable positions
filter = {1, 0, -1},
}
}

If a string representing a Lua chunk is specified for the filter parameter, the chunk is called every frame in DCS World, with the observed value passed as an argument. The return value of the chunk becomes the Event Value. However, if the chunk does not return a value, or if the return value’s type is not a string or number, the event will not be triggered.

Here is an example of a filter that converts the position value of the F-16C’s Stores Config switch into meaningful strings.

-- Register an event to notify the change of Stores Config switch on F-16C
local change_stores_config_switch = mapper.register_event('STORES_CONFIG_SW')

-- Register observed data definition
dcs.add_observed_data{
{
event = change_stores_config_switch,
argument_number = 358, -- Observing the F-16C Stores Config switch
filter = [[
local value = ...
if value == 0 then
return 'CAT I'
elseif value == 1 then
return 'CAT III'
end
]]
}
}

Lua chunk within DCS

The Lua chunks specified in dcs.register_chunk() and dcs.add_observed_data() each have their own unique environment derived from the calling context when executed within the DCS process. To be more specific, a new table is created with the table representing the calling environment assigned to the __index field of metatable, and this new table is set as the environment for each chunk. This minimizes the risk of global variable access within the chunk affecting global variables in other chunks, DCS core modules, or aircraft modules.

On the other hand, the global variable fsmapper refers to the same table across all chunks. If you need to exchange information between chunks, store values in the table referenced by the fsmapper global variable.

note

While fsmapper uses Lua 5.4, DCS World is built with Lua 5.1. The string representing the chunk to be executed within DCS must comply with Lua 5.1 specification.