Author Topic: Universal warrior brain for MCO  (Read 6493 times)

0 Members and 1 Guest are viewing this topic.

Offline magic

  • Moderator
  • 211
Universal warrior brain for MCO
There is a file UniversalBrain.ABL under data/mission/warriors folder. I tried to make one universal brain that will make things easier for mission designers. Here is "how to" use it.

//****************************************************************************************//
//
//      Universal Warrior Brain for Mech Commander Omnitech
//****************************************************************************************//

fsm UniversalBrain; //EACH BRAIN MUST HAVE AN UNIQUE FSM ID..- every brain file used in the same mission must have different fsm name


   var

      static WorldPosition      startPosition;
      static PatrolState      PState;
      static PatrolPath      PPath;

      static boolean         willRequestHelp;
      static real            lastHelpRequestTime;
      static real            helpRequestFrequency;
      static integer         AttackStateHandle;
      static boolean         poweredDown;
      static boolean         powerUp;
      //static boolean         been_hit;  //use this if powered down and you want to power up when hit.
      //static boolean         All_power; //use this if powered down and you want to power up all mates on this unit power-up.

      static integer         scanRange;
      static WorldPosition      MovePoint;
      static integer         escortSquadID;
      static integer[20]      moverList;
      static real            escortRange;

      static boolean         IsEscortUnitDead;
      static worldPosition       guardSpot;


static integer         Orders1; //declare here for control in this file or declare in main mission.abl as eternal boolean for control from there.
//****************************************************************************************

function init;

    code


//********************************************************************
//               Scan Ranges for Unit
      scanRange = 500;

//********************************************************************
// Patrol brain part - only need to change if you make a patrol brain or complex brain controlled from main mission.ABL
//               Patrol STATE
      PState[0] = 1;       // This is the Type of Patrol. 0 = Linear. 1 = Looping
                  //(Linear = Unit will move from 1 to 2 to 3, then 3 to 2 to 1) Assuming there are only 3 points to the Patrol
                  //(Looping = Unit will move from 1 to 2 to 3, then 1 to 2 to 3) Assuming there are only 3 points to the Patrol
      PState[1] = 7;       //This is the Amount of Move Points there are listed below. Make sure you Count Patrol Point '0'
      PState[2] = -1;    //This is How many Times the unit will perform the Patrol.. (-1 = Forever).

//               Patrol Points below

      //Enter the Coordinates of where you want the Unit to Patrol. It will do them in Order Start from 0 and ending at the Last Point
      //Make sure you change the Index number (numbers in Brackets [0, 0] to match the correct Patrol Point.
      //Also, the number of Mover Points MUST match the number you have entered in the Patrol State.

      PPath[0, 0] = -3178;   //X coordinate found in the editor
      PPath[0, 1] = -6208;   //Y coordinate found in the editor
      PPath[1, 0] = -4842;
      PPath[1, 1] = -3520;
      PPath[2, 0] = -5184;
      PPath[2, 1] = -704;
      PPath[3, 0] = -4416;
      PPath[3, 1] = 1898;
      PPath[4, 0] = -3050;
      PPath[4, 1] = 2666;
      PPath[5, 0] = -704;
      PPath[5, 1] = -789;
      PPath[6, 0] = 2112;
      PPath[6, 1] = -2794;

      PState[3] = PATROL_DIRECTION_FORWARD;   
      PState[4] = -1;    //reset cur point
      PState[5] = -1;    //reset cur cycle
      PState[6] = CONTACT_CRITERIA_ENEMY + CONTACT_CRITERIA_VISUAL_OR_SENSOR + CONTACT_CRITERIA_NOT_DISABLED;   

//********************************************************************
// Escort brain part - only need to change if you make escort brain or complex brain controlled from main mission.ABL
//            Unit ID to escort
      escortSquadID = 2; //This is the Squad ID (Found in editor) for the unit you want to escort
      escortRange = 250.0; //How far the escorting unit will drift


//         Guard Location if escortee is dead   
      guardSpot[0] = -704; //The X Coordinate (Found in the editor) is the area this Unit will Guard if the Unit it is suppose to Escort is destroyed
      guardSpot[1] = 4842; //The Y Coordinate (Found in the editor) is the area this Unit will Guard if the Unit it is suppose to Escort is destroyed
      guardSpot[2] = 0;

      IsEscortUnitDead = False;
      getUnitMates(escortSquadID, moverList);

//********************************************************************

      // Grab his start position...
      getObjectPosition(-1, startPosition);
      setTargetPriority(0, TARGET_PRIORITY_CURTARGET, -1, 150, CONTACT_CRITERIA_ENEMY + CONTACT_CRITERIA_VISUAL_OR_SENSOR + CONTACT_CRITERIA_NOT_DISABLED);
      setTargetPriority(1, TARGET_PRIORITY_MOVER, 0, scanRange, CONTACT_CRITERIA_ENEMY + CONTACT_CRITERIA_VISUAL_OR_SENSOR + CONTACT_CRITERIA_NOT_DISABLED);
      setTargetPriority(2, TARGET_PRIORITY_NONE, 0, 0, 0);
      AttackStateHandle = getStateHandle("attack");
      willRequestHelp = true; //?true or false
      helpRequestFrequency = 20.0; //?in secs
      lastHelpRequestTime = -100.0;

      setWillHelp(True);
//********************************************************************
//use this if unit is powered down

