Home   Help Search Login Register  

Author Topic: The FSM enigma...  (Read 3752 times)

0 Members and 1 Guest are viewing this topic.

Offline laggy

  • Members
  • *
  • "Behold a pale horse"
The FSM enigma...
« on: 29 Jul 2009, 23:35:58 »
Hi everyone,

Can anyone tell me what the h*ll a FSM file is for?
I am completely clueless when it comes to this riddle.
Does someone actually write this stuff?

This example is the shortest I could find and is taken from the campaign mission "Harvest Red".
Sorry if it is too long, just shorten it in that case, I thought a complete code would be necessary.

setCaptive.FSM
Code: [Select]
/*%FSM<COMPILE "C:\bis\fsmeditor\scriptedFSM.cfg, setCaptive">*/
/*%FSM<HEAD>*/
/*
item0[] = {"Init",0,4346,100.000000,-100.000000,200.000000,-50.000000,0.000000,"Init"};
item1[] = {"always",8,218,100.000000,-25.000000,200.000000,25.000000,0.000000,"always"};
item2[] = {"nothing",2,250,100.000000,50.000000,200.000000,100.000000,0.000000,"nothing"};
item3[] = {"player_joined__",4,218,100.000000,125.000000,200.000000,175.000000,0.000000,"player" \n "joined / left"};
item4[] = {"reset_captive_st",2,250,100.000000,200.000000,200.000000,250.000000,0.000000,"reset" \n "captive status"};
item5[] = {"",7,210,44.477524,221.155640,52.477539,229.155640,0.000000,""};
item6[] = {"",7,210,44.212105,-3.410065,52.212120,4.589926,0.000000,""};
link0[] = {0,1};
link1[] = {1,2};
link2[] = {2,3};
link3[] = {3,4};
link4[] = {4,5};
link5[] = {5,6};
link6[] = {6,1};
globals[] = {25.000000,1,0,0,0,640,480,1,200,6316128,1,-150.236465,408.991119,385.731812,-96.601913,1040,897,1};
window[] = {2,-1,-1,-1,-1,968,220,1180,220,3,1057};
*//*%FSM</HEAD>*/
class FSM
{
  fsmName = "setCaptive";
  class States
  {
    /*%FSM<STATE "Init">*/
    class Init
    {
      name = "Init";
      init = /*%FSM<STATEINIT""">*/"_pool = +(_this);" \n "" \n "{" \n " if (captive _x) then {" \n " _x setVariable [""overriden"", TRUE]" \n " } else {" \n " _x setVariable [""overriden"", FALSE]" \n " }" \n "} forEach _pool;" \n "" \n "debuglog str(_pool);"/*%FSM</STATEINIT""">*/;
      precondition = /*%FSM<STATEPRECONDITION""">*/""/*%FSM</STATEPRECONDITION""">*/;
      class Links
      {
        /*%FSM<LINK "always">*/
        class always
        {
          priority = 0.000000;
          to="nothing";
          precondition = /*%FSM<CONDPRECONDITION""">*/""/*%FSM</CONDPRECONDITION""">*/;
          condition=/*%FSM<CONDITION""">*/"true"/*%FSM</CONDITION""">*/;
          action=/*%FSM<ACTION""">*/""/*%FSM</ACTION""">*/;
        };
        /*%FSM</LINK>*/
      };
    };
    /*%FSM</STATE>*/
    /*%FSM<STATE "nothing">*/
    class nothing
    {
      name = "nothing";
      init = /*%FSM<STATEINIT""">*/""/*%FSM</STATEINIT""">*/;
      precondition = /*%FSM<STATEPRECONDITION""">*/""/*%FSM</STATEPRECONDITION""">*/;
      class Links
      {
        /*%FSM<LINK "player_joined__">*/
        class player_joined__
        {
          priority = 0.000000;
          to="reset_captive_st";
          precondition = /*%FSM<CONDPRECONDITION""">*/""/*%FSM</CONDPRECONDITION""">*/;
          condition=/*%FSM<CONDITION""">*/"{(isPlayer _x && captive _x && (lifeState _x) != ""UNCONSCIOUS"") || (!(isPlayer _x) && !(captive _x))} count _pool > 0"/*%FSM</CONDITION""">*/;
          action=/*%FSM<ACTION""">*/""/*%FSM</ACTION""">*/;
        };
        /*%FSM</LINK>*/
      };
    };
    /*%FSM</STATE>*/
    /*%FSM<STATE "reset_captive_st">*/
    class reset_captive_st
    {
      name = "reset_captive_st";
      init = /*%FSM<STATEINIT""">*/"{" \n " if (isPlayer _x && captive _x && (lifeState _x) != ""UNCONSCIOUS"") then {" \n " _nic = [objNull, _x, rSETCAPTIVE, FALSE] call RE" \n " } else {" \n " if (!(isPlayer _x) && !(captive _x)) then {_nic = [objNull, _x, rSETCAPTIVE, TRUE] call RE}" \n " }" \n "} forEach _pool"/*%FSM</STATEINIT""">*/;
      precondition = /*%FSM<STATEPRECONDITION""">*/""/*%FSM</STATEPRECONDITION""">*/;
      class Links
      {
        /*%FSM<LINK "always">*/
        class always
        {
          priority = 0.000000;
          to="nothing";
          precondition = /*%FSM<CONDPRECONDITION""">*/""/*%FSM</CONDPRECONDITION""">*/;
          condition=/*%FSM<CONDITION""">*/"true"/*%FSM</CONDITION""">*/;
          action=/*%FSM<ACTION""">*/""/*%FSM</ACTION""">*/;
        };
        /*%FSM</LINK>*/
      };
    };
    /*%FSM</STATE>*/
  };
  initState="Init";
  finalStates[] =
  {
  };
};
/*%FSM</COMPILE>*/

