From 25dcc950d4cf7e82c3d6f8a9740f93f779fc2179 Mon Sep 17 00:00:00 2001 From: SilentSpike Date: Thu, 19 May 2016 16:28:41 +0100 Subject: [PATCH 01/10] Add an AI function to correctly clear all waypoints Unfortunately clearing all waypoints from AI is not as simple as deleting them all with `deleteWaypoint`. You have to kill their pre-planned movement (based on old waypoints) by having them complete at least one waypoint. One solution is to move all of their old waypoints to their position before deleting them, however if waypoint statements are being used this could have adverse effects. So this function creates a fresh waypoint for the purpose of killing their movement. It is also self-deleting (through its completion statement) to avoid any possible issues with timing. --- addons/ai/CfgFunctions.hpp | 6 ++++++ addons/ai/fnc_clearWaypoints.sqf | 34 ++++++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+) create mode 100644 addons/ai/fnc_clearWaypoints.sqf diff --git a/addons/ai/CfgFunctions.hpp b/addons/ai/CfgFunctions.hpp index 715586fdf..33caeabb6 100644 --- a/addons/ai/CfgFunctions.hpp +++ b/addons/ai/CfgFunctions.hpp @@ -15,6 +15,12 @@ class CfgFunctions description = "A function used to add a waypoint to a group. Parameters: - Group (Group or Object) - Position (XYZ, Object, Location or Group) Optional: - Radius (Scalar) - Waypoint Type (String) - Behaviour (String) - Combat Mode (String) - Speed Mode (String) - Formation (String) - Code To Execute at Each Waypoint (String) - TimeOut at each Waypoint (Array [Min, Med, Max]) - Waypoint Completion Radius (Scalar) Example: [this, this, 300, ""MOVE"", ""AWARE"", ""YELLOW"", ""FULL"", ""STAG COLUMN"", ""this spawn CBA_fnc_searchNearby"", [3,6,9]] Returns: Waypoint Author: Rommel"; file = "\x\cba\addons\ai\fnc_addWaypoint.sqf"; }; + // CBA_fnc_clearWaypoints + class clearWaypoints + { + description = "A function used to correctly clear all waypoints from a group."; + file = "\x\cba\addons\ai\fnc_clearWaypoints.sqf"; + }; // CBA_fnc_searchNearby class searchNearby { diff --git a/addons/ai/fnc_clearWaypoints.sqf b/addons/ai/fnc_clearWaypoints.sqf new file mode 100644 index 000000000..cb4d896f6 --- /dev/null +++ b/addons/ai/fnc_clearWaypoints.sqf @@ -0,0 +1,34 @@ +/* ---------------------------------------------------------------------------- +Function: CBA_fnc_clearWaypoints + +Description: + A function used to correctly clear all waypoints from a group. + +Parameters: + - Group (Group or Object) + +Example: + (begin example) + [group player] call CBA_fnc_clearWaypoints + (end) + +Returns: + None + +Author: + SilentSpike + +---------------------------------------------------------------------------- */ +#include "script_component.hpp" +params [["_group", grpNull, [grpNull,objNull]]]; +_group = _group call CBA_fnc_getGroup; + +private _waypoints = waypoints _group; +{ + // Waypoint index changes with each deletion, so don't delete _x + deleteWaypoint [_group,0]; +} forEach _waypoints; + +// Create a self-deleting waypoint at the leader position to halt all planned movement (based on old waypoints) +private _wp = _group addWaypoint [getPosATL (leader _group), 0]; +_wp setWaypointStatements ["true", "deleteWaypoint [group this,0]"]; From 678bb644026d64bb72d5f3759654d8cb2cad94f6 Mon Sep 17 00:00:00 2001 From: SilentSpike Date: Thu, 19 May 2016 16:12:01 +0100 Subject: [PATCH 02/10] Update taskDefend AI function - Retain open building positions to make groups defending overlapping areas respect one another. - Use new A3 scripting commands to optimise and enhance the function. - Makes the function a lot more readable with comments and more spacing. - Capitalize commands and function names appropriately. - Any existing waypoints are cleared before defending begins. --- addons/ai/fnc_taskDefend.sqf | 110 ++++++++++++++++++----------------- 1 file changed, 58 insertions(+), 52 deletions(-) diff --git a/addons/ai/fnc_taskDefend.sqf b/addons/ai/fnc_taskDefend.sqf index c16bf7a36..910871900 100644 --- a/addons/ai/fnc_taskDefend.sqf +++ b/addons/ai/fnc_taskDefend.sqf @@ -25,11 +25,11 @@ Returns: Nil Author: - Rommel + Rommel, SilentSpike ---------------------------------------------------------------------------- */ -params ["_group", ["_position",[]], ["_radius",50], ["_threshold",2]]; +params ["_group", ["_position",[]], ["_radius",50,[0]], ["_threshold",2,[0]], ["_patrol",true,[true]]]; _group = _group call CBA_fnc_getGroup; if !(local _group) exitWith {}; // Don't create waypoints on each machine @@ -37,66 +37,72 @@ if !(local _group) exitWith {}; // Don't create waypoints on each machine _position = [_position,_group] select (_position isEqualTo []); _position = _position call CBA_fnc_getPos; -_group enableattack false; +[_group] call CBA_fnc_clearWaypoints; +_group enableAttack false; -private ["_count", "_list", "_list2", "_units", "_i"]; -_statics = [_position, vehicles, _radius, {(_x iskindof "StaticWeapon") && {(_x emptypositions "Gunner" > 0)}}] call CBA_fnc_getnearest; -_buildings = _position nearObjects ["building",_radius]; -_units = units _group; -_count = count _units; +private _statics = _position nearObjects ["StaticWeapon", _radius]; +private _buildings = _position nearObjects ["Building", _radius]; +// Filter out occupied statics +_statics = _statics select { (_x emptyPositions "Gunner") > 0 }; + +// Filter out buildings below the size threshold (and store positions for later use) +_buildings = _buildings select { + private _positions = _x buildingPos -1; + + if (isNil {_x getVariable "CBA_taskDefend_positions"}) then { + _x setVariable ["CBA_taskDefend_positions",_positions]; + }; + + count (_positions) > _threshold +}; + +private _units = units _group; +private _assigned = 0; { - if (str(_x buildingpos _threshold) == "[0,0,0]") then {_buildings = _buildings - [_x]}; -} foreach _buildings; -_i = 0; -{ - _count = (count _statics) - 1; - if (random 1 < 0.31 && {_count > -1}) then { - _x assignasgunner (_statics select _count); - _statics resize _count; - [_x] ordergetin true; - _i = _i + 1; + // 31% chance to occupy nearest free static weapon + if ((random 1 < 0.31) && { !(_statics isEqualto []) }) then { + _x assignAsGunner (_statics deleteAt 0); + [_x] orderGetIn true; + + _assigned = _assigned + 1; } else { - if (random 1 < 0.93 && {count _buildings > 0}) then { - private ["_building","_p","_array"]; - _building = _buildings call BIS_fnc_selectRandom; - _array = _building getvariable "CBA_taskDefend_positions"; - if (isnil "_array") then { - private "_k"; _k = 0; - _building setvariable ["CBA_taskDefend_positions",[]]; - while {str(_building buildingpos _k) != "[0,0,0]"} do { - _building setvariable ["CBA_taskDefend_positions",(_building getvariable "CBA_taskDefend_positions") + [_k]]; - _k = _k + 1; - }; - _array = _building getvariable "CBA_taskDefend_positions"; - }; - if (count _array > 0) then { - _p = (_building getvariable "CBA_taskDefend_positions") call BIS_fnc_selectRandom; - _array = _array - [_p]; - if (count _array == 0) then { + // 93% chance to occupy a random nearby building position + if ((random 1 < 0.93) && { !(_buildings isEqualto []) }) then { + private _building = selectRandom _buildings; + private _array = _building getVariable ["CBA_taskDefend_positions",[]]; + + if !(_array isEqualTo []) then { + private _pos = _array deleteAt (floor(random(count _array))); + + // If building positions are all taken remove from possible buildings + if (_array isEqualTo []) then { _buildings = _buildings - [_building]; - _building setvariable ["CBA_taskDefend_positions",nil]; + _building setVariable ["CBA_taskDefend_positions",nil]; }; - _building setvariable ["CBA_taskDefend_positions",_array]; - [_x,_building buildingpos _p] spawn { - if (surfaceIsWater (_this select 1)) exitwith {}; - (_this select 0) domove (_this select 1); + _building setVariable ["CBA_taskDefend_positions",_array]; + + // AI manipulation trickey to keep them in position until commanded to move + [_x, _pos] spawn { + params ["_unit","_pos"]; + if (surfaceIsWater _pos) exitwith {}; + + _unit doMove _pos; sleep 5; - waituntil {unitready (_this select 0)}; - (_this select 0) disableai "move"; - dostop _this; - waituntil {not (unitready (_this select 0))}; - (_this select 0) enableai "move"; + waituntil {unitReady _unit}; + _unit disableAI "move"; + doStop _unit; + waituntil {!(unitReady _unit)}; + _unit enableAI "move"; }; - _i = _i + 1; + + _assigned = _assigned + 1; }; }; }; -} foreach _units; -{ - _x setvariable ["CBA_taskDefend_positions",nil]; -} foreach _buildings; -if (count _this > 4 && {!(_this select 4)}) then {_i = _count}; -if (_i < _count * 0.5) then { +} forEach _units; + +// If half of the group's units aren't assigned then patrol +if (_patrol && {_assigned < (count _units) * 0.5}) then { [_group, _position, _radius, 5, "sad", "safe", "red", "limited"] call CBA_fnc_taskpatrol; }; From 752e1865a5ffc5bf6fd56271844afa6e244ec61c Mon Sep 17 00:00:00 2001 From: SilentSpike Date: Thu, 19 May 2016 16:44:36 +0100 Subject: [PATCH 03/10] Update taskPatrol AI function - The `cycle` waypoint is placed back at the start of the loop instead of randomly within the radius. - Any existing waypoints are cleared before the patrol loop is created. - `_this` is now correctly private. --- addons/ai/fnc_taskPatrol.sqf | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/addons/ai/fnc_taskPatrol.sqf b/addons/ai/fnc_taskPatrol.sqf index c00f6b47f..25dc90eda 100644 --- a/addons/ai/fnc_taskPatrol.sqf +++ b/addons/ai/fnc_taskPatrol.sqf @@ -43,15 +43,23 @@ if !(local _group) exitWith {}; // Don't create waypoints on each machine _position = [_position,_group] select (_position isEqualTo []); _position = _position call CBA_fnc_getPos; -_this =+ _this; +// Clear existing waypoints first +[_group] call CBA_fnc_clearWaypoints; + +private _this =+ _this; if (count _this > 3) then { _this deleteAt 3; }; -for "_x" from 1 to _count do { + +// Store first WP to close loop later +private _wp = _this call CBA_fnc_addWaypoint; + +for "_x" from 1 to (_count - 1) do { _this call CBA_fnc_addWaypoint; }; -_this2 =+ _this; -_this2 set [3, "CYCLE"]; -_this2 call CBA_fnc_addWaypoint; -deleteWaypoint ((waypoints _group) select 0); +// Close the patrol loop +_this set [1, getWPPos _wp]; +_this set [2, 0]; +_this set [3, "CYCLE"]; +_this call CBA_fnc_addWaypoint; From b4f62777ec3c672465c7f5cbeb01e01e47ba9abf Mon Sep 17 00:00:00 2001 From: SilentSpike Date: Thu, 19 May 2016 17:10:57 +0100 Subject: [PATCH 04/10] Update taskSearchArea AI function - Any existing waypoints are now cleared before the searching begins. - The recursive argument check is now more explicit. --- addons/ai/fnc_taskSearchArea.sqf | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/addons/ai/fnc_taskSearchArea.sqf b/addons/ai/fnc_taskSearchArea.sqf index c9e39a3da..ccf700a6d 100644 --- a/addons/ai/fnc_taskSearchArea.sqf +++ b/addons/ai/fnc_taskSearchArea.sqf @@ -9,6 +9,8 @@ Description: Parameters: _group - The group that will search [Group or Object] _area - The area to search [Marker or Trigger] + +Optional: _behaviour - Waypoint behaviour [String, defaults to "UNCHANGED"] _combat - Waypoint combat mode [String, defaults to "NO CHANGE"] _speed - Waypoint speed [String, defaults to "UNCHANGED"] @@ -38,30 +40,34 @@ params [ ["_onComplete", "", [""]], ["_timeout", [0,0,0], [[]], 3] ]; -private ["_pos","_args","_statement","_building"]; _group = _group call CBA_fnc_getGroup; if !(local _group) exitWith {}; // Don't create waypoints on each machine -// Cache arguments as group variable for recursive calls -_args = [_area,_behaviour,_combat,_speed,_formation,_onComplete,_timeout]; -if (_area isEqualTo "") then { +// Collect arguments for use in recursive calls (not using `select` to include default values) +private _args = [_area,_behaviour,_combat,_speed,_formation,_onComplete,_timeout]; + +// Retrieve cached arguments in case of recursive call +if (isNil {param [1]}) then { _args = _group getVariable [QGVAR(taskSearch),_args]; +} else { + // Clear existing waypoints and cache arguments upon first call + [_group] call CBA_fnc_clearWaypoints; + _group setVariable [QGVAR(taskSearch),_args]; }; -_group setVariable [QGVAR(taskSearch),_args]; _args params ["_area","_behaviour","_combat","_speed","_formation","_onComplete","_timeout"]; // Select a random position in the area -_pos = [_area] call CBA_fnc_randPosArea; +private _pos = [_area] call CBA_fnc_randPosArea; // Exit if any bad input was used (has to run after all the above code) if ((_pos isEqualTo []) || {_area isEqualTo ""} || {isNull _group}) exitWith {}; // Prepare recursive function call statement -_statement = "[this] call CBA_fnc_taskSearchArea;"; +private _statement = "[this] call CBA_fnc_taskSearchArea;"; // Prepare building search statement -_building = nearestBuilding _pos; +private _building = nearestBuilding _pos; if ((_building distanceSqr _pos) < 400) then { _statement = _statement + "[this] spawn CBA_fnc_searchNearby;"; }; @@ -83,6 +89,3 @@ _onComplete = _statement + _onComplete; _timeout, 5 ] call CBA_fnc_addWaypoint; - -// Remove starting/previous waypoint -deleteWaypoint [_group,0]; From fd36422f850220b5869f317b350d7e6d4f975253 Mon Sep 17 00:00:00 2001 From: SilentSpike Date: Thu, 19 May 2016 18:31:36 +0100 Subject: [PATCH 05/10] Update searchNearby AI function - Now callable (by including the spawn within the function). - Accounts for units being killed while searching and dispatches all available units to search simultaneously. - Doesn't permanently change behaviour of the group if the function aborts due to building distance. - Optimized with new A3 commands and made more readable with comments and spacing. --- addons/ai/fnc_searchNearby.sqf | 77 +++++++++++++++++--------------- addons/ai/fnc_taskPatrol.sqf | 2 +- addons/ai/fnc_taskSearchArea.sqf | 2 +- 3 files changed, 43 insertions(+), 38 deletions(-) diff --git a/addons/ai/fnc_searchNearby.sqf b/addons/ai/fnc_searchNearby.sqf index f9e921368..94f0eab07 100644 --- a/addons/ai/fnc_searchNearby.sqf +++ b/addons/ai/fnc_searchNearby.sqf @@ -9,51 +9,56 @@ Parameters: Example: (begin example) - [group player] spawn CBA_fnc_searchNearby + [group player] call CBA_fnc_searchNearby (end) Returns: Nil Author: - Rommel + Rommel, SilentSpike ---------------------------------------------------------------------------- */ params ["_group"]; -_group = _group call CBA_fnc_getgroup; -_group lockwp true; -private ["_leader","_behaviour"]; -_leader = leader _group; -_behaviour = behaviour _leader; -_group setbehaviour "combat"; - -(_leader call CBA_fnc_getnearestbuilding) params ["_building", "_indices"]; -_group setformdir ([_leader, _building] call bis_fnc_dirto); - -if (_leader distance _building > 500) exitwith {_group lockwp false}; - -private ["_count","_units"]; -_units = units _group; -_count = (count _units) - 1; - -while {_indices > 0 && {_count > 0}} do { - sleep 10; - while {_indices > 0 && {_count > 0}} do { - private "_unit"; - _unit = _units select _count; - if (unitready _unit) then { - _unit commandmove (_building buildingpos _indices); - _indices = _indices - 1; - }; - _count = _count - 1; +_group = _group call CBA_fnc_getGroup; +_group lockWP true; + +private _building = nearestBuilding (leader _group); +if ((leader _group) distanceSqr _building > 250e3) exitwith {_group lockWP false}; + +[_group,_building] spawn { + params ["_group","_building"]; + private _behaviour = behaviour (leader _group); + + // Prepare group to search + _group setBehaviour "Combat"; + _group setFormDir ((leader _group) getDir _building); + + // Search while there are still available positions + private _positions = _building buildingPos -1; + while {!(_positions isEqualTo [])} do { + // Abort search if the group has no units left + if ((units _group) isEqualTo []) exitWith {}; + + // Send all available units to the next available position + { + if (_positions isEqualTo []) exitWith {}; + if (unitReady _x) then { + private _pos = _positions deleteAt 0; + _x commandMove _pos; + }; + } forEach (units _group); + + // Provide time for orders to be carried out + sleep 10; }; - _units = units _group; - _count = (count _units) - 1; + + // Once units are all finished searching return to previous tasks + waitUntil {sleep 3; {unitReady _x} count (units _group) >= count (units _group) - 1}; + { + _x doFollow (leader _group); + } forEach (units _group); + _group setBehaviour _behaviour; + _group lockWP false; }; -waituntil {sleep 3; {unitready _x} count _units >= count (units _group) - 1}; -{ - _x dofollow _leader; -} foreach _units; -_group setbehaviour _behaviour; -_group lockwp false; diff --git a/addons/ai/fnc_taskPatrol.sqf b/addons/ai/fnc_taskPatrol.sqf index 25dc90eda..40cfd05c7 100644 --- a/addons/ai/fnc_taskPatrol.sqf +++ b/addons/ai/fnc_taskPatrol.sqf @@ -22,7 +22,7 @@ Optional: Example: (begin example) [this, getmarkerpos "objective1"] call CBA_fnc_taskPatrol - [this, this, 300, 7, "MOVE", "AWARE", "YELLOW", "FULL", "STAG COLUMN", "this spawn CBA_fnc_searchNearby", [3,6,9]] call CBA_fnc_taskPatrol; + [this, this, 300, 7, "MOVE", "AWARE", "YELLOW", "FULL", "STAG COLUMN", "this call CBA_fnc_searchNearby", [3,6,9]] call CBA_fnc_taskPatrol; (end) Returns: diff --git a/addons/ai/fnc_taskSearchArea.sqf b/addons/ai/fnc_taskSearchArea.sqf index ccf700a6d..3d9de23dc 100644 --- a/addons/ai/fnc_taskSearchArea.sqf +++ b/addons/ai/fnc_taskSearchArea.sqf @@ -69,7 +69,7 @@ private _statement = "[this] call CBA_fnc_taskSearchArea;"; // Prepare building search statement private _building = nearestBuilding _pos; if ((_building distanceSqr _pos) < 400) then { - _statement = _statement + "[this] spawn CBA_fnc_searchNearby;"; + _statement = _statement + "[this] call CBA_fnc_searchNearby;"; }; // Inject the statement in this order to ensure valid syntax From 9c823f3fe891ee5a21b6863302b6abe1e856eaff Mon Sep 17 00:00:00 2001 From: SilentSpike Date: Sat, 21 May 2016 11:40:53 +0100 Subject: [PATCH 06/10] Fix v1.54 compatiblity of fnc_taskDefend Commented out the part that isn't easily regex replaced so that it can be uncommented in future. --- addons/ai/fnc_taskDefend.sqf | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/addons/ai/fnc_taskDefend.sqf b/addons/ai/fnc_taskDefend.sqf index 910871900..31dc860ea 100644 --- a/addons/ai/fnc_taskDefend.sqf +++ b/addons/ai/fnc_taskDefend.sqf @@ -44,10 +44,24 @@ private _statics = _position nearObjects ["StaticWeapon", _radius]; private _buildings = _position nearObjects ["Building", _radius]; // Filter out occupied statics -_statics = _statics select { (_x emptyPositions "Gunner") > 0 }; +[_statics,{(_x emptyPositions "Gunner") > 0},true] call CBA_fnc_filter; // Filter out buildings below the size threshold (and store positions for later use) -_buildings = _buildings select { +{ + if ((_x buildingPos _threshold) isEqualto [0,0,0]) then { + _buildings set [_forEachIndex,nil]; + } else { + private _positions = _x buildingPos -1; + + if (isNil {_x getVariable "CBA_taskDefend_positions"}) then { + _x setVariable ["CBA_taskDefend_positions",_positions]; + }; + }; +} forEach _buildings; +_buildings = _buildings arrayIntersect _buildings; + +// v1.56 version of the above +/*_buildings = _buildings select { private _positions = _x buildingPos -1; if (isNil {_x getVariable "CBA_taskDefend_positions"}) then { @@ -55,7 +69,7 @@ _buildings = _buildings select { }; count (_positions) > _threshold -}; +};*/ private _units = units _group; private _assigned = 0; @@ -69,7 +83,7 @@ private _assigned = 0; } else { // 93% chance to occupy a random nearby building position if ((random 1 < 0.93) && { !(_buildings isEqualto []) }) then { - private _building = selectRandom _buildings; + private _building = _buildings call BIS_fnc_selectRandom; private _array = _building getVariable ["CBA_taskDefend_positions",[]]; if !(_array isEqualTo []) then { From f27cdf3789f468d0a9e416ecc4c2c85b03f34f07 Mon Sep 17 00:00:00 2001 From: SilentSpike Date: Sat, 21 May 2016 12:14:32 +0100 Subject: [PATCH 07/10] Restore fnc_searchNearby leader behaviour In actuality this is something of a compromise. Having the leader enter the building was not an intentional change I made. However it makes sense to do things that way when the group is small and so for any group with 2 or less units (includes the leader) the leader will now search the building too. --- addons/ai/fnc_searchNearby.sqf | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/addons/ai/fnc_searchNearby.sqf b/addons/ai/fnc_searchNearby.sqf index 94f0eab07..ff1ffba6f 100644 --- a/addons/ai/fnc_searchNearby.sqf +++ b/addons/ai/fnc_searchNearby.sqf @@ -5,7 +5,7 @@ Description: A function for a group to search a nearby building. Parameters: - Group (Group or Object) + - Group (Group or Object) Example: (begin example) @@ -29,17 +29,26 @@ if ((leader _group) distanceSqr _building > 250e3) exitwith {_group lockWP false [_group,_building] spawn { params ["_group","_building"]; - private _behaviour = behaviour (leader _group); + private _leader = leader _group; + private _behaviour = behaviour _leader; // Prepare group to search _group setBehaviour "Combat"; - _group setFormDir ((leader _group) getDir _building); + _group setFormDir ([_leader, _building] call BIS_fnc_dirTo); + + // Leader will only wait outside if group larger than 2 + if (count (units _group) <= 2) then { + _leader = objNull; + }; // Search while there are still available positions private _positions = _building buildingPos -1; while {!(_positions isEqualTo [])} do { + // Update units in case of death + private _units = (units _group) - [_leader]; + // Abort search if the group has no units left - if ((units _group) isEqualTo []) exitWith {}; + if (_units isEqualTo []) exitWith {}; // Send all available units to the next available position { @@ -48,7 +57,7 @@ if ((leader _group) distanceSqr _building > 250e3) exitwith {_group lockWP false private _pos = _positions deleteAt 0; _x commandMove _pos; }; - } forEach (units _group); + } forEach _units; // Provide time for orders to be carried out sleep 10; @@ -57,7 +66,7 @@ if ((leader _group) distanceSqr _building > 250e3) exitwith {_group lockWP false // Once units are all finished searching return to previous tasks waitUntil {sleep 3; {unitReady _x} count (units _group) >= count (units _group) - 1}; { - _x doFollow (leader _group); + _x doFollow (leader _group); // Not using _leader in case of death } forEach (units _group); _group setBehaviour _behaviour; _group lockWP false; From d876997f6f8cafe81563f5dc101b589529183824 Mon Sep 17 00:00:00 2001 From: SilentSpike Date: Sat, 21 May 2016 14:44:40 +0100 Subject: [PATCH 08/10] Fix building search completion condition Accounts for cases where the leader enters the building. --- addons/ai/fnc_searchNearby.sqf | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/addons/ai/fnc_searchNearby.sqf b/addons/ai/fnc_searchNearby.sqf index ff1ffba6f..bc567a3fb 100644 --- a/addons/ai/fnc_searchNearby.sqf +++ b/addons/ai/fnc_searchNearby.sqf @@ -64,7 +64,11 @@ if ((leader _group) distanceSqr _building > 250e3) exitwith {_group lockWP false }; // Once units are all finished searching return to previous tasks - waitUntil {sleep 3; {unitReady _x} count (units _group) >= count (units _group) - 1}; + waitUntil { + sleep 3; + private _units = (units _group) - [_leader]; + ({unitReady _x} count _units) >= count _units + }; { _x doFollow (leader _group); // Not using _leader in case of death } forEach (units _group); From 5f531b556ae5d7b9ee6a8b2985750c47503c6071 Mon Sep 17 00:00:00 2001 From: SilentSpike Date: Sat, 21 May 2016 16:14:40 +0100 Subject: [PATCH 09/10] Improve behaviour of fnc_searchNearby - The group leader (and any spare units) will now wait at his current position for the search to be complete before moving on. - Waiting between orders instead of between rounds of orders should prevent congestion and decrease time gaps in the search. - Embedding the post-search code into the waypoint condition and completion removes the need to `waitUntil` while also providing built in group unit list `thisList`. --- addons/ai/fnc_searchNearby.sqf | 25 +++++++++---------------- 1 file changed, 9 insertions(+), 16 deletions(-) diff --git a/addons/ai/fnc_searchNearby.sqf b/addons/ai/fnc_searchNearby.sqf index bc567a3fb..df38e2bad 100644 --- a/addons/ai/fnc_searchNearby.sqf +++ b/addons/ai/fnc_searchNearby.sqf @@ -22,15 +22,20 @@ Author: params ["_group"]; _group = _group call CBA_fnc_getGroup; -_group lockWP true; private _building = nearestBuilding (leader _group); -if ((leader _group) distanceSqr _building > 250e3) exitwith {_group lockWP false}; +if ((leader _group) distanceSqr _building > 250e3) exitwith {}; [_group,_building] spawn { params ["_group","_building"]; private _leader = leader _group; - private _behaviour = behaviour _leader; + + // Add a waypoint to regroup after the search + _group lockWP true; + private _wp = _group addWaypoint [getPos _leader, 0, currentWaypoint _group]; + private _cond = "({unitReady _x || !(alive _x)} count thisList) == count thisList"; + private _comp = format ["this setFormation %1; this setBehaviour %2; deleteWaypoint [group this, currentWaypoint (group this)];",formation _group,behaviour _leader]; + _wp setWaypointStatements [_cond,_comp]; // Prepare group to search _group setBehaviour "Combat"; @@ -56,22 +61,10 @@ if ((leader _group) distanceSqr _building > 250e3) exitwith {_group lockWP false if (unitReady _x) then { private _pos = _positions deleteAt 0; _x commandMove _pos; + sleep 2; }; } forEach _units; - - // Provide time for orders to be carried out - sleep 10; }; - // Once units are all finished searching return to previous tasks - waitUntil { - sleep 3; - private _units = (units _group) - [_leader]; - ({unitReady _x} count _units) >= count _units - }; - { - _x doFollow (leader _group); // Not using _leader in case of death - } forEach (units _group); - _group setBehaviour _behaviour; _group lockWP false; }; From 3d7f5183a1a9116b46790d5e6dad70729ba72ad4 Mon Sep 17 00:00:00 2001 From: SilentSpike Date: Sat, 21 May 2016 17:03:15 +0100 Subject: [PATCH 10/10] Fix edge case in fnc_clearWaypoints If a waypoint was created at index 0 before the group complete the waypoint used to reset their path, then the wrong waypoint would be deleted upon its completion. --- addons/ai/fnc_clearWaypoints.sqf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/ai/fnc_clearWaypoints.sqf b/addons/ai/fnc_clearWaypoints.sqf index cb4d896f6..378ffcd75 100644 --- a/addons/ai/fnc_clearWaypoints.sqf +++ b/addons/ai/fnc_clearWaypoints.sqf @@ -31,4 +31,4 @@ private _waypoints = waypoints _group; // Create a self-deleting waypoint at the leader position to halt all planned movement (based on old waypoints) private _wp = _group addWaypoint [getPosATL (leader _group), 0]; -_wp setWaypointStatements ["true", "deleteWaypoint [group this,0]"]; +_wp setWaypointStatements ["true", "deleteWaypoint [group this,currentWaypoint (group this)]"];