poweredDown = False;
powerUp = True;
//been_hit = True;
//All_power = True;

//********************************************************************
//Use this if unit powered down and out of map

MovePoint[0] = -448;
MovePoint[1] = -7146;
MovePoint[2] = 0;

//********************************************************************
//Control variable use to set brain type - you can init here or init in main mission ABL and control/change from there
//If it is used from main mission ABL comment out declaration and init here. There could be more OrdersX variables (Orders1, Orders2)
//change Orders1 in this file accordingly.

Orders1 = 0;    //0 - guard
      //1 - attack object - guard
      //2 - moveto position - guard
      //3 - patrol
      //4 - dredattack
      //5 - sentry
      //6 - escort
      
endfunction;

//----------------------------------------------------------------------------------------

function update : integer;

   var

      boolean      processingPilotEvents;
      integer      pilotEventID;
      integer      pilotState;
      integer[20]      pilotEventParams;
      integer      curTarget;
      real         curTime;
      real[3]      myPos;
      real[3]      attackerPos;
      integer      curStateHandle;
      static integer         numFunctionalWeapons;
      static integer[20]      weaponList;

   code

      curTime = getTime;
      curStateHandle = getCurrentStateHandle;


      //--------------------------------------------------
      // Process the pilot events since the last update...
      numFunctionalWeapons = getWeapons(weaponList, 1);
      if (numFunctionalWeapons == 0) then
         trans noWeapons;
      endif;

      //--------------------------------------------------
      // Check to see escorting Unit is dead
      if (((objectStatus(moverList[0]) == 1) or (objectStatus(moverList[0]) == 2)) and (Not IsEscortUnitDead)) then
         IsEscortUnitDead = True;
      endif;

      processingPilotEvents = TRUE;
      while (processingPilotEvents) do
         pilotEventID = getNextPilotEvent(pilotEventParams);
         if (pilotEventID == PILOT_EVENT_NONE) then
            processingPilotEvents = FALSE;
         else
            switch (pilotEventID)
               case PILOT_EVENT_TARGETED:
                  curTarget = getTarget(-1);
                  if (lastHelpRequestTime < (curTime - helpRequestFrequency)) then
                     lastHelpRequestTime = curTime;
                     if (willRequestHelp) then
                        getObjectPosition(pilotEventParams[0], attackerPos);
                        getObjectPosition(-1, myPos);
                        requestHelp(pilotEventParams[0], myPos, 300.0, attackerPos, 300.0, 1);
                     endif;
                  endif;
                  numFunctionalWeapons = getWeapons(weaponList, 0);
                  if (curStateHandle <> AttackStateHandle) then
                     if ((numFunctionalWeapons > 0) and (curTarget == 0)) then
                        corerun = True;
                        magicAttack(pilotEventParams[0]);
                        setState(AttackStateHandle);
                     endif;
                  endif;
                  endcase;
               case PILOT_EVENT_ATTACK_ORDER:
                  curTarget = getTarget(-1);
                  if (curStateHandle <> AttackStateHandle) then
                     if ((numFunctionalWeapons > 0) and (curTarget == 0))then
                        corerun = True;
                        magicAttack(pilotEventParams[0]);
                        setState(AttackStateHandle);
                     endif;
                  endif;
                  endcase;
               case PILOT_EVENT_FIRED_WEAPON:
                  endcase;
               case PILOT_EVENT_HIT:
                  if ((poweredDown) AND (powerUp)) then
                     corePower(True);
                     powerUp = False;
                  endif;
                  endcase;
            endswitch;
         endif;
      endwhile;

      return(0);

endfunction;

//----------------------------------------------------------------------------------------

state noWeapons;

   code

      if (objectClass(-1) == 2) then
         coreEject;
      else
         corePower(false);
      endif;
      
endstate;

//----------------------------------------------------------------------------------------

state attack;

   code

      update;
      corerun = True;
      magicAttack(0);
      resetOrders(1);
      transBack;

endstate;

//----------------------------------------------------------------------------------------

state start;

   var

      worldposition      escortPos;

   code

//Activate this if unit is powered down
//      if (not poweredDown) then
//         corePower(false);
//         poweredDown = true;
//      endif;

//      if ((been_hit) AND (beenhit)) then //beenhit is a system variable that is set to True when hit by weapon fire
//         corePower(True);
//         been_hit = False; //close this loop forever unit is active
//         All_powerup = True; //global variable defined in main mission.ABL used for global power-up other from beenhit - here used to send power-up signal for all mates
//         All_power = False; //close the following loop forever unit is active
//      endif;
      