Ugghh !  :blink:  What does it do and why is it needed ?

Grateful for any answers.

Laggy
And I looked and beheld a pale horse and his name that sat on him was Death and Hell followed with him.

Offline Inkompetent

  • Members
  • *
Re: The FSM enigma...
« Reply #1 on: 29 Jul 2009, 23:47:51 »
The FSM, or Finite State Machine, is practically complex setup of switch-case scripts that are the game's AI.

There is the default FSM in the game, that is the basic AI behaviour in ArmA2, but one can also code own FSMs for customized AI behaviour.

Plainly put it is probably the most complex mess you can stick your nose into in ArmA2. About the same level as making models by writing them in binary code :P

Very useful for zombie mods and stuff though, where you drastically want to change the behaviour of things. Although I'm not sure how ArmA2 handles the stuff. In ArmA1 the default FSM had higher priority than custom ones, so as soon as the game encountered something covered by the default FSM it canceled the custom one.

Offline laggy

  • Members
  • *
  • "Behold a pale horse"
Re: The FSM enigma...
« Reply #2 on: 29 Jul 2009, 23:58:21 »
But it looks like the code is written by some kind of editor and not by a... human.
Do you need some kind of program to do this or just a crazy binary brain structure?

EDIT:

Is the FSM code bound to the model?

I remember when I did createUnit "pastor" (the german shepard dog, which is originally an agent, not unit), into a group.

The dog obeyed certain commands, but refused to board a vehicle for example. It also had worse path finding than a human unit.
« Last Edit: 30 Jul 2009, 09:13:09 by bedges »
And I looked and beheld a pale horse and his name that sat on him was Death and Hell followed with him.

Offline JamesF1

  • Editors Depot Staff
  • *****
    • JamesBurgess.co.uk
Re: The FSM enigma...
« Reply #3 on: 30 Jul 2009, 00:44:46 »
Well, as FSMs are almost universally represented (in Computer Science) using graphs/circuit diagrams (for the sake of simplicity), I would tend to presume that BIS would have had a useful FSM editor on hand.  Either that, or therein lies an excellent explanation as to why the AI are so buggy ;)  They're incredibly useful for making decision/state-based AI systems relatively quickly.

I do seem to recall an FSM editor being available somewhere for ArmA1... but I could just be dreaming that up.

Offline Kremator

  • Members
  • *
Re: The FSM enigma...
« Reply #4 on: 30 Jul 2009, 00:52:03 »

Offline Worldeater

  • Former Staff
  • ****
  • Suum cuique
Re: The FSM enigma...
« Reply #5 on: 30 Jul 2009, 01:02:20 »
BIS has a FSM Editor [1]. From the VBS2 website:

Quote
Note, the FSM Editor will be included in the VBS2 Development Suite as a free update in 2009.

I really hope us mere ARMA folks get this editor for free, too (just like the other editing stuff).


[1] Nobody would write this stuff using a text editor. You may end up in a room with cushioned walls wearing a jacket with very long sleeves and the buttons up the back.
try { return true; } finally { return false; }

Offline laggy

  • Members
  • *
  • "Behold a pale horse"
Re: The FSM enigma...
« Reply #6 on: 30 Jul 2009, 01:08:12 »
Thanks for all the good answers  :good:

I can sleep well now.

Laggy
And I looked and beheld a pale horse and his name that sat on him was Death and Hell followed with him.

Offline Le_CuLtO

  • Members
  • *
Re: The FSM enigma...
« Reply #7 on: 31 Jul 2009, 00:29:00 »

Offline Rommel92

  • Members
  • *
