Spawn Friendly AI Scripts – Mission: Friend or Foe

COOP Mission

This mission pits our players against a garrisoned force of CSAT that are supported by a guerilla force of FIA. The problem for our players is that our side also has FIA support and we need to be able to identify Friend Or Foe!

I’m sharing two scripts here. The first one will monitor the number of Friendly Fire (FF) kills and if the limit is exceeded, the mission will end in failure. The second script handles all the dynamic spawning of friendly guerilla units to make it random every time.

Get this mission on the Steam Workshop by clicking HERE.
//monitorFF.sqf
//This script is by Unkl for PracticallyRealGaming.com - feel free to adapt it to your purpose but please give credit
//script requires a game logic object placed on the map named "server" which is used to store friendly fire counts
//TO MONITOR IF FRIENDLY AI UNITS ARE KILLED
//ALL INDEDEPENDENT UNITS ARE AI AND FRIENDLY
//USAGE: []execVM "monitorFF.sqf";  //ADD TO INITSERVER.SQF - assuming you name this script "monitorFF.sqf"

_friendlySide = independent;
_maxKillsAcceptable = 2;

//COUNT OF FRIENDLY UNITS KILLED
server setVariable ["ffKilled", 0, true];

//INIT ALL CURRENT FRIENDLY AI UNITS
_friendlyUnits = [];
{
	if (side _x == independent) then {
		_friendlyUnits pushback _x;
	};
}forEach allUnits;
{_x setVariable ["hasHandler", false, true];}forEach _friendlyUnits;

//*************START OF EXECUTION LOOP**************************************************************************
[_maxKillsAcceptable,_friendlySide]spawn {
	_run = true;
	_max = _this select 0;
	_friendlySide = _this select 1;
	while {_run} do {
		if (server getVariable "ffKilled" > _max) then {
			"Unacceptable friendly casualties. This mission is scrubbed!" remoteExec ["hint", 0, false];
			sleep 10;
			"end2" call BIS_fnc_endMissionServer; //END THE MISSION IN FAILURE
			_run = false; //STOP LOOP
		};
		
		//GET A LIST OF THE FRIENDLY UNITS (ALL _friendlySide UNITS)
		_friendlyUnits = [];
		{
			if (side _x == _friendlySide) then {
				_friendlyUnits pushback _x;
			};
		}forEach allUnits;
		
		//INCREMENT SCORE IF ANY OF THE FRIENDLY SIDE ARE KILLED BY A PLAYER
		//THIS ALLOWS FOR ZEUS TO ADD UNITS AND WILL ADD FF EVENT HANDLER TO THOSE NEW UNITS
		{
			if (!(_x getVariable "hasHandler")) then {
				_x addMPEventHandler ["MPKilled", {
					params ["_unit", "_killer", "_instigator", "_useEffects"];
					if (isPlayer _killer) then {
						_currentScore = server getVariable "ffKilled";
						_currentScore = _currentScore + 1;
						server setVariable ["ffKilled", _currentScore, true];
						_mssg = format ["%1 has killed a friendly unit. This mission will be scrubbed if you can not identify Friend Or Foe!", name _killer];
						_mssg remoteExec ["Hint", 0, false];
						_mssg = format ["Your team has already killed %1 friendly units!", _currentScore];
						_mssg remoteExec ["systemChat", 0, false];
					};
				}];
				_x setVariable ["hasHandler", true, true];
			};
		}forEach _friendlyUnits;
		
		//DELAY LOOP EXECUTION FOR IMPROVED PERFORMANCE
		sleep 30;
	}; //END OF WHILE DO LOOP
}; //END OF SPAWN
//spawnFriendlyFIA.sqf
//This script is by Unkl for PracticallyRealGaming.com - feel free to adapt it to your purpose but please give credit
//script requires a game logic object placed on the map named "server" which is used to store friendly fire counts
//USAGE: []execVM "spawnFriendlyFIA.sqf";  //ADD TO INITSERVER.SQF - assuming you name this script "spawnFriendlyFIA.sqf"

