BIS_fnc_taskPatrol is horribly inconsistent - it creates each new waypoint from the previous waypoint's position, so your patrol could end up either zigzagging back and forth or ending up 100 metres further out than you expected it to. taskPatrol's "distance" variable isn't a distance from the groups initial position, it's an arbitrary value.
That's where my patrol function fixes things. I wanted a consistent patrol function, that makes AI actually patrol around an area.
I'll admit this probably isn't the most user-friendly script, but it shouldn't take too long to figure out - everything is commented as best as I could. At some point I'll probably make this into one large function that handles everything neatly.
I have made this into 2 neat functions that handle both giving patrols and spawning units.
Obviously credit to BIS, as this is based on taskPatrol.
What does it do?
The first function generates 2-3 waypoints around a group's current position, within a set distance, and then gives the group a cycle waypoint so they follow the patrol route. It also generates an around each waypoint that is blacklisted, and cannot be used again for any call of the function in the mission (so it won't generate 2 waypoints touching each other).
The second function will spawn a group of units and give them a patrol. It can also be used to spawn a group of units and tell them to hold at their spawn position.
taskPatrol
What are the parameters for the function?
[grp,pos,distance] call cc_fnc_taskPatrol;
Where grp is the group to be given a patrol; pos is the position from which the units will patrol;distance is the distance they will patrol within.
How do I use it?
1. Create a new file in your mission folder called taskPatrol.sqf. In this file, paste the following:
Code: Select all
// Patrol function by Ciaran (vaguely based on BIS_fnc_taskPatrol)
params ["_grp","_pos","_maxDist"];
if (isNil "blacklistA") then {blacklistA = [];}; //if blacklist area isn't defined, define it so we can pushback blacklisted areas into it
[_grp,"SAFE","WEDGE","RED","LIMITED"] call ws_fnc_setAIMode; //set AI behaviour
if (_maxDist < 30) exitWith {private "_wp"; _wp = _grp addWaypoint [_pos, 0]; _wp setWaypointType "HOLD";} ; //no patrol for units with dist below 30, given hold waypoint instead
//create 2-3 waypoints
for "_i" from 0 to (1 + (floor (random 2))) do
{
private ["_wp", "_newPos"];
_newPos = [_pos,25,_maxDist,0.1,0,0,0,blacklistA,[_pos,_pos]] call BIS_fnc_findSafePos; //creates waypoints within maxDist of the group's starting pos
// create an area around this waypoint that cannot be used again
_blacklistP1 = _newPos getPos [25,315]; //top left point
_blacklistP2 = _newPos getPos [25,135]; //bottom right point
// DEBUG: Creates markers at these 2 points
//_mkr1 = createMarker [format ["%1 -1",_blacklistP1],_blacklistP1];_mkr1 setMarkerSize [0.5,0.5];_mkr1 setMarkerType "mil_dot";_mkr1 setMarkerColor "ColorEAST";
//_mkr2 = createMarker [format ["%1 -2",_blacklistP2],_blacklistP2];_mkr2 setMarkerSize [0.5,0.5];_mkr2 setMarkerType "mil_dot";_mkr2 setMarkerColor "ColorEAST";
blacklistA pushback [_blacklistP1,_blacklistP2]; //pushback this area into the blacklist array
//create move waypoint at the new position
_wp = _grp addWaypoint [_newPos, 0];
_wp setWaypointType "MOVE";
_wp setWaypointCompletionRadius 3;
// DEBUG: Marker placed at each wp, with maxDist displayed
//_mkr = createMarker [format ["%1-bpos",_newPos],_newPos];_mkr setMarkerSize [0.5,0.5];_mkr setMarkerType "mil_dot";_mkr setMarkerColor "ColorGreen";_mkr setMarkerText format ["%1", _maxDist];
};
//cycle back to the group's original position
private ["_wp"];
_wp = (_this select 0) addWaypoint [_pos, 0];
_wp setWaypointType "CYCLE";
_wp setWaypointCompletionRadius 3;
Code: Select all
cc_fnc_taskPatrol = compile preprocessfile "taskPatrol.sqf";
spawnPatrol
What are the parameters for the function?
Mandatory; Optional.
[pos,distance,side,size,units] call cc_fnc_spawnPatrol;
Where pos is the position to spawn units at; distance is the distance they should patrol around; side is the side of the spawned units; size is the number of units to spawn.
Units can be either an array of units, from which the function will randomly select the number you defined with size, or if size is set to 0, units can be an array of arrays, for if you would like a specific group/groups of units to spawns. The function will randomly select one of the arrays within the units array.
If units is left undefined, the function will create a random group of units from the arrays in spawnPatrol.sqf.
How do I use it?
1. Create a new file called spawnPatrol.sqf, and paste the following code into it
Code: Select all
// spawn the patrol
params ["_pos","_dist","_side","_size","_units"];
if (count _this < 5) then {
// NATO
_grpWest = ["B_Soldier_lite_F","B_Soldier_F"];
// CSAT
_grpEast = ["O_Soldier_lite_F","O_Soldier_F"];
// AAF
_grpResistance = ["I_Soldier_lite_F","I_Soldier_F"];
// Syndikat Paramilitary
// ["I_C_Soldier_Para_1_F","I_C_Soldier_Para_2_F","I_C_Soldier_Para_7_F"];
// Syndikat Bandit
// ["I_C_Soldier_Bandit_4_F","I_C_Soldier_Bandit_7_F","I_C_Soldier_Bandit_5_F"];
// FIA
// ["B_G_Soldier_lite_F","B_G_Soldier_F"];
_units = switch (_side) do {
case west: {_grpWest};
case east: {_grpEast};
case resistance: {_grpResistance};
};
};
_spawnUnits = [];
if (_size == 0) then {
_comp = _units; //if size is 0 then the data given should be an array of arrays of units, one of which is chosen when spawning the group
_grp = [_pos,_side,(selectRandom _comp)] call BIS_fnc_spawnGroup; //spawn the group
[_grp,_pos,_dist] call cc_fnc_taskPatrol; //give them the patrol
_spawnUnits append units _grp; //collect units so we can return them, for use with assignGear etc
};
if (_size > 0) then {
_comp = [];
for "_i" from 1 to (_size) do { //randomly select units from the array until we reach the specified size
_comp append [(selectRandom _units)];
};
_grp = [_pos,_side,_comp] call BIS_fnc_spawnGroup;
[_grp,_pos,_dist] call cc_fnc_taskPatrol;
_spawnUnits append units _grp;
};
//return spawned units
_spawnUnits
Code: Select all
cc_fnc_spawnPatrol = compile preprocessfile "spawnPatrol.sqf";
1. In the editor, place down a playable headless client entity, found under Systems -> Logic Entities. Name it hc.
2. Place down Game Logics where you want a group to spawn and patrol around. Name these patrolSpawn, patrolSpawn_1,...,patrolSpawn_n (copy and paste will name them like this). In the init of the Game Logic, paste the following
Code: Select all
this setvariable ["cc_patrolDist",100]
3. Create a file called patrol.sqf, and paste the following into it
Code: Select all
if ((isNil "hc" && !isServer) || (!isNil "hc" && (isServer || hasInterface))) exitWith {}; //headless client
_spawns = [patrolSpawn] call ws_fnc_collectObjectsNum;
_comp = [
["I_C_Soldier_Para_7_F","I_C_Soldier_Para_7_F","I_C_Soldier_Para_7_F"],
["I_C_Soldier_Para_5_F","I_C_Soldier_Para_1_F","I_C_Soldier_Para_1_F"],
["I_C_Soldier_Para_5_F","I_C_Soldier_Para_4_F","I_C_Soldier_Para_1_F"],
["I_C_Soldier_Para_1_F","I_C_Soldier_Para_4_F"],
["I_C_Soldier_Para_1_F","I_C_Soldier_Para_5_F"]
];
_units = [];
{
_units append ([getpos _x,_x getvariable ["cc_patrolDist",100],resistance,0,_comp] call cc_fnc_spawnPatrol);
} forEach _spawns;
[_units,"f\assignGear\f_assignGear_AI.sqf"] remoteExec ["BIS_fnc_execVM",2]; //remoteExec because assignGear/setSkill only run server side
[_units,"f\setAISkill\f_setAISkill.sqf"] remoteExec ["BIS_fnc_execVM",2];
The final 2 lines will run assignGear and setSkill on the units.
4. Add the following line to your mission's init.sqf, after the lines for the function scripts.
Code: Select all
[] execVM "patrol.sqf"
In the current version of ws_fnc in the FA3 template, ws_fnc_setAIMode will have a tantrum if you give it more than three entries (as this function does). There is no reason for this, it will happily accept four entries. To fix this, delete line 37 in ws_fnc/AI/fn_setAIMode.sqf
Feel free to post any feedback below.