Re: The FSM enigma...
« Reply #8 on: 31 Jul 2009, 08:43:23 »
To help you out, removing all comments from those scripts, actually makes it easily editable.
One I made recently:
Code: [Select]
class FSM
{
  fsmName = "PREDLOHA";
  class States
  {
class React
{
name = "React";
init = "";
precondition = "";
class Links
{
class CaseA
{
priority = 1.000000;
to="ContinueTalking";
precondition = "";
condition="_sentenceId == 'line_p_0'";
action="";
};
class CaseB
{
priority = 1.00000;
to="ContinueTalkingB";
precondition = "";
condition="_sentenceId == 'line_p_0b'";
action="";
};
class CaseC
{
priority = 1.00000;
to="KillYou";
precondition = "";
condition="_sentenceId in ['line_p_1b','line_p_1c']";
action="";
};
class CaseD
{
priority = 1.00000;
to="GiveYou";
precondition = "";
condition="_sentenceId == 'line_p_1a'";
action="";
};
class interrupted
{
priority = 1.000000;
to="ContinueTalking";
precondition = "";
condition="_sentenceId == 'interrupted'";
action="";
};
class always
{
priority = 0.000000;
to="END";
precondition = "";
condition="true";
action="";
};
};
};
class END
{
name = "END";
init = "";
precondition = "";
class Links
{
};
};
class ContinueTalking
{
name = "ContinueTalking";
init = "_this kbTell [_from, _topic,'line_m_1'];"
precondition = "";
class Links
{
};
};
class ContinueTalkingB
{
name = "ContinueTalkingB";
init = "_this kbTell [_from, _topic,'line_m_1b'];"
precondition = "";
class Links
{
};
};
class Killyou
{
name = "Killyou";
init = "_this kbTell [_from, _topic,'line_m_2b']; _this dofire _from;"
precondition = "";
class Links
{
};
};
class Giveyou
{
name = "GiveYou";
init = "_this kbTell [_from, _topic,'line_m_2a'];"
precondition = "";
class Links
{
};
};
  };
  initState="React";
  finalStates[] =
  {
"END",
"ContinueTalking",
"ContinueTalkingB",
"Killyou",
"Giveyou"
  };
};

Bit more simple:
Code: [Select]
class FSM
{
  fsmName = "PREDLOHA";
  class States
  {
    class React
    {
      name = "React";
      init = "";
      precondition = "";
      class Links
      {
        class FirstWords
        {
          priority = 1.000000;
          to="ReplyA";
          precondition = "";
          condition="_sentenceId == 'line_m_0'";
          action="";
        };
        class AnotherReply
        {
          priority = 1.000000;
          to="ReplyB";
          precondition = "";
          condition="_sentenceId == 'line_m_1'";
          action="";
        };
        class always
        {
          priority = 0.000000;
          to="END";
          precondition = "";
          condition="true";
          action="";
        };
      };
    };
    class END
    {
      name = "END";
      init = "";
      precondition = "";
      class Links
      {
      };
    };
    class ReplyA
    {
      name = "ReplyA";
      init = "_this kbTell [_from, _topic,'line_p_0'];";
      precondition = "";
      class Links
      {
      };
    };
    class ReplyB
    {
      name = "ReplyB";
      init = "_this kbTell [_from, _topic,'line_p_1'];";
      precondition = "";
      class Links
      {
      };
    };
  };
  initState="React";
  finalStates[] =
  {
    "END",
    "ReplyA",
    "ReplyB",
  };
};

SQF equivalent:
Code: [Select]
BIS_convMenu = [];

switch (_sentenceId) do {
case "line_p_0":
{
_this kbtell [_from, _topic,"line_m_1"];
};
case "line_p_0b":
{
_this kbtell [_from, _topic,"line_m_1b"];
};
case "line_p_1a":
{
_this kbtell [_from, _topic,"line_m_2a"];
removeallweapons this;
};
case "line_p_1b":
{
_this kbtell [_from, _topic,"line_m_2b"];
_this doFire _from;
};
case "line_p_1c":
{
_this kbtell [_from, _topic,"line_m_2c"];
_this doFire _from;
};
};

BIS_convMenu
Code: [Select]
// collect reactions to BIS_convMenu _this _from _topic _sentenceid
BIS_convMenu = [];

switch (_sentenceId) do {
case "line_m_0":
{
BIS_convMenu = BIS_convMenu + [["So what", _topic, "line_p_0", []]];
BIS_convMenu = BIS_convMenu + [["Well arent you the cool kid", _topic, "line_p_0b", []]];
};
case "line_m_1":
{
BIS_convMenu = BIS_convMenu + [["I envy you", _topic, "line_p_1a", []]];
BIS_convMenu = BIS_convMenu + [["I love you", _topic, "line_p_1b", []]];
BIS_convMenu = BIS_convMenu + [["I want to kill you", _topic, "line_p_1c", []]];
};
case "line_m_1b":
{
BIS_convMenu = BIS_convMenu + [["I envy you", _topic, "line_p_1a", []]];
BIS_convMenu = BIS_convMenu + [["I love you", _topic, "line_p_1b", []]];
BIS_convMenu = BIS_convMenu + [["I want to kill you", _topic, "line_p_1c", []]];
};
};

BIS_convMenu

Hopefully this helps you understand.
« Last Edit: 31 Jul 2009, 08:45:35 by Rommel92 »