//      if ((All_power) AND (All_powerup)) then //this loop is used if you recive power-up signal from mates or global power-up (All_powerup=True)
//         corePower(True);
//         All_power = False; //close this loop forever unit is active
//         been_hit = False; //close the previous loop forever unit is active
//      endif;


   
switch (Orders1)
   case 0:
      corerun = True;
      magicGuard(startposition, -1);
   endcase;
   case 1:
      if ((getenemycount(-1) == 0)) then
         if isalive(73402) then                               //73402 is building ID from the editor - target can be mover (you must use getUnitMates(SquadID, moverList);
            magicAttack(73402);                       //magicAttack(moverList[0]);
         endif;
      else
         corerun = True;
         getObjectPosition(-1, startPosition);
         magicGuard(startposition, -1);
      endif;

   endcase;
   case 2:
      if (distancetoposition(-1, MovePoint) > 150) then
         corerun = True;
         coreMoveTo(MovePoint, TACORDER_PARAM_RUN);
      else
         corerun = True;
         getObjectPosition(-1, startPosition);
         magicGuard(startposition, -1);
      endif;   
      
   endcase;
   case 3:
      corerun = True;
      magicPatrol(PState, PPath);

   endcase;
   case 4:
      corerun = True;
      getObjectPosition(-1, startPosition);
      magicGuard(startposition, -1);
   endcase;
   case 5:
      coreRun = True;
      coreSentry(startposition, 300, -1);
   endcase;
   case 6:
   if not IsEscortUnitDead then   
      getObjectPosition(moverList[0], escortPos);
      corerun = True;
      setMoveArea(escortPos, escortRange);
      magicEscort(moverList[0]);
   else
      coreRun = True;
      magicGuard(guardSpot, -1);
   endif;

   endcase;
endswitch;

      update;
      resetOrders(1);
endstate;

//----------------------------------------------------------------------------------------

endfsm.

In order to use this brain you must copy then change file name and change fsm ID (usually the same as file name).
Everything is controlled by Orders1 variable.

Orders1 = 0;    //0 - guard
      //1 - attack object - guard
      //2 - moveto position - guard
      //3 - patrol
      //4 - dredattack
      //5 - sentry
      //6 - escort

It can be defined locally in this file or globally in main mission.ABL file.
If you only want one type of brain local declaration is enough you just need to change the line Orders1 = X.

Orders1 = 0)
no need to change anything it is simple guard brain

Orders1 = 1)
if you want your brain to attack building object you will need building ID from the editor:

if ((getenemycount(-1) == 0)) then
         if isalive(73402) then                               //73402 is building ID from the editor
            magicAttack(73402);                     
         endif;
      else
         corerun = True;
         getObjectPosition(-1, startPosition);
         magicGuard(startposition, -1);
      endif;

If you want to attack mover object (mech or vehicle) then:
(INIT section - get unit ID from squad ID from the editor - using already declared scortSquadID and moverList variables)
escortSquadID = X;  //X is squad ID from the editor

getUnitMates(escortSquadID, moverList);

Then the code is:
if ((getenemycount(-1) == 0)) then
         if isalive(moverList[0]) then                               
            magicAttack(moverList[0]);                     
         endif;
      else
         corerun = True;
         getObjectPosition(-1, startPosition);
         magicGuard(startposition, -1);
      endif;

Orders1 = 2)
You must set MovePoint in INIT from the coordinates of the point you want your unit to move from the editor.

if (distancetoposition(-1, MovePoint) > 150)
         corerun = True;
         coreMoveTo(MovePoint, TACORDER_PARAM_RUN);
      else
         corerun = True;
         getObjectPosition(-1, startPosition);
         magicGuard(startposition, -1);
      endif;

Orders1 = 3)
INIT section

You must set the number of patrol points you want and X, Y coordinates for every patrol point (from the editor).
Example below is for 5 patrol points.
   
      PState[1] = 5;       //This is the Amount of Move Points there are listed below. Make sure you Count Patrol Point '0'
      PState[2] = -1;    //This is How many Times the unit will perform the Patrol.. (-1 = Forever).

//               Patrol Points below
      PPath[0, 0] = -3178;   //X coordinate found in the editor
      PPath[0, 1] = -6208;   //Y coordinate found in the editor
      PPath[1, 0] = -4842;
      PPath[1, 1] = -3520;
      PPath[2, 0] = -5184;
      PPath[2, 1] = -704;
      PPath[3, 0] = -4416;
      PPath[3, 1] = 1898;
      PPath[4, 0] = -3050;
      PPath[4, 1] = 2666;

Orders1 = 4)
Simple attack brain, you just need to set Orders1 to 4.

Orders1 = 5)
Simple sentry brain around 300 radius around startposition.

      coreRun = True;
      coreSentry(startposition, 300, -1);

You can set different coordinates for startposition.

Orders1 = 6)
You must set escortSquadID in init section:

escortSquadID = X;  //X is squad ID from the editor

That is ALL if you want to use it as simple (one order) brain.

If you want to use it as complex brain you must declare Order1 in main mission.abl as eternal boolean variable.
There could be more then one definition of similar Orders variables in main mission ABL (Orders1, Orders2,..., OrdersX)
If you use exactly the same name (Orders1) you must comment out declaration and init of Orders1 in brain file.
Or simply use Order1, Order2,..., OrderX variables to avoid any possible conflict (no "s").

This way you can change orders for that unit by changing Orders1 variable here

switch (Orders1)

to OrderX.

How can you control OrderX variable from main mission.ABL file?

1) you must set OrderX to 0 or 1 or 2 or 3 or 4 or 5 or 6. Depends on what you want your unit to do first in INIT section of main mission.ABL file.

2) When some condition is met (objective completed, point reached, some unit dead, ...) you can change OrderX to another number and change the brain from e.g. guard (0) to escort (6). You MUST define every parameter for every role in brain file, in this case escortSquadID.

3) another condition is met (escorted unit has reached its destination)  and you want your unit to guard again simply set OrderX to 0 again or maybe patrol (3 - you must have all parameter for patrol defined in brain file).

OR you can simply use multiple brain files using my new command:

setbrain(PartID, brainName);

PartID - number from the editor for buildings, part id for mover (obtained with getunitmates(squadID)) from squad ID.
brainName - the name of the brain file without extension.

