ArmA 2 Forum, ArmA 2 Home, ArmA 2 Config, ArmA 2 File Formats, ArmA 2 Missions, ArmA 2 3D Modeling, ArmA 2 Scripting, ArmA 2 Terrain, ArmA 2 Texturing, ArmA 2 Tools
FSM Editor Manual
http://community.bistudio.com/wiki/FSM_Editor_Manual
Terminology
Inside this documentation, the following terms are used:
Basic knowledge for designers
There is an information about some warnings and errors every designer should know.
1. Save as
2. Getting the errors/warnings information
3. Common Warnings and Errors
o every FSM state should have different name. If not, the name will be slightly changed through compilation, which can be checked in the compilation result (fsm scripted for instance)
o all conditions called from the same state should also have different name
o if the same condition is used for more states, the condition and action code will be compiled to more different places in the compilation result. But only one of them can be used during decompilation! So, one cannot freely change the compilation result in text editor (decompilation can indeterministically copy such changes to all places or ignore it at all).
o impossible, as no one can say, what happens when the condition is true
o you cannot concatenate conditions, you should combine their condition to one or insert dummy state in between 4. Using knees
States
Every state can has two editable tabs:
1. Init code
2. Precondition
Conditions are tested in the decreasing oreder of their priority. This implies that True conditions should have zero priority on order not to shadow other conditions to be tested.
Conditions
Conditions have three editable tabs and priority edit box:
1. Precondition
2. Condition
3. Action
4. Priority is used to define the order to process the conditions. Higher values first.
In FSMScripted, multiline scripts can be used too. The last statement is relevant, as shown in the example:
_vehicle = vehicle _this; _commander = effectiveCommander _vehicle; isHidden _commander
FSM Compiler
FSMCompilers compiles the FSM created (or edited) in FSMEditor into some other format, using compile config.
At present, the following formats and compile configs are possible:
FSM Entity
FSM using FSMEntity functions. This FSM is reffered in config, loaded and processed during simulation. This FSM format is currently used for ambient behaviour (butterfly, honeybee, dragonfly).
class CfgNonAIVehicles { class DragonFly: Insect { model = "dragonfly.p3d"; flySound[]={animals\fly.wss,db-105,1, 1}; fsm[] = {"Dragonfly"}; straightDistance=2; }; ... }
Thresholds
Each state defines thresholds, which can be used to define which of multiple links from this state is selected. This is done like:
thresholds[] = { {1, 0, 1} };
This will store a random value with a minimal value of 0 (second element) and a maximum value of 1 (third element) and store it in slot 1 (first element). Every condition returns a value. This value is compared against the number a defined slot:
threshold = 1;
When the condition value is greater or equal than the value in the slot, this link is selected.
When FSM starts, all threshold slots are initialized to 0.5. Slot value set by one state is then left at that value even for all states to come.
FSM Scripted
FSM using scripted commands and condition. These FSM are not used yet, but were tested on simple FSM (teleport), trigered by radio alpha.
New functions commandFSM and doFSM added:
_unit xxxFSM [“FSM filename”, destination, target]
in scripts in FSM, following parameters are defined:
to make this application useful, some functions for controlling units on low level needs to be added.
Global Switch FSM
Compilation to the *.cpp code, using switch to navigate through FSM states. The compile uses many FSM attributes, to define function declaration, precondition codes etc. This FSM was first used in seagull.cpp to code autopilot functionality. So, opening seagull.cpp in FSMEditor.
Class Compile FSM
Compilation to the *.cpp, using Fsm class architecture. It creates %(stateName) functions for state initialization and check%(stateName functions for checking conditions. No FSM created by FSMEditor has been compiled and used in engine, but some were coded manually before FSMEditor existence.
How does the FSMCompiler work
We say, that FSMCompiler works as compiler, if it compiles FSM edited in FSMEditor into any other format. And we say, FSMCompiler works as decompiler, if it decompiles compilation result into FSM format, which can FSMEditor read.
In order to make decompilation possible, compilation must write some decompile info into compilation result. Compiler writes this info using xml like tags enclosed, by default, by C/C++ program comments ”/*…*/“.
The compilation result has the following structure:
/*%FSM<COMPILE "compileConfigPath, fsmName">*/ /*%FSM<HEAD>*/ /* item0[] = {"someStateName",0,250,-55.278748,-369.225311,34.721249,-319.225342,0.000000;} item1[] = {"someOtherStateName",4,218,-55.288883,-274.332214,34.711143,-224.332199,1.000000;} ... link0[] = {0,1}; link1[] = {0,3}; ... globals[] = {0.000000,1,0,1,65280,640,480,1,25,6316128,1,-147.218781,307.800598,236.949921,-392.713837,482,667,1}; window[] = {0,-1,-1,-1,-1,894,66,837,87,1,500}; *//*%FSM</HEAD>*/ AND HERE IS RESULT OF PASS COMPILATION /*%FSM</COMPILE>*/
The whole result is enclosed by COMPILE tag, with compileConfig and FSMName specified. In the HEAD tag, there are data to specify GUI representation of FSM, in order to display it's structure the same way, it was last edited and saved in FSMEditor. Each Compile tag uniquelly determines the FSM compiled into some file, by its FSMName. File can contain more than one FSM, each enclosed by it's COMPILE tags with different FSMName. It works in such a way, that:
o it will be appended to the place marked by /*%FSM<APPEND/>*/ tag, or to the end of file otherwise.
Compile configs
Compile config is param file, which controls compilation process. It contains three main classes:
All classes or command names should contain some postfix to make their multiple usage possible. For instance, you can use multiple prints inside one class, using for something like print_1, print_2, etc. It is due to paramFile assumption of name uniqueness.
Compile config - Classes structure
The classes have the following structure:
o Can contain: class Pass
o the content of this class will be processed for the whole FSM o Can contain: State, FinalStates, print, noDecompile
o the content of this class will be processed for each FSM state o Can contain: Link, FinalStates, print, noDecompile
o the content of this class will be processed for each FSM condition o Can contain: FinalStates, print, noDecompile
o the content of this class will be processed for each final state o Can contain: print
o It is one of three root classes o contains array value names[].
o It is one of three root classes o it defines prefixes and sufixes of tags for decompilation o Can contain: + process = 1; … 0 for not processing Decompile info + FSMLeft = ”/*“; … what to write before tag + FSMRight = “*/”; … what to write after tag + class FSMPrefix … prefix of opening tags + class FSMPrefix2 … prefix of closing tags + class FSMSufix … sufix of opening tags + class FSMSufix2 … sufix of closing tags
o defines prefixes and sufixes for every tag o Can contain: + default = ”“; … value for tags which are not specified + tagName = “someText”; … value for specific tag
o it defines text to print into compilation result
example: print_1 = “FSM contains %(numStates) states, from which %(numFinalStates) are final\n”;
o Some specific FSM values can be printed using the following format: ***%modifier(varName)
+ modifiers:
# %( … text is not modified
# %quoted( … quatation chars ” are doubled
# %qt( … enclose the text into quotes “”
# %qtquoted( … combine qt and quoted together
+ varNames:
# statename … name of state which is currently processed
# linkname … name of condition which is currently processed
# stateinit … state initialization code
# statePrecondition … precondition code before condition testing
# condition … condition code
# action … action code
# condPrecondition … precondition code before testing this condition
# to … target state to change if this condition is true
# priority … priority
# initStatename … name of starting state
# finalStatename … name of final state currently processed (iterates inside class FinalStates)
# numStates … total number of FSM states
# numConditions … total number of condition within current state
# numFinalStates … total number of final states
# fsmName … name of FSM
# “anyAttributeName” … any other attribute defined in FSMEditor
+ some specific char can be printed using the following:
# %% … the char %
#
… the char \
# \n … the newline char
# \t … the tabulator char
* entry indent
o specifies the number of spaces to insert before each line of compilation result
o value -1 for no “indenting”
* entry rewritefile
o value 0 … output will be appended to the file
o value 1 … output will rewrite the file
* entry ifstart
o value -1 … process only states, which are not starting
o value 1 … process only starting states
o value 0 … process both starting and not starting states
* entry iffinal
o value -1 … process only states, which are not final
o value 1 … process only final states
o value 0 … process both final and not final states
* entry iffirst
o value -1 … from now on, process only iff the state/finalState/link is not the first
o value 1 … from now on, process only iff the state/finalState/link IS the first one
o value 0 … do not check first/not first (default)
o This is needed when printing some arrays and the first item should be printed different way
print_3 = "_finalStateArray = ["; class FinalStates { iffirst_yes = 1; print_1 = "%qt(finalStateName)"; iffirst_no = -1; print_2 = ", %qt(finalStateName)"; //not first, so start with comma separator iffirst_all = 0; } print_4 = "];\n";
o value 1 … convert all values to one line o value 0 … converting to one line off
o value 1 … printing decompile tags off o value 0 … printing decompile tags on
Printing decompile tags
In order to allow decompiler to rebuild the FSM from compilation result, each state, condition or other values must be processed during compilation. If compilation uses many passes, than there is no need to use decompile tags printing in each pass. You can control the compile tags printing, using the following:
o No tags at all.
o Using hprint instead of print has the effect of switching noDecompile on, but only within the scope of this one print. If the noDecompile is switched on yet, the hprint has no effect.
o It prints all tags used inside print text. If the noDecompile is switched on yet, the print works like hprint.
Remarks
1. Scripted FSM does not allow values containing newline chars. In order not to force user to write all values (in FSMEditor) into one line, there is modifier clearNewLines. It can be used inside Compile class.
2. If there is such need to enclose value into quotes, the modifier qt should be used.