Mission Scripting Foundation Documentation
Current release: 1.02
ED Forums Thread For discussion and downloads of current version.
This is transcribed from an auto-translation of the original Russian msf_mission_developers_guide.pdf documentation Original Documention is available at the ED Forums thread linked above. This is a WIP 14/54 pages completed.
Contents
Who should read this guide?
This guide is intended for developers using DCS World, who want to expand the standard features by means of the Simulator Scripting Engine (SSE) and this add-on script engine framework called the Mission Scripting Foundation (MSF).
Assumed Knowledge
- Knowledge of the programming language Lua, Lexical conventions, Basic types, Expressions and operators, Scope
- The basic types, classes, methods and properties provided by SSE.
- Understanding the principles of programming ?Event Based Progamming Model?
- The Mission Editor (ME)
General Guidelines for script for DCS World
- The texts of all the scripts used in the DCS World have to be encoded UTF8 without BOM.
- Names of groups and units for use with Mission Scripting Foundation, should meet the [1]Lua:lexical naming conventions of Lua]
- Any script running under SSE is blocked; (does not return to DCS World until a result) so a hung script to hang the entire server and a slow script can slow the entire server.
- Heavy calculations in terms of performance should be distributed in time.
- Return code should be less than the frame period for an average FPS (at 30 FPS this is 22.5 ms).
Overview of the Mission Scripting Foundation
Mission Scripting Foundation (MSF) - gives developers of SSE missions a working framework and examples of framework functionality that can be applied in missions to give; scripted behaviours to units, dynamic generation of groups and virtual-groups, interaction with and command of units and group/virtual-group enities to the end goal of creating intelligent air defense, dynamic artillery, dynamic logisitcs and transport systems, and many more possibilities.
MSF is developed on the basis of the script engine SSE, it relies on capabilities available in SSE.
MSF Architecture
Mission Scripting Foundation provides functionality via the namespace mission.
In turn, mission includes the following three components:
- mission.model is a structured meta-table of information about all the entities (objects). The model provides as close to a real-time table of the mission state as possible. The mission.model can take entities populated in the Mission Editor and dynamically add new functionality to create new model objects.
- mission.controller component provides a model to interact directly with the player as controller by using interfaces in the game such as the F10 Radio Menu, and text chat messages. When calling the respective controller methods in scripts. The mission.controller provides functions to start\stop the refresh cycle model and to route messages and audio transmissions to specific groups, countries and coalitions.
- mission.view component provides a table that is a queue of text messages for recipients virtual-groups\groups\coalitions\countries and allows for the playback of queued audio messages for virtual-groups\groups\coalitions\countries recipients. Components rely on the MSF mission.model because they require the meta-table.
- mission.utils component is a namespace that includes a set of various useful functions
Using MSF
Step by step instruction for using in mission.
- Download the latest versions of the script
- Load MSF.lua script or MSF_beta_xxx.lua with trigger at start of mission.
- Initialize the state of the MSF mission.model
- Identify objects in the mission that you want to augment and communicate with via MSF.
- Add objects (by unit name or group name) to the mission.model using a basic MSF method called mission.model:addUnit() and use advanced methods like mission.model.addAirDefenceGroupment() to group units and attach event handlers related to air defence roles. You can write your own advanced methods using existing methods as a guide. Advanced methods and object types are described further in this document. Depending on the complexity of the mission and the behaviors programmed, the initialization script may be contained in a single lua file or divided logically into several files. Example: ground_defense_init.lua, air_defense_init.lua, transport_init.lua etc ...
- Optional: Add sound objects for use by MSF event handlers (for automatically generating speech events between units and groups). Use the mission.model:addSound() method for each sound object you want to add. Put the list into an initialization file.
- Start Process. After adding objects the developer must call the mission.controller:start() method that updates the mission table structure and begins the MSF processing loop. MSF constantly updates the status of the objects included in the mission.model. When an object's state changes, MSF gives notice in the form of events. MSF gives developers the opportunity to link these events with higher logic that can modify the course of the mission or the behavior of the objects involved in the mission. The most significant task the developer must perform is to determine what events need to be monitored and what objects require in terms of their role and what actions to perform.
- Mission completion. Mission end conditions are met then call mission.controller:stop() method.
Utility functions of MSF
Here we will describe available developmer tools in MSF that provide a utility function for use inside larger scripts. These utlity functions are widely used in examples further on in this documentation so familiarity with them will be helpful
All utility functions implemented in MSF are found in namespace: mission.utils
We will list these functions, provide descriptions and examples of use.
mission.utils.getDistance(_point1,_point2)
Args: _point1 and _point2 are Vec3 points
Returns: returns Number in meters
Example:local _point1 = { x = 100, y = 50, z = 400 }; local _point2 = { x = 104, y = 51, z = 401 }; local _result = mission.utils.getDistance(_point1, _point2); trigger.action.outText ('Distance between two points:' .. string.format ("% .3f", _result), 15);
> The distance between the points: 4.123
mission.utils.getHeading(_position)
Args: _position is an SSE Pos3 type --position and orientation
Returns: Number - as heading in degrees
Example: Get the azimuth of an object with name Shilka.
local _shilka = Unit.getByName('Shilka'); then get position and orientation local _shilka_position = _shilka:getPosition(); then azimuth local _azimuth = mission.utils.getHeading (_shilka_position); trigger.action.outText('Azimuth Shilka: ' .. string.format(“%.3f”, _azimuth));
mission.utils.transformPoint(_position,_local_point)
Args: _position is the position and orientation of a vehicle in a SSE Pos3 type _local_point is point in space in a SSE Vec3 type
Returns: Vec3 --global point
Example: Transform a coordinate from local to the object to the global coordinate system
local _global_point = mission.utils.transformPoint(_shilka_position, _local_point); trigger.action.outText('local point {x = 0, y = 0, z = 1}'.. 'with respect to the unit _shilka ' .. 'in global co-orindates equals {'.. ' x =' .. String.format("% .3f", _global_point.x) .. ' Y =' .. string.format("% .3f", _global_point.y) .. ' Z =' .. string.format("% .3f", _global_point.z) .. '}' ', 15);
mission.utils.getLogic(Number)
Arg: Number is probability from 0 to 1;
Returns: Boolean
Example: None Given
mission.utils.getEnumItemNameById(Number _enum_value, Table _enum)
Args: _enum_value --an index number _enum enumeration type --an SSE table
Returns: String --enumerated from table
Example:Local _shilka = Unit.getByName('Shilka'); --Returns Unit Object local _shilka_country = _shilka:getCountry(); --returns Number local _shilka_country_name = mission.utils.getEnumItemNameById( _shilka_country, country.id); -- retrieves string of country name from SSE table country.id using index trigger.action.outText ('Country of Shilka is :' .. _shilka_country_name, 15)
mission.utils.getRCS(_unit_type,_has_external_weapon)
This is a built-in function unique to MSF that uses a lookup table of pre-calculated values to get a more accurate value for Radar Cross Section
Args: _unit_type is SSE TypeName (only helicopters and aircraft) _has_external_weapon is Boolean
Example: None Given
mission.utils.getGuidanceAt(_from,_to)
Args: _from is object that is the reference for guidance _to is object that is the destination
Returns: Distance in meters, Azimuth in degrees
Example:local _shilka, _tank = Unit.getByName('Shilka'), Unit.getByName('Tank'); local _range, _azimuth = mission.utils.getGuidanceAt(_shilka, _tank); trigger.action.outText ('azimuth goal Tank:' .. String.format ("% .3f", _azimuth) .. ', delete:' .. string.format ("% .3f", _range), 15)
mission.utils.getGuidanceAtAir(Object _from, Object _to)
Provides direction from one object in the air towards another airborne object
Args: _to is the object that is the target _from is the object to recieve directions
Returns: Number -- distance to target in meters Number -- deviation in azimuth from present course in degrees (- left|right +) Number -- difference in height in meters (- below|above +) Number -- speed of convergence in m/s (- diverge|converge +)
Example:local _figther, _bandit = Unit.getByName('Figther'), Unit.getByName('Bandit'); local _range, _heading_diff, _altitude_diff, _closing_speed = mission.utils.getGuidanceAtAir(_figther, _bandit); local _heading_dir = 'Right'; if _heading_diff < 0 then _heading_dir = 'left'; end local _altitude_dir = 'above'; if _altitude_diff < 0 then _altitude_dir = 'below'; end local _closing_status = 'Distance unchanged'; if _closing_speed < 0 then _closing_status = 'diverging'; end if _closing_speed > 0 then _closing_status = 'converging'; end local _targeting_report = 'New target: \n'; _targeting_report = _targeting_report .. 'range: ' .. string.format(“%.2f”, _range) .. '\n'; if math.abs(_heading_diff) > 2 then ignore small course corrections _targeting_report = _targeting_report .. _heading_dir .. string.format(“%.1f”, _heading_diff) .. '\n'; end if math.abs(_heading_diff) > 100 then ignore altitude differences of less than 100m if _altitude_diff > 1000 then _altitude_diff, _ = math.modf(_altitude_diff / 1000); end _targeting_report = _targeting_report .. _altitude_dir .. string.format(“%.1f”, _altitude_diff) .. '\n'; end _targeting_report = _targeting_report .. _closing_status; convey intercept as message trigger.action.outText(_targeting_report, 15);
mission.utils.getPYR(_position)
A function for obtaining direction angles, roll and pitch of an object
Args: _position is position and orientation Position3 type
Returns: Number Pitch in degrees Number Direction in degrees Number Roll in Degrees
Example: Not given
mission.utils.getCargoTemplateByGroupName(_group_name,_offset_point,_cargo_template)
A function for obtaining a cargo template for use in transportation groups.
Args: _group_name is the group name from the editor to copy the template from. _offset_point is Vec3 point offset from the landing point where the cargo will be positioned _cargo_template is an MSF type for cargo templates. This arguement if an empty table will populated with the correct strcuture.
Returns: modifies _cargo_template
Example: MSF Cargo types and examples are given in further chapters.
mission.utils.getGroupDescriptor(_group_name, _point, _unit_table)
A function to create new vehicle groups
Arguments: _group_name is a group name which will be created. Should not already exist. _point is a Vec3 point at which the group will be created _unit_table is a MSF type table of units that should be included in new group. msfUnitDescriptor structure is described in future chapter on the msfGroup class.
Returns: modifies mission databases
BITWISE operations
WIP 14/54 pages completed Haven't even got near the good stuff yet.