DECLARATION section

      static integer      Commando;
      static integer[2]   moverList;

INIT section

getUnitMates(5, moverList);
Commando = moverList[0];


CODE section

if (LopCCC) then
if (checkObjectiveStatus(3) == 1) then //Objective3 completed
   addmovertoplayer(Commando, 0, 2); //remove commando from player roster and add to allied team
   setbrain(Commando, "p_guard");  //brain file name is p_guard.abl
   LopCCC = False;
endif;
endif;

If you want your unit to be powered down at start you will have use this
//Activate this if unit is powered down
      if (not poweredDown) then
         corePower(false);
         poweredDown = true;
      endif;

//If you want your unit to power-up when hit by weapon fire you must activate the following loop
      if ((been_hit) AND (beenhit)) then //beenhit is a system variable that is set to True when hit by weapon fire
         corePower(True);
         been_hit = False; //close this loop forever unit is active
         All_powerup = True; //global variable defined in main mission.ABL used for global power-up other from beenhit - here used to send power-up signal for all mates
         All_power = False; //close the following loop forever unit is active
      endif;
      
//if you have defined global activation trigger (All_powerup) in main mission.ABL file activate this loop otherwise comment out All_powerup = True; in previous loop
      if ((All_power) AND (All_powerup)) then //this loop is used if you recive power-up signal from mates or global power-up (All_powerup=True)
         corePower(True);
         All_power = False; //close this loop forever unit is active
         been_hit = False; //close the previous loop forever unit is active
      endif;


I know this is complicated but it is much better then using weird way of GOTO states from original MC2.

Good luck.
« Last Edit: July 31, 2013, 04:08:40 am by magic »

 

Offline magic

  • Moderator
  • 211
Re: Universal warrior brain for MCO
UniversalBrain.ABL from MCO 304 is not good. I forgot to copy correct file to release.

Will upload soon.

 
Re: Universal warrior brain for MCO
I don't want to be stepping on any toes/ conflicting with Magic's awesome code.. but... I copied/created my own Universal Warrior Brain to use and edit for specific units within my missions. I changed a few things from Magic's brain above, for better or worse I don't know. Magic has a better grasp of this code then I do, but I've also tried to heavily comment my file for ease of understanding for everyone else;
Code: [Select]
//----------------------------------------------------------------------------------------
// Universal Warrior Brain for Mech Commander Omnitech
// By Magic
// Edited by RustyDios 24 / 02 / 15
//----------------------------------------------------------------------------------------
// Every style of brain for the same mission must have a UNIQUE module name
// the fsm name is usually shared by the filename
// Several units can still share a brain file, they will all do the same thing the brain tells them to
//----------------------------------------------------------------------------------------

fsm RD_UWB; // make this unique per file, EACH BRAIN MUST HAVE AN UNIQUE FSM ID.., usually brain_file_name.

//----------------------------------------------------------------------------------------
// Declare variable definitions
//----------------------------------------------------------------------------------------
var

//-------------------------------------------------------------------------------
// Define this here for control inside this brain
// Comment out here and declare as an eternal integer in mission.abl
//   for control of this unit from there, you could also change the two mentions of this
//   in the file to something else, like OrderFlea and control only the units with the OrderFlea
//   variable in them.
//-------------------------------------------------------------------------------

static integer OrderType; // Define what order this unit should be following

//-------------------------------------------------------------------------------
// Don't Edit these
//-------------------------------------------------------------------------------

static integer MyID; // Defines the vehicleID for this unit
static worldposition MyLoc; // Defines position of this unit
static integer MyScanRange; // Defines a Scan Range for this Unit
static boolean PoweredUp; // Defines if the unit is powered down/up
static boolean SetPoweredDown; // Defines if the unit should be powered down

static PatrolState PState; // Defines a Patrol State
static PatrolPath PPath; // Defines a point on a patrol path

static worldposition MoveToPoint; // Defines a position to move towards

static integer BuildingID ; // Defines a buildingID from the editor

static integer[12] UnitList; // Defines an array to hold VehicleID's
// At most the unit is going to have 12 mates as per commander & group in the mission.fit ??
// This can be a [2] at minimum but I chose 12 as a default

static integer EscortID; // Defines a unit to escort by SquadID
static boolean IsEscortDead; // Defines a boolean if escortee is dead
static real EscortRange; // Defines a range to stay to the escortee
static worldposition EscortLoc; // Defines where the escortee is

static boolean Capturable; // Defines if this unit can be captured

static integer Unit1; // defines a unit under this MHQ command by editor SquadID
static integer Unit2; // defines a unit under this MHQ command by editor SquadID
static integer Unit3; // defines a unit under this MHQ command by editor SquadID
static integer Unit4; // defines a unit under this MHQ command by editor SquadID

static boolean WillRequestHelp; // Defines if this unit will ask for help
static real LastRequestTime; // Defines the time since last help request
static real HelpRequestFreq; // Defines how often to ask for help

static integer AttackStateHandle;

//----------------------------------------------------------------------------------------
// Initialise these are set up just once
//----------------------------------------------------------------------------------------
function Init;
code

//-------------------------------------------------------------------------------
// Set up the unit basics
//-------------------------------------------------------------------------------

MyScanRange = 500; // Defines a Scan Range for this Unit
// Roughly 100 for infantry or powered armour, 150 for elementals, 300 for vehicles and 500 for mechs