//*****THIS FUNCTION IS SPAWNED IN THE CODE AT THE BOTTOM************************************************************************
unk_spawngroup = {
  //ARRAY OF SPAWNPOINTS PUT ON MAP - USE GAME LOGIC OBJECT
  _selectedSpawn = selectRandom [spawnpoint, spawnpoint_1, spawnpoint_2, spawnpoint_3, spawnpoint_4, spawnpoint_5, spawnpoint_6, spawnpoint_7, spawnpoint_8, spawnpoint_9, spawnpoint_10, spawnpoint_11, spawnpoint_12, spawnpoint_13, spawnpoint_14, spawnpoint_15, spawnpoint_16, spawnpoint_17, spawnpoint_18, spawnpoint_19, spawnpoint_20, spawnpoint_21, spawnpoint_22];
  //ARRAY OF POINTS TO MOVE UNITS TO FOR RANDOM ATTACK/PATROLS - USE GAME LOGIC OBJECTS
  _selectedAttack = getPos (selectRandom [attackpoint, attackpoint_1, attackpoint_2, attackpoint_3, attackpoint_4, attackpoint_5, attackpoint_6, attackpoint_7, attackpoint_8, attackpoint_9, attackpoint_10, attackpoint_11, attackpoint_12, attackpoint_13, attackpoint_14, attackpoint_15, attackpoint_16, attackpoint_17, attackpoint_18, attackpoint_19]);
  
  //ARRAY OF CLASSNAMES SUITABLE FOR LEADERS
  _leaderUnitType = selectRandom ["I_G_Soldier_TL_F","I_G_officer_F","I_G_Soldier_SL_F"];
  //ARRAY OF CLASSNAMES SUITABLE FOR SUBORDINATE UNITS
  _subordinateUnitTypes = ["I_G_Soldier_AR_F","I_G_Soldier_GL_F","I_G_Soldier_LAT2_F","I_G_Soldier_M_F","I_G_Soldier_F","I_G_Soldier_F","I_G_medic_F"];
  
  //CREATE A NEW GROUP
  newGroup = createGroup [independent, true];
  //SPAWN IN NEW LEADER
  newLeader = _leaderUnitType createUnit [_selectedSpawn, newGroup, "newLeader = this"];
  sleep .5; //SHORT DELAY TO ENSURE UNIT IS SPAWNED BEFORE EXECUTING COMMANDS ON IT
  //SELECT A RANDOM NUMBER OF UNITS TO SPAWN AS SUBORDINATES
  _numberInGroup = floor random (count _subordinateUnitTypes);
  //LOOP THROUGH AND SPAWN IN THE SUBORDINATES
  for [{ _loop = 1 },{ _loop < _numberInGroup},{ _loop = _loop + 1}] do
  {
    _newUnit = (_subordinateUnitTypes select _loop) createUnit [_selectedSpawn,newGroup, "newUnit = this"];
  };
  
  //SET PATROL LOCATION FOR NEW GROUP
  sleep 1;  //short pause to ensure units are spawned before assigning waypoints
  //REMOVE ANY EXISTING WAYPOINTS
  while {count waypoints newgroup > 0} do {
	deleteWaypoint [newGroup, 0];
  };
  //ADD NEW WAYPOINT
  newgroup addWaypoint [_selectedAttack, 50, 0, "Move"];
  [newgroup, 0] setWaypointSpeed "NORMAL";
  [newgroup, 0] setWaypointBehaviour "SAFE";
  newgroup setcurrentwaypoint [newgroup, 0];
  
  //ADD SCRIPT TO MONITOR IF THEY REACH THEIR DESTINATION TO THEN MAKE THEM PATROL
  [newgroup, _selectedAttack] spawn {
	_group = _this select 0;
	_dest = _this select 1;
	_run = true;
	_group deleteGroupWhenEmpty true;
	while {_run} do {
		//CHECK IF REACHED DESTINATION AND IF SO SET TO PATROL
		_destinationReached = false;
		{
			if (_x distance _dest < 50) then {
				_destinationReached = true;
			};
		}forEach units _group;
		if (_destinationReached) then {
			[_group, _dest, 100] call bis_fnc_taskPatrol;
			_run = false; //STOP LOOP
			//systemChat "spawned group to start patrol";  //DEBUG MESSAGE
		};
		
		//check if group has been eliminated and if so stop script
		if (count units _group < 1) then {
			_run = false;  //STOP LOOP
			//systemchat "spawned group killed - script stopped"; //DEBUG MESSAGE
		};
		
		//DELAY LOOP EXECUTION FOR IMPROVED PERFORMANCE
		sleep 5;
	};
  };
  
  //SHORT PAUSE BEFORE ADDING EVENT HANDLERS
  sleep 1;
  
  //ADD FRIENDLY FIRE EVENT HANDLER TO EACH OF THE NEW UNITS
  {
	_x addMPEventHandler ["MPKilled", {
		params ["_unit", "_killer", "_instigator", "_useEffects"];
		if (isPlayer _killer) then {
			_currentScore = server getVariable "ffKilled";
			_currentScore = _currentScore + 1;
			server setVariable ["ffKilled", _currentScore, true];
			_mssg = format ["%1 has killed a friendly unit. This mission will be scrubbed if you can not identify Friend Or Foe!", name _killer];
			_mssg remoteExec ["Hint", 0, false];
			_mssg = format ["Your team has already killed %1 friendly units!", _currentScore];
			_mssg remoteExec ["systemChat", 0, false];
		};
	}];
	_x setVariable ["hasHandler", true, true];
  }forEach units newGroup;
  
 //systemChat "group spawned...";  //DEBUG MESSAGE
  
  //IF NEW SPAWNED GROUP DOES NOT MOVE THEN REMOVE IT
  (units newGroup select 0) spawn {
	_unit = _this;
	_thisGroup = group _unit;
	_startSpot = getPos _unit;
	sleep 30;
	if ((getPos _unit) distance _startSpot < 4) then {
		while {count (units _thisGroup) > 0} do {
			deleteVehicle (units _thisGroup select 0);
		};
		deleteGroup _thisGroup;
		
		//systemChat "Idle group deleted";  //DEBUG MESSAGE
	};
  };
  
};
//***********END OF FUNCTION******************************************************************************************************


//*******BEGINNING OF EXECUTION **************************************************************************************************
//DELAY FIRST RANDOM SPAWN FOR 5 MINUTES
sleep 300;
_mandatorySpawnDelay = 120; //SET THIS TO SLOW DOWN THE FRIENDLY FIA SPAWNING
_run = true;
while {_run} do {
  _friendlyFIA = [];
  {
	if (side _x == independent) then {
		_friendlyFIA pushback _x;
	};
  }forEach allUnits;
  if (count _friendlyFIA < 10) then {
	sleep (floor random 60 + _mandatorySpawnDelay);
	[]spawn unk_spawngroup;  //EXECUTE THE FUNTION DEFINED ABOVE
  };
  sleep 10;
};

Note: I’ve made some changes while preparing for this post so I will be doing a QA later. You can get to this mission file from the Steam Workshop. A link is below.

Happy mission making!

Unkl out.

GET THE MISSION HERE FROM THE STEAM WORKSHOP