#include "script_component.hpp" /* * Author: alganthe * Internal function used by ace_ai_fnc_garrison to make the units move to the positions it picked. * * Arguments: * 0: Array of arrays * 0: Unit needing to be placed * 1: Position the unit need to be placed at * * Return Value: * Nothing * * Example: * [ [unit1, [10, 10, 10]], [unit2, [30, 30, 30]], [unitN, getPos player] ] call ace_ai_fnc_garrisonMove * * Public: No */ params [ ["_unitMoveList", nil, [[]]] ]; if (isNil "_unitMoveList") exitWith {}; // Start initial movement private _unitMoveListUnits = (_unitMoveList apply {_x select 0}); [QGVAR(setBehaviour), [(_unitMoveListUnits select {leader _x == _x}), "AWARE"], _unitMoveListUnits] call CBA_fnc_targetEvent; [QGVAR(AISection), [_unitMoveListUnits, ["FSM"], false], _unitMoveListUnits] call CBA_fnc_targetEvent; [QGVAR(doMove), [_unitMoveList], _unitMoveListUnits] call CBA_fnc_targetEvent; [QGVAR(enableAttack), [_unitMoveListUnits select {leader _x == _x}, false], _unitMoveListUnits] call CBA_fnc_targetEvent; { _x setVariable [QGVAR(garrisonMove_failSafe), nil, true]; _x setVariable [QGVAR(garrisonMove_unitPosMemory), nil, true]; } foreach _unitMoveListUnits; // Avoid duplicate PFHs if (isNil QGVAR(garrison_moveUnitPFH)) then { missionNameSpace setVariable [QGVAR(garrison_moveUnitPFH), true, true]; // PFH checking if the units have reached their destination [{ params ["_args", "_pfhID"]; private _unitMoveList = missionNameSpace getVariable [QGVAR(garrison_unitMoveList), []]; // End PFH if all units are placed / unable to reach position if (_unitMoveList isEqualTo []) then { missionNameSpace setVariable [QGVAR(garrison_moveUnitPFH), nil, true]; LOG("garrisonMove PFH: PFH finished it's job | deleting PFH"); _pfhID call CBA_fnc_removePerFrameHandler; } else { { _x params ["_unit", "_pos"]; private _fnc_attemptFailed = { if (_failSafeRemainingAttemps == 0 ) then { _unit setVariable [QGVAR(garrisonMove_failSafe), nil, true]; _unit setVariable [QGVAR(garrisonMove_unitPosMemory), nil, true]; [QGVAR(unGarrison), [[_unit]], _unit] call CBA_fnc_targetEvent; _unitMoveList deleteAt (_unitMoveList find _x); LOG("garrisonMove PFH: all moving commands failed | restoring AI capabilities"); } else { _unit setVariable [QGVAR(garrisonMove_failSafe), [_failSafeTimer + 15, _failSafeRemainingAttemps - 1]]; [QGVAR(doMove), [[[_unit, _pos]]], _unit] call CBA_fnc_targetEvent; LOG("garrisonMove PFH unitReady: unit not close enough | Sending another doMove command"); }; }; private _fnc_attemptSuccessful = { _unit setVariable [QGVAR(garrisonMove_failSafe), nil, true]; _unit setVariable [QGVAR(garrisonMove_unitPosMemory), nil, true]; _unit setVariable [QGVAR(garrisonned), true, true]; _unitMoveList deleteAt (_unitMoveList find _x); [QGVAR(AISection), [[_unit], ["PATH"], false], _unit] call CBA_fnc_targetEvent; [QGVAR(AISection), [[_unit], ["FSM"], true], _unit] call CBA_fnc_targetEvent; if ({(_x select 0) in units _unit && {!isPlayer (_x select 0)}} count _unitMoveList == 0) then { [QGVAR(enableAttack), [[_unit], true], _unit] call CBA_fnc_targetEvent; }; LOG(format [ARR_2("garrisonMove PFH: unit in position | %1 units left", count _unitMoveList)]); }; // Check if unit is alive or even existing if (!alive _unit || {_unit getVariable [QGVAR(garrisoned), false]}) then { _unitMoveList deleteAt (_unitMoveList find _x); LOG(format [ARR_2("garrisonMove PFH: unit dead, deleted or garrisoned via TP | %1 units left", count _unitMoveList)]); } else { private _unitPos = getPos _unit; if (surfaceisWater _unitPos) then { _unitPos = getPosASL _unit; } else { _unitPos = getPosATL _unit; }; if (unitReady _unit) then { // Check for distance, doMove and AI are moody and may stop for no reason, within 6 meters and ready should be fine if (_unitPos distance _pos < 1.5) then { call _fnc_attemptSuccessful; } else { // Tell the unit to move if an order wasn't given within 30s, avoid doMove spam (_unit getVariable [QGVAR(garrisonMove_failSafe), [CBA_missionTime, 5]]) params ["_failSafeTimer", "_failSafeRemainingAttemps"]; if (_failSafeTimer <= CBA_missionTime) then { call _fnc_attemptFailed; }; }; } else { (_unit getVariable [QGVAR(garrisonMove_unitPosMemory), [CBA_missionTime, [0,0,0]]]) params ["_unitPosTimer", "_unitOldPos"]; // AI may sometimes not be able to report unitReady, this is to avoid the PFH running forever switch true do { case ((_unitPos distance _pos) < 1.5) : { call _fnc_attemptSuccessful; }; case ((_unitPosTimer + 5) < CBA_missionTime && {_unitOldPos distance _unitPos < 0.5}) : { call _fnc_attemptFailed; }; case (_unitOldPos distance _unitPos < 0.5) : {}; default { _unit setVariable [QGVAR(garrisonMove_unitPosMemory), [CBA_missionTime, _unitPos]]; }; }; }; }; } foreach _unitMoveList; missionNameSpace setVariable [QGVAR(garrison_unitMoveList), _unitMoveList, true]; }; }, 0.5, []] call CBA_fnc_addPerFrameHandler; };