// Flip the states of these two to power down the unit
PoweredUp = TRUE; // Units usually start by default as powered up
SetPoweredDown = FALSE; // Sets the unit to power down

Capturable = FALSE; // Sets this unit to be capturable (for orders 8 and 9)

MyID = GetID; // Gets the ID of this unit and stores it as MyID
GetObjectPosition(MyID,MyLoc); // Gets the location of the unit and stores it as his location

//-------------------------------------------------------------------------------
// Set up the Order type
//-------------------------------------------------------------------------------

OrderType = 0; // Define what order this unit should be following, default is guard start location
//0 - Guard (StartLocation) //4 - Move to Attack Building then Guard
//1 - Nothing, null brain code //5 - Escort a unit
//2 - Patrol set route //6 - Stands Sentry for ScanRange
//3 - Move to Position then Guard //7 - DredAttack, attack anything that is in range (no different from guard really)

//8 - Capturable non-weapon unit, ie Repair Truck, Mine Layer -- NOT WORKING --
// use rd_uwb_fsu instead .... not sure why it doesn't work here...it puts the unit to the ally commander !!
// _fsu has almost the exact the same code
//9 - Capturable HQ unit with weapon units under command -- NOT WORKING --
// Same code (almost- must first find the VehID of the MHQ unit)...
// ...Works in a main mission.abl, just not here !?!#FFS#!?!

//-------------------------------------------------------------------------------
// Set up the Patrol Route(s)
//-------------------------------------------------------------------------------

PState[0] = 1;    // This is the Type of Patrol. 0 = Linear. 1 = Looping
//(Linear = Unit will move from 0 to 1 to 2 to 3, then 3 to 2 to 1 to 0) Assuming there are  4 points to the Patrol
//(Looping = Unit will move from 0 to 1 to 2 to 3 back to 0 and begin again) Assuming there are 4 points to the Patrol
PState[1] = 4;    //This is the Amount of Move Points there are listed below. Make sure you count Patrol Point '0'
PState[2] = -1;    //This is How many Times the unit will perform the Patrol.. (-1 = Forever).

// This is patrol direction, ie from point 0 to 1 to 2 to 3
PState[3] = PATROL_DIRECTION_FORWARD;   
PState[4] = -1;    //Reset Current Patrol Point
PState[5] = -1;    //Reset Current Patrol Cycle
PState[6] = CONTACT_CRITERIA_ENEMY + CONTACT_CRITERIA_VISUAL_OR_SENSOR + CONTACT_CRITERIA_NOT_DISABLED;

PPath[0, 0] = 1; //X coordinate found in the editor
PPath[0, 1] = 1; //Y coordinate found in the editor
PPath[1, 0] = 2;
PPath[1, 1] = 2;
PPath[2, 0] = 3;
PPath[2, 1] = 3;
PPath[3, 0] = 4;
PPath[3, 1] = 4;

// Further patrol routes can be set up by copying this section but calling it PStateX and PPathX, for example
// Remember to declare them in the variable section too..
// Uncomment the switchable patrol state code in Case 2 below

//-------------------------------------------------------------------------------
// Set up the Move To Point (then guard at)
//-------------------------------------------------------------------------------

MoveToPoint[0] = 1.0; // x co-ord from the editor
MoveToPoint[1] = 1.0; // y co-ord from the editor
MoveToPoint[2] = 0.0; // z co-ord / altitude, will be set by terrain elevation

//-------------------------------------------------------------------------------
// Set up Building to Attack
//-------------------------------------------------------------------------------

BuildingID = 69042; // BuildingID from the editor to attack, likely defaults to a tree

//-------------------------------------------------------------------------------
// Set up the Escort Details
//-------------------------------------------------------------------------------

EscortID = 1; // SquadID of the escortee,
// no clue as to who the default is but ...
// ... unless this is an escort brain it shouldn't matter

IsEscortDead = FALSE; // Defines a boolean if escortee is dead
EscortRange = 200.0; // Defines a range to stay to the escortee in meters
GetUnitMates(EscortID,UnitList); // Converts the squadID into a vehicle ID
EscortID = UnitList[0]; // Sets the VehicleID to this name
GetObjectPosition(EscortID,EscortLoc); // Gets the position of the Escortee

//-------------------------------------------------------------------------------
// Set up if the unit can be Captured
//-------------------------------------------------------------------------------

if (Capturable == TRUE) then
SetCapturable(MyID,TRUE); // Sets the unit to be capturable
// No need to close this loop here as it is within the init function, so only gets run once :)
// This also means we can reuse the boolean variable in the main code as a loop check
endif;

//-------------------------------------------------------------------------------
// Set up the units under this ones command
//-------------------------------------------------------------------------------

Unit1 = 1; // The editor SquadID for a unit under command from this HQ
Unit2 = 1; // The editor SquadID for a unit under command from this HQ
Unit3 = 1; // The editor SquadID for a unit under command from this HQ
Unit4 = 1; // The editor SquadID for a unit under command from this HQ

GetUnitMates(Unit1,UnitList); // Converts the squadID into a vehicle ID
Unit1 = UnitList[0]; // Assigns the VehID to this name
GetUnitMates(Unit2,UnitList); // Converts the squadID into a vehicle ID
Unit2 = UnitList[0]; // Assigns the VehID to this name
GetUnitMates(Unit3,UnitList); // Converts the squadID into a vehicle ID
Unit3 = UnitList[0]; // Assigns the VehID to this name
GetUnitMates(Unit4,UnitList); // Converts the squadID into a vehicle ID
Unit4 = UnitList[0]; // Assigns the VehID to this name

//-------------------------------------------------------------------------------
// Set up "Everything else"
//-------------------------------------------------------------------------------

CoreRun = TRUE; // Sets the unit to Run instead of walk

SetWillHelp(True); // Defines if this unit will move to help mates
WillRequestHelp = TRUE; // Defines if this unit will ask for help
LastRequestTime = -100; // States the last time the unit asked for help was -100 seconds ago (before the mission)
HelpRequestFreq = 20; // The unit will ask for help every 20 odd seconds

SetTargetPriority(0, TARGET_PRIORITY_CURTARGET, -1, 150,
CONTACT_CRITERIA_ENEMY + CONTACT_CRITERIA_VISUAL_OR_SENSOR + CONTACT_CRITERIA_NOT_DISABLED);
SetTargetPriority(1, TARGET_PRIORITY_MOVER, 0, MyScanRange,
CONTACT_CRITERIA_ENEMY + CONTACT_CRITERIA_VISUAL_OR_SENSOR + CONTACT_CRITERIA_NOT_DISABLED);
SetTargetPriority(2, TARGET_PRIORITY_NONE, 0, 0, 0);

AttackStateHandle = GetStateHandle("Attack");

endfunction;

//----------------------------------------------------------------------------------------
// Update This is continuous
//----------------------------------------------------------------------------------------
function update: integer;
var
boolean ProcessingPilotEvents;
integer PilotEventID;
integer PilotState;
integer[20] PilotEventParams;
integer CurrentTarget;
real CurrentTime;
real[3] AttackerLoc;
integer CurrentStateHandle;
static integer NumberFunctionalWeapons;
static integer[20] WeaponList;

code

CurrentTime = GetTime; // Gets the current time
CurrentStateHandle = GetCurrentStateHandle; // Gets the current state handle
GetObjectPosition(MyID,MyLoc); // Gets the location of the unit and stores it as his location
ProcessingPilotEvents = TRUE; // Sets the fact that we're doing "stuff"

NumberFunctionalWeapons = GetWeapons(WeaponList, 1); // Store all the still functioning weapons


//-------------------------------------------------------------------------------
// Check we still have weapons, if no head to no weapons state
//-------------------------------------------------------------------------------
if (NumberFunctionalWeapons == 0) then // If we have no weapons ..
trans NoWeapons; // .. go to the non-weapon state
endif;

//-------------------------------------------------------------------------------
// Check to see if the escortee is dead, if yes enter guard mode at current location
//-------------------------------------------------------------------------------
if (((ObjectStatus(EscortID) == 1) OR (ObjectStatus(EscortID) == 2)) AND (IsEscortDead == FALSE)) then
MagicGuard(MyLoc,-1); // Guard my current Location (within a -1 range or me?)
IsEscortDead = True;
else
GetObjectPosition(EscortID, EscortLoc);
SetMoveArea(EscortLoc, EscortRange);
MagicEscort(EscortID);
endif;

//-------------------------------------------------------------------------------
// Check to see what we're doing now...
//-------------------------------------------------------------------------------
while (ProcessingPilotEvents) do
PilotEventID = GetNextPilotEvent(PilotEventParams); // Set up the event

// If Pilot event is doing nothing, stop doing stuff this round
if (pilotEventID == PILOT_EVENT_NONE) then
ProcessingPilotEvents = FALSE;
else
// If Pilot event is doing something, lets make changes dependant on event type
switch (PilotEventID)

// Pilot has been targeted for attack
case PILOT_EVENT_TARGETED:
CurrentTarget = GetTarget(MyID); // Sets our current target

// If we have not asked for help recently, ask for it
if (LastRequestTime < (CurrentTime - HelpRequestFreq)) then
LastRequestTime = CurrentTime;
if (WillRequestHelp) then
GetObjectPosition(CurrentTarget, AttackerLoc); // PilotEventParams[0] is our attackers ID
GetObjectPosition(MyID, MyLoc); // Update our location
// Request Help against my target from anyone 300m near me or it
RequestHelp(CurrentTarget, MyLoc, 300.0, AttackerLoc, 300.0, 1);
endif;
endif;
// If we're not attacking, set that as our next event state, providing we have weapons and a target still
if (CurrentStateHandle <> AttackStateHandle) then
if ((NumberFunctionalWeapons > 0) and (CurrentTarget <> 0)) then
CoreRun = True;
MagicAttack(CurrentTarget);
SetState(AttackStateHandle);
endif;
endif;
endcase;

// Pilot has an order to attack
case PILOT_EVENT_ATTACK_ORDER:
CurrentTarget = GetTarget(MyID);

// If we're not attacking, set that as our next event state, providing we have weapons and a target still
if (CurrentStateHandle <> AttackStateHandle) then
if ((NumberFunctionalWeapons > 0) and (CurrentTarget <> 0)) then
CoreRun = True;
MagicAttack(CurrentTarget);
SetState(AttackStateHandle);
endif;
endif;
endcase;

// Pilot has fired a weapon, do nothing - keep firing
case PILOT_EVENT_FIRED_WEAPON:
endcase;

// If we've been hit but were powered down, power up and start attacking
case PILOT_EVENT_HIT:
if ((BeenHit == TRUE) AND (PoweredUp == FALSE)) then
CorePower(True);
PoweredUp = TRUE;
SetPoweredDown = FALSE;
endif;

CurrentTarget = GetTarget(MyID);

// If we're not attacking, set that as our next event state, providing we have weapons and a target still
if (CurrentStateHandle <> AttackStateHandle) then
if ((NumberFunctionalWeapons > 0) and (CurrentTarget <> 0)) then
CoreRun = True;
MagicAttack(CurrentTarget);
SetState(AttackStateHandle);
endif;
endif;
endcase;
endswitch;
endif;
endwhile;

return(0);
endfunction;
//----------------------------------------------------------------------------------------
// No Weapons State What do we do if we have no weapons?
//----------------------------------------------------------------------------------------
state NoWeapons;
code
if (ObjectClass(MyID) == 2) then // if we're a mech
CoreEject;
else // we're NOT a mech
CorePower(FALSE);
endif;
endstate;
//----------------------------------------------------------------------------------------
// Attack State What do we do if we're attacking ?
//----------------------------------------------------------------------------------------
state Attack;
code
update; // Run the update function do decide what to do next
CoreRun = True; // Run instead of walking
MagicAttack(0); // Attack our CurrentTarget
ResetOrders(1); // Reset the brain
TransBack; // Go back to doing what we was before
endstate;
//----------------------------------------------------------------------------------------
// Start State What do we do first ?
//----------------------------------------------------------------------------------------
state Start;
code
if (SetPoweredDown == TRUE) then // if we're suppose to be shutdown, shut us down
CorePower(FALSE);
SetPoweredDown = FALSE;
PoweredUp = FALSE;
endif;

// if we have been hit and are powered down ... then power us up
if ((BeenHit == TRUE) AND (PoweredUp == FALSE))then
CorePower(TRUE);
SetPoweredDown = FALSE;
PoweredUp = TRUE;
endif;

switch (OrderType)

// Guard my location
case 0:
CoreRun = True; // Ensure we're still running and not walking
MagicGuard(MyLoc,-1); // Guard my location (to a range of -1 or Guard Me ??)
endcase;

//1 - Nothing, null brain code
case 1:
SetEngageRadius(0); // Don't engage anything
IdentifySensorContactsOFF; // Don't call out sensor contacts
MoveToEngageOFF; // Don't move to fight
StopFighting; // Don't fight
ReturnFireOFF; // Don't return fire
CorePower(FALSE); // Might as well switch off too
endcase;

//2 - Patrol set route
case 2:
//if (SomeCondition == TRUE) then // Change to the new route when the condition is met
// CoreRun = TRUE; // Ensure we're still running and not walking
// MagicPatrol(PStateX,PPathX); // Patrol a pre-set route

//else // this is our first/default patrol route
CoreRun = True; // Ensure we're still running and not walking
MagicPatrol(PState, PPath); // Patrol a pre-set route
//endif;
endcase;

//3 - Move to Position then Guard
case 3:
// If we're more then 200m away from our MoveToPoint start moving towards it
if (DistanceToPosition(MyID, MoveToPoint) > 200) then
CoreRun = True; // Ensure we're still running and not walking
CoreMoveTo(MoveToPoint, TACORDER_PARAM_RUN);
// If we're there, start guarding it
else
CoreRun = True; // Ensure we're still running and not walking
GetObjectPosition(MyID,MyLoc); // Update our location
MagicGuard(MyLoc, -1); // Guard our Location
endif;
endcase;

//4 - Move to Attack Building then Guard
case 4:
if ((GetEnemyCount(MyID) == 0)) then // If we have no enemies..
if (IsAlive(BuildingID)) then // .. and the building is not dead...
MagicAttack(BuildingID); // .. attack it
CoreRun = True; // Ensure we're still running and not walking
endif;
else
CoreRun = True; // Ensure we're still running and not walking
GetObjectPosition(MyID,MyLoc); // Update our location
MagicGuard(MyLoc, -1); // Guard our Location
endif;
endcase;

//5 - Escort a unit
case 5:
if (IsEscortDead == FALSE) then // if the escortee is not dead...
GetObjectPosition(EscortID, EscortLoc); // Get the location of the escortee
CoreRun = True; // Ensure we're still running and not walking
SetMoveArea(EscortLoc, EscortRange); // Set us to move around the escortee at range
MagicEscort(EscortID); // Escort the escortee
else
CoreRun = True; // Ensure we're still running and not walking
GetObjectPosition(MyID,MyLoc); // Update our location
MagicGuard(MyLoc, -1); // Guard our Location
endif;
endcase;

//6 - Stands Sentry for ScanRange
case 6:
CoreRun = True; // Ensure we're still running and not walking
GetObjectPosition(MyID,MyLoc);   // Update our location
CoreSentry(MyLoc,MyScanRange, -1); // Sentry / Guard our Location
endcase;

//7 - DredAttack, attack anything that is an enemy
case 7:
CoreRun = True; // Ensure we're still running and not walking
GetObjectPosition(MyID,MyLoc); // Update our location
MagicGuard(MyLoc, -1); // Guard our Location
endcase;

//8 - Capturable non-weapon unit, ie Repair Truck, Mine Layer
case 8:
CoreRun = True; // Ensure we're still running and not walking
GetObjectPosition(MyID,MyLoc); // Update our location
MagicGuard(MyLoc, -1); // Guard our Location

if (Capturable == TRUE) then
// check alignment of unit, 500 = Player_Force, (501 = Clan_Force, 502 = Allied_Force)
if (ObjectSide(MyID) == 500) then
// Displays the message entered below
SetTextMsg(1,
" MechWarrior Report -
   Commander, a new unit and its crew have agreed
   to work for us until our mission is complete -
   or they are dead.",1);
Capturable = FALSE; // Close the loop
//ObjectChangeSides(MyID, 0); // Change sides, not needed, handled by the below
AddMoverToPlayer(MyID, 0, 0); // Add the unit to the player team, player command
SetBrain(MyID, "pbrain"); // Change the unit brain to control by player
endif;
endif;
endcase;

//9 - Capturable HQ unit with weapon units under command
case 9:
CoreRun = True; // Ensure we're still running and not walking
GetObjectPosition(MyID,MyLoc); // Update our location
MagicGuard(MyLoc, -1); // Guard our Location

if (Capturable == TRUE) then
// check alignment of unit, 500 = Player_Force, (501 = Clan_Force, 502 = Allied_Force)
if (ObjectSide(MyID) == 500) then
// Displays the message entered below
SetTextMsg(1,
" MechWarrior Report -
   Commander, the unit's under this Mobile HQ will now obey your orders
    until our mission is complete -
    or they are dead.",1);
Capturable = FALSE; // Close the loop
AddMoverToPlayer(MyID, 0, 2); // Add this unit to the player team, ally commander

// Change sides for the units under the MHQ's command
//ObjectChangeSides(Unit1, 0); // Change sides, not needed, handled by the below
//ObjectChangeSides(Unit2, 0); // Change sides, not needed, handled by the below
//ObjectChangeSides(Unit3, 0); // Change sides, not needed, handled by the below
//ObjectChangeSides(Unit4, 0); // Change sides, not needed, handled by the below

AddMoverToPlayer(Unit1, 0, 0); // set this unit to the player team, player commander
AddMoverToPlayer(Unit2, 0, 0); // set this unit to the player team, player commander
AddMoverToPlayer(Unit3, 0, 0); // set this unit to the player team, player commander
AddMoverToPlayer(Unit4, 0, 0); // set this unit to the player team, player commander

SetBrain(Unit1, "pbrain"); // make the unit repond to player commands
SetBrain(Unit2, "pbrain"); // make the unit repond to player commands
SetBrain(Unit3, "pbrain"); // make the unit repond to player commands
SetBrain(Unit4, "pbrain"); // make the unit repond to player commands
endif;
else
CoreRun = True; // Ensure we're still running and not walking
GetObjectPosition(MyID,MyLoc); // Update our location
MagicGuard(MyLoc, -1); // Guard our Location
endif;
endcase;

endswitch;

update; // Run the update function
ResetOrders(1); // Reset the brain to run again (minus init function?)
endstate;
//----------------------------------------------------------------------------------------
// Finish
//----------------------------------------------------------------------------------------

endfsm.

Maybe someone might find it useful... at the very minimum I'll have a copy here should I loose mine :) :)
« Last Edit: March 13, 2015, 02:53:43 am by magic »

 

Offline magic

  • Moderator
  • 211
Re: Universal warrior brain for MCO
Useable brain, thank you RustyDios.

Change "fsm" at the top to "module XXX : integer;"

I guess you tried this and it works?

 
Re: Universal warrior brain for MCO
No. I haven't tried that out with this particular file. I do however have another warriorbrain called rd_uwb_fsu which was a slight variation of the null_order brain that I can use to capture non-weaponised vehicles. The code here was pulled directly from the _fsu file and there are only two major differences.
1) In this code the unit is set to guard as a default action - the original was a null brain code
2) This code is written as a fsm, the other one that works is as a module.

Considering the code is also apparently stable for a mission.abl (another module based code, not fsm) I'm guessing that some of those functions for that specific part only work in a module environment and not in a fsm environment... although I have no idea what the difference is. . . fsm is new to me and something I'd not encountered before looking at MCO examples.

I'm taking a guess and part of me remembers reading something about the "change" to fsm format for warriors, I can't find the reference at the moment, but I think it means FreeStandingModule.

EDIT :: I've just tried making those adjustments to turn the file from fsm to module. It does NOT work. The game crashes out with a syntax error. First for an unexpected token (line 540 and a bit - return). I commented it out to see what would happen. Then for an unexpected token again (line 540 and a bit - endmodule). So I commented that out too. Next it wants to complain that there is missing code for "endstate;". So I put "endfsm." back in and with "endfsm." in at the bottom it crashes with no report (but still roughly halfway through loading, ie at the brains part), likely because module >> endfsm isn't compatible.

I don't really get how Order 8 (free support unit) works in a different file  http://www.hard-light.net/forums/index.php?topic=89176.0 see edit3 here... and Order 9 (free weapon units after hq capture) works within the main mission.abl... ... with very little difference between the code (mainly layout/module - fsm)... ...

I've changed the above post to remove the notes on changing the "filetype" for orders 8 and 9. It would be nice to get them working as intended. I've left in the warning that they don't work - maybe someone else can fix them with my examples as a base to work from?
The brain still works providing that OrderType is never changed to 8 or 9... ...
... ... at least the rest of the brain works as intended :)
« Last Edit: February 24, 2015, 06:23:32 pm by RustyDios »