From 13f1547ef87730adb4468273f32ae34e73bef3ba Mon Sep 17 00:00:00 2001 From: PiZZAD0X Date: Thu, 5 Jan 2023 12:32:01 -0800 Subject: [PATCH 01/19] WIP UGL and Grenade actions --- .../headless_ai/functions/CfgFunctions.hpp | 1 + .../functions/Combat/fn_fireUGL.sqf | 24 +++++- .../functions/Diag/fn_ClosestEnemy.sqf | 4 +- .../functions/Diag/fn_EnemyArray.sqf | 23 ++++-- .../functions/Diag/fn_getGrenades.sqf | 19 +++++ .../SightAidSM/fn_SA_OnSECombatMode.sqf | 73 ++++++++++++++++--- .../fn_SA_OnSERemoveCantSeeEnemy.sqf | 6 +- .../SightAidSM/fn_SA_onSEEnemyInRange.sqf | 5 +- modules/headless_ai/preInitGlobal.sqf | 13 +++- modules/headless_ai/settings.hpp | 6 +- modules/headless_ai/settings/sight.hpp | 16 +++- modules/modules.sqf | 2 +- 12 files changed, 157 insertions(+), 35 deletions(-) create mode 100644 modules/headless_ai/functions/Diag/fn_getGrenades.sqf diff --git a/modules/headless_ai/functions/CfgFunctions.hpp b/modules/headless_ai/functions/CfgFunctions.hpp index d0b9ee3d..3e3d4eee 100644 --- a/modules/headless_ai/functions/CfgFunctions.hpp +++ b/modules/headless_ai/functions/CfgFunctions.hpp @@ -114,6 +114,7 @@ class COMPONENT { class ClosestObject {}; class DriverCheck {}; class EnemyArray {}; + class getGrenades {}; class getStance {}; class hasMine {}; class hasAT {}; diff --git a/modules/headless_ai/functions/Combat/fn_fireUGL.sqf b/modules/headless_ai/functions/Combat/fn_fireUGL.sqf index 1091cf52..ad478840 100644 --- a/modules/headless_ai/functions/Combat/fn_fireUGL.sqf +++ b/modules/headless_ai/functions/Combat/fn_fireUGL.sqf @@ -22,16 +22,18 @@ if (_invisibleTarget isEqualTo objnull) then { _invisibleTarget = _targetClass createVehicleLocal [0,0,0]; createVehicleCrew _invisibleTarget; _invisibleTarget allowdamage false; - private _invisibleTargetHelper = "Sign_Sphere100cm_F" createVehicleLocal [0,0,0]; if (GETMVAR(UseMarkers,false)) then { + private _invisibleTargetHelper = "Sign_Sphere100cm_F" createVehicleLocal [0,0,0]; _invisibleTargetHelper setobjecttexture [0,"#(rgb,8,8,3)color(1,0,0,1)"]; + _invisibleTargetHelper attachTo [_invisibleTarget, [0,0,0]]; } else { - _invisibleTargetHelper setobjecttexture [0,""]; + //_invisibleTargetHelper setobjecttexture [0,""]; }; - _invisibleTargetHelper attachTo [_invisibleTarget, [0,0,0]]; SETVAR(_unit,InvisibleTarget,_invisibleTarget); }; +SETVAR(_unit,busy,true); + //private _heightAdjustMult = (GETMVAR(HeightAdjustMult,0.25)); private _targetPos = [_target, 5] call CBA_fnc_randPos; private _laserPos = ATLToASL [_targetPos select 0, _targetPos select 1, (_targetPos select 2) + 2]; @@ -50,6 +52,15 @@ _unit doTarget _invisibleTarget; _this params ["_unit", "_muzzle", "_invisibleTarget"]; [_unit, _muzzle] call BIS_fnc_fire; private _relDir = _unit getDir _invisibleTarget; + [{ + params ["_unit", "_invisibleTarget"]; + _unit reveal [_invisibleTarget, 0]; + _invisibleTarget setposASL [0,0,0]; + SETVAR(_unit,busy,false); + }, [ + _unit, + _invisibleTarget + ], 3] call CBA_fnc_waitAndExecute; //TODO: move to optional param or put in existing functions that call this //[{ // _this params ["_unit", "_invisibleTarget", "_relDir"]; @@ -57,4 +68,9 @@ _unit doTarget _invisibleTarget; // _unit doTarget objNull; // [_unit, _relDir, 2] call FUNC(SuppressDirection); //}, [_unit, _invisibleTarget, _relDir]] call CBA_fnc_execNextFrame; -}, [_unit, _muzzle, _invisibleTarget], 1, {}] call CBA_fnc_waitUntilAndExecute; +}, [_unit, _muzzle, _invisibleTarget], 3, { + _this params ["_unit", "", "_invisibleTarget"]; + _unit reveal [_invisibleTarget, 0]; + _invisibleTarget setposASL [0,0,0]; + SETVAR(_unit,busy,false); +}] call CBA_fnc_waitUntilAndExecute; diff --git a/modules/headless_ai/functions/Diag/fn_ClosestEnemy.sqf b/modules/headless_ai/functions/Diag/fn_ClosestEnemy.sqf index ada8bb39..a5c0bfcd 100644 --- a/modules/headless_ai/functions/Diag/fn_ClosestEnemy.sqf +++ b/modules/headless_ai/functions/Diag/fn_ClosestEnemy.sqf @@ -8,7 +8,9 @@ private _enemyArray = [_group] call FUNC(EnemyArray); if (_enemyArray isEqualTo []) exitwith {objnull}; -private _distanceArray = _enemyArray apply { +private _distanceArray = _enemyArray select { + [_x] call EFUNC(FW,isAlive) +} apply { private _enemyDistance = _unit distance2d _x; [_enemyDistance, _x] }; diff --git a/modules/headless_ai/functions/Diag/fn_EnemyArray.sqf b/modules/headless_ai/functions/Diag/fn_EnemyArray.sqf index da22d6df..eeefea32 100644 --- a/modules/headless_ai/functions/Diag/fn_EnemyArray.sqf +++ b/modules/headless_ai/functions/Diag/fn_EnemyArray.sqf @@ -18,15 +18,24 @@ private _sideUpdateTime = switch (_side) do { default {QGVAR(enemyArrayUpdateTime_West)}; }; private _enemyArray = missionNamespace getVariable [_sideEnemies, []]; -if (_forced || {_enemyArray isEqualTo []} || {CBA_MissionTime >= (missionNamespace getVariable [_sideUpdateTime, CBA_MissionTime - 5]) + (GETMVAR(EnemyUpdateFrequency,5))}) then { +if ( + _forced || + {_enemyArray isEqualTo []} || + {CBA_MissionTime >= (missionNamespace getVariable [_sideUpdateTime, CBA_MissionTime - 5]) + (GETMVAR(EnemyUpdateFrequency,5))} +) then { private _unitSide = side _group; - _enemyArray = ((allUnits + vehicles) - allCurators) select { - !(_x isKindOf "TargetSoldierBase") && - !(_x isKindOf "HeadlessClient_F") && - {[_unitSide, (side _x)] call BIS_fnc_sideIsEnemy} + private _newEnemyArray = ((allUnits + vehicles) - allCurators) select { + !isNull _x && + {!(_x isKindOf "TargetSoldierBase")} && + {!(_x isKindOf "HeadlessClient_F")} && + {!(_x isKindOf "B_UAV_AI")} && + {!(_x isKindOf "O_UAV_AI")} && + {!(_x isKindOf "I_UAV_AI")} && + {[_unitSide, side _x] call BIS_fnc_sideIsEnemy} && + {[_x] call EFUNC(FW,isAlive)} }; missionNamespace setVariable [_sideUpdateTime, CBA_MissionTime]; - missionNamespace setVariable [_sideEnemies, _enemyArray]; + missionNamespace setVariable [_sideEnemies, _newEnemyArray]; }; -_enemyArray \ No newline at end of file +_enemyArray diff --git a/modules/headless_ai/functions/Diag/fn_getGrenades.sqf b/modules/headless_ai/functions/Diag/fn_getGrenades.sqf new file mode 100644 index 00000000..34077367 --- /dev/null +++ b/modules/headless_ai/functions/Diag/fn_getGrenades.sqf @@ -0,0 +1,19 @@ +#include "script_component.hpp" + +params ["_unit"]; + +private _frags = []; +private _smokes = []; + +magazines _unit select { + _x call BIS_fnc_isThrowable && + {_x isKindOf ["HandGrenade", configFile >> "CfgMagazines"]} +} apply { + if (_x isKindOf ["SmokeShell", configFile >> "CfgMagazines"]) then { + _smokes pushBack _x + } else { + _frags pushBack _x + }; +}; + +[_frags, _smokes] diff --git a/modules/headless_ai/functions/SightAidSM/fn_SA_OnSECombatMode.sqf b/modules/headless_ai/functions/SightAidSM/fn_SA_OnSECombatMode.sqf index 29f7b69f..bf952026 100644 --- a/modules/headless_ai/functions/SightAidSM/fn_SA_OnSECombatMode.sqf +++ b/modules/headless_ai/functions/SightAidSM/fn_SA_OnSECombatMode.sqf @@ -12,18 +12,67 @@ if (_enemyTarget isEqualTo objnull) exitwith {}; private _distance = GETVAR(_unit,SA_enemyDistance,600); if (_distance > GETMVAR(SightAidDistance,600)) exitwith {}; private _knowsabouttarget = _unit knowsabout _enemyTarget; +private _cansee = [objNull, "VIEW"] checkVisibility [eyePos _Unit, eyePos _enemyTarget]; if (_knowsabouttarget < 4) then { - private _cansee = [objNull, "VIEW"] checkVisibility [eyePos _Unit, eyePos _enemyTarget]; - if ((_cansee > 0.6) && {(_distance < GETMVAR(SightAidEngageDistance,200))}) exitwith { - _unit reveal [_enemyTarget, 4]; - _unit doSuppressiveFire _enemyTarget; - }; - if (_cansee > 0.05) then { - private _revealValue = linearConversion [100, GETMVAR(SightAidDistance,600), _distance, 4, GETMVAR(SightAidMinIncrease,1)]; - _unit reveal [_enemyTarget, _knowsabouttarget + _revealValue]; - if (GETMVAR(UseMarkers,false)) then { - LOG_4("revealing: %1 to %2, old knows: %3 new: %4",_enemyTarget,_unit,_knowsabouttarget,(_unit knowsabout _enemyTarget)); - }; - }; + if ((_cansee > 0.6) && {(_distance < GETMVAR(SightAidEngageDistance,200))}) then { + _unit reveal [_enemyTarget, 4]; + } else { + if (_cansee > 0.05) then { + private _revealValue = linearConversion [100, GETMVAR(SightAidDistance,600), _distance, 4, GETMVAR(SightAidMinIncrease,1)]; + _unit reveal [_enemyTarget, _knowsabouttarget + _revealValue]; + if (GETMVAR(UseMarkers,false)) then { + LOG_4("revealing: %1 to %2, old knows: %3 new: %4",_enemyTarget,_unit,_knowsabouttarget,(_unit knowsabout _enemyTarget)); + }; + }; + }; }; +if ( + !(GETVAR(_unit,busy,false)) && + {_knowsabouttarget > 1.5} +) then { + // Random grenade chance - random check, range check, then check for grenades, check for building, nearby friendlies to target, if none - throw grenade + if (GETMVAR(forceGrenades,true)) then { + private _chance = round random 100; + if ( + _chance <= GETMVAR(grenadeChance,25) && + {_distance <= GETMVAR(grenadeRange,40)} && + {_distance > 5} + ) then { + private _grenades = [_unit] call FUNC(getGrenades); + _grenades params [ + ["_frags", [], [[]]], + ["_smokes", [], [[]]] + ]; + if (_frags isNotEqualTo []) then { + //throw frag at enemy + TRACE_2("throwing frag at enemy!",_unit,_enemyTarget); + //private _dir = _unit getDir _enemyTarget; + //_unit setDir _dir; + SETVAR(_unit,busy,true); + [_unit, "HandGrenadeMuzzle"] call BIS_fnc_fire; + [{ + params ["_unit"]; + SETVAR(_unit,busy,false); + }, [ + _unit + ], 2] call CBA_fnc_waitAndExecute; + //_unit forceWeaponFire ["HandGrenadeMuzzle","HandGrenadeMuzzle"]; + //_unit forceWeaponFire ["MiniGrenadeMuzzle","MiniGrenadeMuzzle"]; + }; + }; + }; + if (GETMVAR(forceUGLs,true)) then { + private _chance = round random 100; + if ( + _chance <= GETMVAR(UGLChance,25) && + {_distance <= GETMVAR(UGLMaxRange,200)} && + {_distance > GETMVAR(UGLMinRange,50)} + ) then { + private _UGL = _unit call FUNC(hasUGL); + if (_UGL isNotEqualTo "") then { + [_unit, _UGL, _enemyTarget] call FUNC(fireUGL); + }; + }; + }; +}; diff --git a/modules/headless_ai/functions/SightAidSM/fn_SA_OnSERemoveCantSeeEnemy.sqf b/modules/headless_ai/functions/SightAidSM/fn_SA_OnSERemoveCantSeeEnemy.sqf index 03aac001..36e07824 100644 --- a/modules/headless_ai/functions/SightAidSM/fn_SA_OnSERemoveCantSeeEnemy.sqf +++ b/modules/headless_ai/functions/SightAidSM/fn_SA_OnSERemoveCantSeeEnemy.sqf @@ -4,7 +4,11 @@ params ["_unit"]; private _enemyTarget = GETVAR(_unit,SA_enemyTarget,objnull); private _enemyInRange = GETVAR(_unit,SA_enemyInRange,[]); -if ((_enemyTarget isNotEqualTo objnull) && {(_enemyInRange isNotEqualTo [])} && {count _enemyInRange > 1}) then { +if ( + (_enemyTarget isEqualTo objnull) && + {_enemyInRange isNotEqualTo []} && + {count _enemyInRange > 1} +) then { _enemyInRange - [_enemyTarget]; SETVAR(_unit,SA_enemyInRange,_enemyInRange); private _seeChecks = GETVAR(_unit,SA_seeChecks,0); diff --git a/modules/headless_ai/functions/SightAidSM/fn_SA_onSEEnemyInRange.sqf b/modules/headless_ai/functions/SightAidSM/fn_SA_onSEEnemyInRange.sqf index 275a31b6..5c461b48 100644 --- a/modules/headless_ai/functions/SightAidSM/fn_SA_onSEEnemyInRange.sqf +++ b/modules/headless_ai/functions/SightAidSM/fn_SA_onSEEnemyInRange.sqf @@ -6,7 +6,10 @@ params ["_unit"]; private _enemyInRange = []; private _enemyArray = group _unit call FUNC(EnemyArray); if (_enemyArray isNotEqualTo []) then { - _enemyInRange = _enemyArray select {((vehicle _unit) distance2d _x) <= (GETMVAR(SightAidDistance,600))}; + _enemyInRange = _enemyArray select { + vehicle _unit distance2d _x <= GETMVAR(SightAidDistance,600) && + {[_x] call EFUNC(FW,isAlive)} + }; }; SETVAR(_unit,SA_seeChecks,0); diff --git a/modules/headless_ai/preInitGlobal.sqf b/modules/headless_ai/preInitGlobal.sqf index ec729743..227fb5e4 100644 --- a/modules/headless_ai/preInitGlobal.sqf +++ b/modules/headless_ai/preInitGlobal.sqf @@ -41,7 +41,6 @@ GVAR(QRF_Distance) = [missionConfigFile >> QGVAR(settings) >> "QRF_Distance", "n GVAR(mountStatics) = ([missionConfigFile >> QGVAR(settings) >> "mountStatics", "number", 1] call CBA_fnc_getConfigEntry) == 1; GVAR(mountStaticsDistance) = [missionConfigFile >> QGVAR(settings) >> "mountStaticsDistance", "number", 50] call CBA_fnc_getConfigEntry; GVAR(usesmoke) = ([missionConfigFile >> QGVAR(settings) >> "usesmoke", "number", 1] call CBA_fnc_getConfigEntry) == 1; -GVAR(grenadechance) = [missionConfigFile >> QGVAR(settings) >> "grenadechance", "number", 45] call CBA_fnc_getConfigEntry; GVAR(AIDisembark) = ([missionConfigFile >> QGVAR(settings) >> "AIDisembark", "number", 1] call CBA_fnc_getConfigEntry) == 1; GVAR(AIMagLimit) = [missionConfigFile >> QGVAR(settings) >> "AIMagLimit", "number", 2] call CBA_fnc_getConfigEntry; GVAR(rainImpact) = ([missionConfigFile >> QGVAR(settings) >> "rainImpact", "number", 1] call CBA_fnc_getConfigEntry) == 1; @@ -61,6 +60,18 @@ GVAR(SightAidDistance) = [missionConfigFile >> QGVAR(settings) >> "SightAid" >> GVAR(SightAidMinIncrease) = [missionConfigFile >> QGVAR(settings) >> "SightAid" >> "minIncrease", "number", 2] call CBA_fnc_getConfigEntry; GVAR(SightAidEngageDistance) = [missionConfigFile >> QGVAR(settings) >> "SightAid" >> "engageDistance", "number", 200] call CBA_fnc_getConfigEntry; +GVAR(forceGrenades) = ([missionConfigFile >> QGVAR(settings) >> "SightAid" >> "forceGrenades", "number", 1] call CBA_fnc_getConfigEntry) == 1; +GVAR(grenadeChance) = [missionConfigFile >> QGVAR(settings) >> "SightAid" >> "grenadeChance", "number", 25] call CBA_fnc_getConfigEntry; +GVAR(grenadeRange) = [missionConfigFile >> QGVAR(settings) >> "SightAid" >> "grenadeRange", "number", 40] call CBA_fnc_getConfigEntry; + +GVAR(forceUGLs) = ([missionConfigFile >> QGVAR(settings) >> "SightAid" >> "forceUGLs", "number", 1] call CBA_fnc_getConfigEntry) == 1; +GVAR(UGLChance) = [missionConfigFile >> QGVAR(settings) >> "SightAid" >> "UGLChance", "number", 25] call CBA_fnc_getConfigEntry; +GVAR(UGLMaxRange) = [missionConfigFile >> QGVAR(settings) >> "SightAid" >> "UGLMaxRange", "number", 200] call CBA_fnc_getConfigEntry; +GVAR(UGLMinRange) = [missionConfigFile >> QGVAR(settings) >> "SightAid" >> "UGLMinRange", "number", 50] call CBA_fnc_getConfigEntry; + +GVAR(forceAT) = ([missionConfigFile >> QGVAR(settings) >> "SightAid" >> "forceAT", "number", 1] call CBA_fnc_getConfigEntry) == 1; + + //Bunker Settings GVAR(BunkerDistance) = [missionConfigFile >> QGVAR(settings) >> "Bunker" >> "distance", "number", 1200] call CBA_fnc_getConfigEntry; GVAR(AimDistAdjust) = [missionConfigFile >> QGVAR(settings) >> "Bunker" >> "aimDistAdjust", "number", 0.00024] call CBA_fnc_getConfigEntry; diff --git a/modules/headless_ai/settings.hpp b/modules/headless_ai/settings.hpp index 9ff2d1db..1215e8dd 100644 --- a/modules/headless_ai/settings.hpp +++ b/modules/headless_ai/settings.hpp @@ -7,7 +7,7 @@ of reinforcements or subsequent AOs. // Array objects // eg: ["mainEnemy", "patrol_1", "patrol_2", "patrol_3"] -arrayObjects[] = {"hc1", "hc2"}; +arrayObjects[] = {"hc_spawn"}; // Initial spawns are spawned upon init, at the start of the mission. // eg: ["mainEnemy"] @@ -72,10 +72,6 @@ QRF_Distance = 2500; mountStatics = true; // Distance AI will mount empty statics from - maximum of 100m mountStaticsDistance = 50; -// Should AI use smoke grenades? Besides default A3 behavior? -usesmoke = false; -// Percentage chance of AI using grenades -grenadechance = 45; // AI will automatically disembark from vehicles when in combat. AIDisembark = true; // How low should an AI's mag count be for them to consider finding more ammo? This DOES NOT include the mag loaded in the gun already. diff --git a/modules/headless_ai/settings/sight.hpp b/modules/headless_ai/settings/sight.hpp index 3b6f186f..34932b76 100644 --- a/modules/headless_ai/settings/sight.hpp +++ b/modules/headless_ai/settings/sight.hpp @@ -8,13 +8,25 @@ distance = 800; minIncrease = 2; // Distance at which the AI will force engage the enemies engageDistance = 200; + // Do AI use grenades forced by the statemachine? forceGrenades = true; // What percentage chance does the AI have in using a grenade? -grenadeChance = 45; +grenadeChance = 25; // What distance does the AI need to be within to use a grenade? -grenadeRange = 20; +grenadeRange = 40; + +// Should AI use smoke grenades? Besides default A3 behavior? +usesmoke = false; + // Do AI use UGLs forced by the statemachine? forceUGLs = true; +// What percentage chance does the AI have in using a ugl? +UGLChance = 99; +// What distance does the AI need to be within to use a ugl? +UGLMaxRange = 200; +// What distance does the AI need to be outside of to use a ugl? +UGLMinRange = 50; + // Do AI use rocket launchers forced by the statemachine? forceAT = true; diff --git a/modules/modules.sqf b/modules/modules.sqf index c5a409e1..053a04ff 100644 --- a/modules/modules.sqf +++ b/modules/modules.sqf @@ -45,7 +45,7 @@ Additional modules that can be enabled by removing the // //#include "firemission_virtual\root.sqf" //#include "gas\root.sqf" //#include "grad-fortifications\root.sqf" -//#include "headless_ai\root.sqf" +#include "headless_ai\root.sqf" //#include "headless_spawn\root.sqf" //#include "hostage\root.sqf" //#include "in_game_brief\root.sqf" From 049f384848bb04c301104fe47a7847cc451c4bf6 Mon Sep 17 00:00:00 2001 From: PiZZAD0X Date: Mon, 9 Jan 2023 08:54:59 -0800 Subject: [PATCH 02/19] UGL changes, caching weapon types, AT usage --- .../headless_ai/functions/CfgFunctions.hpp | 3 ++ .../functions/Combat/fn_fireAT.sqf | 38 +++++++++++++---- .../functions/Diag/fn_UGLRoundType.sqf | 37 +++++++++++++++++ .../functions/Diag/fn_getWeaponType.sqf | 28 +++++++++++++ .../headless_ai/functions/Diag/fn_hasAT.sqf | 6 ++- .../headless_ai/functions/Diag/fn_hasMG.sqf | 7 +++- .../headless_ai/functions/Diag/fn_hasUGL.sqf | 41 +++++++++++++++---- .../functions/Diag/fn_muzzleMags.sqf | 16 ++++++++ .../SightAidSM/fn_SA_OnSECombatMode.sqf | 30 ++++++++++++-- modules/headless_ai/settings/sight.hpp | 8 +++- 10 files changed, 192 insertions(+), 22 deletions(-) create mode 100644 modules/headless_ai/functions/Diag/fn_UGLRoundType.sqf create mode 100644 modules/headless_ai/functions/Diag/fn_getWeaponType.sqf create mode 100644 modules/headless_ai/functions/Diag/fn_muzzleMags.sqf diff --git a/modules/headless_ai/functions/CfgFunctions.hpp b/modules/headless_ai/functions/CfgFunctions.hpp index 3e3d4eee..eaf0a3b0 100644 --- a/modules/headless_ai/functions/CfgFunctions.hpp +++ b/modules/headless_ai/functions/CfgFunctions.hpp @@ -116,10 +116,13 @@ class COMPONENT { class EnemyArray {}; class getGrenades {}; class getStance {}; + class getWeaponType {}; class hasMine {}; class hasAT {}; class hasMG {}; class hasUGL {}; + class UGLRoundType {}; + class muzzleMags {}; class HasRadioGroup {}; class IRCheck {}; class isAimed {}; diff --git a/modules/headless_ai/functions/Combat/fn_fireAT.sqf b/modules/headless_ai/functions/Combat/fn_fireAT.sqf index cad94942..71d83ccc 100644 --- a/modules/headless_ai/functions/Combat/fn_fireAT.sqf +++ b/modules/headless_ai/functions/Combat/fn_fireAT.sqf @@ -32,10 +32,12 @@ if (_invisibleTarget isEqualTo objnull) then { SETVAR(_unit,InvisibleTarget,_invisibleTarget); }; +SETVAR(_unit,busy,true); + //private _heightAdjustMult = (GETMVAR(HeightAdjustMult,0.25)); private _targetPos = [_target, 5] call CBA_fnc_randPos; -private _laserPos = ATLToASL [_targetPos select 0, _targetPos select 1, (_targetPos select 2) + 4]; -_invisibleTarget setPosASL [_laserPos select 0, _laserPos select 1, (_laserPos select 2)]; +private _laserPos = ATLToASL [_targetPos select 0, _targetPos select 1, (_targetPos select 2) + 0]; +_invisibleTarget setPosASL [_laserPos select 0, _laserPos select 1, (_laserPos select 2) + 1]; _unit selectWeapon (secondaryWeapon _unit); _unit reveal [_invisibleTarget, 4]; _unit doTarget _invisibleTarget; @@ -44,10 +46,32 @@ _unit doTarget _invisibleTarget; private _unit = _this select 0; ({ !([getPosATL _unit, getDir _unit, 5, getPosATL _x] call BIS_fnc_inAngleSector) - } forEach ((units group _unit) - [_unit])) - && {[_unit, false] call FUNC(isAimed)} - && {currentWeapon _unit isEqualTo secondaryWeapon _unit} + } forEach ((units group _unit) - [_unit])) && + {[_unit, false] call FUNC(isAimed)} && + {currentWeapon _unit isEqualTo secondaryWeapon _unit} }, { - params ["_unit"]; + _this params ["_unit", "_invisibleTarget"]; _unit forceWeaponFire [weaponState _unit select 1, weaponState _unit select 2]; -}, [_unit], 5, {}] call CBA_fnc_waitUntilAndExecute; + //private _relDir = _unit getDir _invisibleTarget; + [{ + params ["_unit", "_invisibleTarget"]; + _unit reveal [_invisibleTarget, 0]; + _invisibleTarget setposASL [0,0,0]; + SETVAR(_unit,busy,false); + }, [ + _unit, + _invisibleTarget + ], 5] call CBA_fnc_waitAndExecute; + //TODO: move to optional param or put in existing functions that call this + //[{ + // _this params ["_unit", "_invisibleTarget", "_relDir"]; + // _invisibleTarget setPosASL [0,0,0]; + // _unit doTarget objNull; + // [_unit, _relDir, 2] call FUNC(SuppressDirection); + //}, [_unit, _invisibleTarget, _relDir]] call CBA_fnc_execNextFrame; +}, [_unit, _invisibleTarget], 5, { + _this params ["_unit", "_invisibleTarget"]; + _unit reveal [_invisibleTarget, 0]; + _invisibleTarget setposASL [0,0,0]; + SETVAR(_unit,busy,false); +}] call CBA_fnc_waitUntilAndExecute; diff --git a/modules/headless_ai/functions/Diag/fn_UGLRoundType.sqf b/modules/headless_ai/functions/Diag/fn_UGLRoundType.sqf new file mode 100644 index 00000000..39d8a180 --- /dev/null +++ b/modules/headless_ai/functions/Diag/fn_UGLRoundType.sqf @@ -0,0 +1,37 @@ +#include "script_component.hpp" + + +params [ + ["_mag", "", [""]] +]; + +// create namespace to store cache +if (isNil QGVAR(UGLRoundHashMap)) then { + GVAR(UGLRoundHashMap) = createHashMap; +}; + +// see if mag is already cached in hashmap +private _return = GVAR(UGLRoundHashMap) getOrDefault [_mag, -1]; + +if (_return isEqualTo -1) then { + // otherwise generate info and store in hashmap + // shot = 1 + // smoke = 2 + // flare = 3 + private _ammo = getText (configfile >> "CfgMagazines" >> _mag >> "Ammo"); + private _sim = getText (configfile >> "CfgAmmo" >> _ammo >> "simulation"); + _return = switch _sim do { + case "shotSmoke": { + 2 + }; + case "shotIlluminating": { + 3 + }; + default { + 1 + }; + }; + GVAR(UGLRoundHashMap) set [_mag, _return]; +}; + +_return diff --git a/modules/headless_ai/functions/Diag/fn_getWeaponType.sqf b/modules/headless_ai/functions/Diag/fn_getWeaponType.sqf new file mode 100644 index 00000000..563de5fc --- /dev/null +++ b/modules/headless_ai/functions/Diag/fn_getWeaponType.sqf @@ -0,0 +1,28 @@ +#include "script_component.hpp" + + +params [["_weapon", "", [""]]]; +if (_weapon isEqualTo "") exitWith {false}; + +// create namespace to store cache +if (isNil QGVAR(weaponTypeNamespace)) then { + GVAR(weaponTypeNamespace) = createHashMap; +}; + +// see if weapon is already cached in hashmap +private _return = GVAR(weaponTypeNamespace) getOrDefault [_weapon, -1]; + +if (_return isEqualTo -1) then { + // otherwise generate info and store in hashmap + private _type = (_weapon call BIS_fnc_itemtype) select 1; + _return = switch _type do { + case "MachineGun": {3}; + case "Launcher": {4}; + case "MissileLauncher": {4}; + case "RocketLauncher": {4}; + default {1}; + }; + GVAR(weaponTypeNamespace) set [_weapon, _return]; +}; + +_return diff --git a/modules/headless_ai/functions/Diag/fn_hasAT.sqf b/modules/headless_ai/functions/Diag/fn_hasAT.sqf index b570b7f9..56fb853f 100644 --- a/modules/headless_ai/functions/Diag/fn_hasAT.sqf +++ b/modules/headless_ai/functions/Diag/fn_hasAT.sqf @@ -3,6 +3,10 @@ params ["_unit"]; -private _response = (((secondaryWeapon _unit) isNotEqualTo "") && {secondaryWeaponMagazine _unit isNotEqualTo []}); +private _response = ( + secondaryWeapon _unit isNotEqualTo "" && + {secondaryWeaponMagazine _unit isNotEqualTo []} && + {[secondaryWeapon _unit] call FUNC(getWeaponType) isEqualTo 4} +); _response diff --git a/modules/headless_ai/functions/Diag/fn_hasMG.sqf b/modules/headless_ai/functions/Diag/fn_hasMG.sqf index 4985465f..8b437534 100644 --- a/modules/headless_ai/functions/Diag/fn_hasMG.sqf +++ b/modules/headless_ai/functions/Diag/fn_hasMG.sqf @@ -3,6 +3,9 @@ params ["_unit"]; -private _isMG = ((primaryweapon _unit) call BIS_fnc_itemtype) select 1 == "MachineGun"; +private _weapon = primaryweapon _unit; +if (_weapon isEqualTo "") exitWith {false}; -_isMG \ No newline at end of file +private _isMG = ([_weapon] call FUNC(getWeaponType)) isEqualTo 3; + +_isMG diff --git a/modules/headless_ai/functions/Diag/fn_hasUGL.sqf b/modules/headless_ai/functions/Diag/fn_hasUGL.sqf index 909a3847..63d4609a 100644 --- a/modules/headless_ai/functions/Diag/fn_hasUGL.sqf +++ b/modules/headless_ai/functions/Diag/fn_hasUGL.sqf @@ -4,11 +4,36 @@ params ["_unit"]; private _weapon = currentWeapon _unit; -private _muzzles = _weapon call CBA_fnc_getMuzzles; -if (count _muzzles < 2) exitWith {""}; -private _muzzle = ""; -{ - private _cfgPath = configFile >> "CfgWeapons" >> _weapon >> _x; - if (getText(_cfgPath >> "cursorAim") == "gl") exitWith {_muzzle = _x} -} forEach _muzzles; -_muzzle + +// create namespace to store cache +if (isNil QGVAR(weaponMuzzleNamespace)) then { + GVAR(weaponMuzzleNamespace) = createHashMap; +}; + +// see if weapon is already cached in hashmap +private _return = GVAR(weaponMuzzleNamespace) getOrDefault [_weapon, "NA"]; +TRACE_2("r1",_unit,_return); + +if (_return isEqualTo "NA") then { + // otherwise generate info and store in hashmap + private _muzzles = getArray (configFile >> "CfgWeapons" >> _weapon >> "muzzles"); + { + if (_x == "this") then { + _muzzles set [_forEachIndex, _weapon]; + }; + } forEach _muzzles; + _return = if (count _muzzles < 2) then { + "" + } else { + private _muzzle = ""; + { + if ( + getText(configFile >> "CfgWeapons" >> _weapon >> _x >> "cursorAim") == "gl" + ) exitWith {_muzzle = _x} + } forEach _muzzles; + _muzzle + }; + GVAR(weaponMuzzleNamespace) set [_weapon, _return]; +}; + +_return diff --git a/modules/headless_ai/functions/Diag/fn_muzzleMags.sqf b/modules/headless_ai/functions/Diag/fn_muzzleMags.sqf new file mode 100644 index 00000000..980f5fb9 --- /dev/null +++ b/modules/headless_ai/functions/Diag/fn_muzzleMags.sqf @@ -0,0 +1,16 @@ +#include "script_component.hpp" + + +params [ + ["_unit", objNull, [objNull]], + ["_muzzle", "", [""]], + ["_count", true, [true]] +]; + +private _magsC = [primaryWeapon _unit] call CBA_fnc_compatibleMagazines; +private _return = if (_count) then { + {_x in _magsC} count magazines _unit +} else { + magazines _unit select {_x in _magsC} +}; +_return diff --git a/modules/headless_ai/functions/SightAidSM/fn_SA_OnSECombatMode.sqf b/modules/headless_ai/functions/SightAidSM/fn_SA_OnSECombatMode.sqf index bf952026..799496a2 100644 --- a/modules/headless_ai/functions/SightAidSM/fn_SA_OnSECombatMode.sqf +++ b/modules/headless_ai/functions/SightAidSM/fn_SA_OnSECombatMode.sqf @@ -32,7 +32,7 @@ if ( {_knowsabouttarget > 1.5} ) then { // Random grenade chance - random check, range check, then check for grenades, check for building, nearby friendlies to target, if none - throw grenade - if (GETMVAR(forceGrenades,true)) then { + if (GETMVAR(forceGrenades,true) && {!(GETVAR(_unit,busy,false))}) then { private _chance = round random 100; if ( _chance <= GETMVAR(grenadeChance,25) && @@ -62,7 +62,7 @@ if ( }; }; }; - if (GETMVAR(forceUGLs,true)) then { + if (GETMVAR(forceUGLs,true) && {!(GETVAR(_unit,busy,false))}) then { private _chance = round random 100; if ( _chance <= GETMVAR(UGLChance,25) && @@ -70,8 +70,32 @@ if ( {_distance > GETMVAR(UGLMinRange,50)} ) then { private _UGL = _unit call FUNC(hasUGL); + TRACE_2("",_unit,_UGL); if (_UGL isNotEqualTo "") then { - [_unit, _UGL, _enemyTarget] call FUNC(fireUGL); + private _magList = [_unit, _UGL, false] call FUNC(muzzleMags); + TRACE_2("",_unit,_magList); + if (_magList isNotEqualTo []) then { + private _index = _magList findIf { + private _type = [_x] call FUNC(UGLRoundType); + (_type isEqualTo 1) + }; + if (_index isNotEqualTo -1) then { + _unit loadMagazine [[0], currentWeapon _unit, _magList select _index]; + [_unit, _UGL, _enemyTarget] call FUNC(fireUGL); + }; + }; + }; + }; + }; + if (GETMVAR(forceAT,true) && {!(GETVAR(_unit,busy,false))}) then { + private _chance = round random 100; + if ( + _chance <= GETMVAR(ATChance,25) && + {_distance <= GETMVAR(ATMaxRange,200)} && + {_distance > GETMVAR(ATMinRange,50)} + ) then { + if (_unit call FUNC(hasAT)) then { + [_unit, _enemyTarget] call FUNC(fireAT); }; }; }; diff --git a/modules/headless_ai/settings/sight.hpp b/modules/headless_ai/settings/sight.hpp index 34932b76..c9c5d5c1 100644 --- a/modules/headless_ai/settings/sight.hpp +++ b/modules/headless_ai/settings/sight.hpp @@ -28,5 +28,11 @@ UGLMaxRange = 200; // What distance does the AI need to be outside of to use a ugl? UGLMinRange = 50; -// Do AI use rocket launchers forced by the statemachine? +// Do AI use launchers forced by the statemachine? forceAT = true; +// What percentage chance does the AI have in using a laucnher? +ATChance = 99; +// What distance does the AI need to be within to use a laucnher? +ATMaxRange = 300; +// What distance does the AI need to be outside of to use a laucnher? +ATMinRange = 50; From 3beac21c87829ba67238786afc85c9a62915d154 Mon Sep 17 00:00:00 2001 From: PiZZAD0X Date: Tue, 10 Jan 2023 07:08:50 -0800 Subject: [PATCH 03/19] fireAT, AI Commander zone control state, optimizations - moved commander checks to separate files - fireAT aiming changes - clearSight function - AI commander control state - enemyArray function param changed to side - nearbyFriendlyEntities optimization, infantry only optional mode --- .../BunkerSM/fn_OnSEEnemyInRange.sqf | 4 +- .../CachingSM/fn_CH_onSEDistanceCheck.sqf | 2 +- .../headless_ai/functions/CfgFunctions.hpp | 2 + .../Combat/fn_CombatAssaultVehicle.sqf | 3 +- .../Combat/fn_ReinforcementResponse.sqf | 2 +- .../functions/Combat/fn_fireAT.sqf | 6 +- .../Commander/fn_CommanderGroupHandler.sqf | 106 +++++++++++++++ .../Commander/fn_CommanderHandler.sqf | 17 ++- .../functions/Commander/fn_CommanderInit.sqf | 30 ++--- .../functions/Commander/fn_assignToArea.sqf | 2 +- .../functions/Diag/fn_ClosestEnemy.sqf | 3 +- .../functions/Diag/fn_ClosestObject.sqf | 2 +- .../functions/Diag/fn_EnemyArray.sqf | 55 +++++--- .../functions/Diag/fn_clearSight.sqf | 15 +++ .../Diag/fn_nearbyFriendlyEntities.sqf | 49 ++++++- .../functions/Main/fn_GroupHandler.sqf | 126 ++++-------------- .../functions/Main/fn_MapMarkers.sqf | 44 +++--- .../SightAidSM/fn_SA_onSEEnemyInRange.sqf | 2 +- modules/headless_ai/preInitGlobal.sqf | 10 ++ modules/headless_ai/settings.hpp | 2 +- modules/headless_ai/settings/commander.hpp | 22 ++- modules/headless_ai/settings/sight.hpp | 4 +- 22 files changed, 319 insertions(+), 189 deletions(-) create mode 100644 modules/headless_ai/functions/Commander/fn_CommanderGroupHandler.sqf create mode 100644 modules/headless_ai/functions/Diag/fn_clearSight.sqf diff --git a/modules/headless_ai/functions/BunkerSM/fn_OnSEEnemyInRange.sqf b/modules/headless_ai/functions/BunkerSM/fn_OnSEEnemyInRange.sqf index fdff69c6..b5456ba3 100644 --- a/modules/headless_ai/functions/BunkerSM/fn_OnSEEnemyInRange.sqf +++ b/modules/headless_ai/functions/BunkerSM/fn_OnSEEnemyInRange.sqf @@ -3,7 +3,7 @@ params ["_unit"]; private _enemyInRange = []; -private _enemyArray = group _unit call FUNC(EnemyArray); +private _enemyArray = side _unit call FUNC(EnemyArray); private _distance = GETVAR(_unit,bunkerDistance,(GVAR(bunkerDistance))); if (_enemyArray isNotEqualTo []) then { _enemyInRange = _enemyArray select {((vehicle _unit) distance2d _x) <= _distance}; @@ -12,4 +12,4 @@ if (_enemyArray isNotEqualTo []) then { SETVAR(_unit,enemyInRange,_enemyInRange); SETVAR(_unit,TargetSet,false); SETVAR(_this,burstCount,0); -SETVAR(_this,BurstResetCount,0); \ No newline at end of file +SETVAR(_this,BurstResetCount,0); diff --git a/modules/headless_ai/functions/CachingSM/fn_CH_onSEDistanceCheck.sqf b/modules/headless_ai/functions/CachingSM/fn_CH_onSEDistanceCheck.sqf index 8d19dacb..3b1e7065 100644 --- a/modules/headless_ai/functions/CachingSM/fn_CH_onSEDistanceCheck.sqf +++ b/modules/headless_ai/functions/CachingSM/fn_CH_onSEDistanceCheck.sqf @@ -7,7 +7,7 @@ private _enemyInRange = false; private _enemyArray = if (GETMVAR(CacheAllPlayers,true)) then { [] call BIS_fnc_listPlayers; } else { - _group call FUNC(EnemyArray); + side _leader call FUNC(EnemyArray); }; if (_enemyArray isNotEqualTo []) then { diff --git a/modules/headless_ai/functions/CfgFunctions.hpp b/modules/headless_ai/functions/CfgFunctions.hpp index eaf0a3b0..5ba94539 100644 --- a/modules/headless_ai/functions/CfgFunctions.hpp +++ b/modules/headless_ai/functions/CfgFunctions.hpp @@ -70,6 +70,7 @@ class COMPONENT { file = "modules\headless_ai\functions\Commander"; class assignToArea {}; class CommanderHandler {}; + class CommanderGroupHandler {}; class CommanderInit {}; }; @@ -110,6 +111,7 @@ class COMPONENT { class Diag { file = "modules\headless_ai\functions\Diag"; class checkView {}; + class clearSight {}; class closestEnemy {}; class ClosestObject {}; class DriverCheck {}; diff --git a/modules/headless_ai/functions/Combat/fn_CombatAssaultVehicle.sqf b/modules/headless_ai/functions/Combat/fn_CombatAssaultVehicle.sqf index 496dbed3..4f2f564c 100644 --- a/modules/headless_ai/functions/Combat/fn_CombatAssaultVehicle.sqf +++ b/modules/headless_ai/functions/Combat/fn_CombatAssaultVehicle.sqf @@ -3,7 +3,6 @@ params ["_group", "_targetPos", ["_compradius", 250, [0]]]; LOG_1("combatAssault started _this: %1",_this); -private _leader = leader _group; private _units = units _group; [_group] call CBA_fnc_clearWaypoints; @@ -38,7 +37,7 @@ private _assaultTaskPFH = [{ (getPosATL _leader distance2D _targetPos) <= _compradius } || { - !(((_group call FUNC(EnemyArray)) findif { + !(((side _leader call FUNC(EnemyArray)) findif { ((_leader distance2D _x) <= (GETVAR(_group,AssaultEngageDistance,200))) && {[_leader, _x] call FUNC(LOSCheck)} }) isEqualTo -1) diff --git a/modules/headless_ai/functions/Combat/fn_ReinforcementResponse.sqf b/modules/headless_ai/functions/Combat/fn_ReinforcementResponse.sqf index ce52a592..3fcfeb46 100644 --- a/modules/headless_ai/functions/Combat/fn_ReinforcementResponse.sqf +++ b/modules/headless_ai/functions/Combat/fn_ReinforcementResponse.sqf @@ -27,7 +27,7 @@ private _knownEnemy = (_nearbyEnemy isNotEqualTo []); // private _importance = GETVAR(_namespace,importance,_forEachIndex); // private _assignedAssets = GETVAR(_namespace,assignedAssets,[]); // private _assetCount = count _assignedAssets; -// private _controlStatus = GETVAR(_namespace,control,"Neutral"); +// private _controlStatus = GETVAR(_namespace,control,"Unknown"); // }; // }; //} else { diff --git a/modules/headless_ai/functions/Combat/fn_fireAT.sqf b/modules/headless_ai/functions/Combat/fn_fireAT.sqf index 71d83ccc..999e2324 100644 --- a/modules/headless_ai/functions/Combat/fn_fireAT.sqf +++ b/modules/headless_ai/functions/Combat/fn_fireAT.sqf @@ -36,7 +36,7 @@ SETVAR(_unit,busy,true); //private _heightAdjustMult = (GETMVAR(HeightAdjustMult,0.25)); private _targetPos = [_target, 5] call CBA_fnc_randPos; -private _laserPos = ATLToASL [_targetPos select 0, _targetPos select 1, (_targetPos select 2) + 0]; +private _laserPos = ATLToASL [_targetPos select 0, _targetPos select 1, (_targetPos select 2) - 1]; _invisibleTarget setPosASL [_laserPos select 0, _laserPos select 1, (_laserPos select 2) + 1]; _unit selectWeapon (secondaryWeapon _unit); _unit reveal [_invisibleTarget, 4]; @@ -44,9 +44,7 @@ _unit doTarget _invisibleTarget; [{ private _unit = _this select 0; - ({ - !([getPosATL _unit, getDir _unit, 5, getPosATL _x] call BIS_fnc_inAngleSector) - } forEach ((units group _unit) - [_unit])) && + [_unit] call FUNC(clearSight) && {[_unit, false] call FUNC(isAimed)} && {currentWeapon _unit isEqualTo secondaryWeapon _unit} }, { diff --git a/modules/headless_ai/functions/Commander/fn_CommanderGroupHandler.sqf b/modules/headless_ai/functions/Commander/fn_CommanderGroupHandler.sqf new file mode 100644 index 00000000..599e3cec --- /dev/null +++ b/modules/headless_ai/functions/Commander/fn_CommanderGroupHandler.sqf @@ -0,0 +1,106 @@ +#include "script_component.hpp" + +params [ + ["_group", grpNull, [grpNull]], + ["_areaAssigned", "NONE", [""]], + ["_assetType", "Infantry", [""]] +]; + +//commander handling +if (_areaAssigned isEqualTo "NONE") then { + //check zones for assignments + private _assigned = false; + if (GETMVAR(CommanderAssignStartZone,false)) then { + private _index = GVAR(CommanderAreasParsed) findIf { + private _namespace = missionNamespace getVariable _x; + private _marker = GETVAR(_namespace,marker,""); + leader _group inArea _marker + }; + if (_index isNotEqualTo -1) then { + private _namespace = missionNamespace getVariable (GVAR(CommanderAreasParsed) select _index); + private _displayName = GETVAR(_namespace,displayName,""); + private _max = GETVAR(_namespace,max,10); + private _assignedAssets = GETVAR(_namespace,assignedAssets,[]); + private _assetCount = count _assignedAssets; + private _controlStatus = GETVAR(_namespace,control,"Unknown"); + private _preferredTypes = GETVAR(_namespace,preferredTypes,"ALL"); + if ( + (_assetCount < _max) && + {!_assigned} && + {!(_controlStatus in ["EnemyControlled", "Contested"])} && + {(_assetType in _preferredTypes) || (_preferredTypes isEqualTo ["ALL"])} + ) then { + LOG_2("Sending group %1 to area %2",_group,_displayName); + _assigned = true; + [_group,_namespace] call FUNC(assignToArea); + }; + }; + } else { + { + private _namespace = missionNamespace getVariable _x; + private _displayName = GETVAR(_namespace,displayName,""); + //private _mission = GETVAR(_namespace,mission,"Patrol"); + //private _marker = GETVAR(_namespace,marker,""); + //private _min = GETVAR(_namespace,min,0); + private _max = GETVAR(_namespace,max,10); + //private _threshold = GETVAR(_namespace,threshold,1); + //private _QRFSupport = GETVAR(_namespace,QRFSupport,true); + //private _assetSupport = GETVAR(_namespace,assetSupport,true); + //private _withdrawalEnabled = GETVAR(_namespace,withdrawalEnabled,true); + //private _resourceUse = GETVAR(_namespace,resourceUse,true); + private _preferredTypes = GETVAR(_namespace,preferredTypes,"ALL"); + //private _terrainMode = GETVAR(_namespace,terrainMode,"Auto"); + //private _importance = GETVAR(_namespace,importance,_forEachIndex); + private _assignedAssets = GETVAR(_namespace,assignedAssets,[]); + private _controlStatus = GETVAR(_namespace,control,"Unknown"); + private _assetCount = count _assignedAssets; + //LOG_3("Area: %1 _assetCount: %2 _max: %3",_displayName,_assetCount,_max); + if ( + (_assetCount < _max) && + {!_assigned} && + {!(_controlStatus in ["EnemyControlled", "Contested"])} && + {(_assetType in _preferredTypes) || (_preferredTypes isEqualTo ["ALL"])} + ) then { + LOG_2("Sending group %1 to area %2",_group,_displayName); + _assigned = true; + [_group,_namespace] call FUNC(assignToArea); + }; + } foreach GVAR(CommanderAreasParsed); + }; + if !(_assigned) then { + ERROR_1("Could not find area suitable for: %1 type %2 ignoring preferred types",_group,_assetType); + { + private _namespace = missionNamespace getVariable _x; + private _displayName = GETVAR(_namespace,displayName,""); + //private _mission = GETVAR(_namespace,mission,"Patrol"); + //private _marker = GETVAR(_namespace,marker,""); + //private _min = GETVAR(_namespace,min,0); + private _max = GETVAR(_namespace,max,10); + //private _threshold = GETVAR(_namespace,threshold,1); + //private _QRFSupport = GETVAR(_namespace,QRFSupport,true); + //private _assetSupport = GETVAR(_namespace,assetSupport,true); + //private _withdrawalEnabled = GETVAR(_namespace,withdrawalEnabled,true); + //private _resourceUse = GETVAR(_namespace,resourceUse,true); + //private _preferredTypes = GETVAR(_namespace,preferredTypes,"ALL"); + //private _terrainMode = GETVAR(_namespace,terrainMode,"Auto"); + //private _importance = GETVAR(_namespace,importance,_forEachIndex); + private _assignedAssets = GETVAR(_namespace,assignedAssets,[]); + private _controlStatus = GETVAR(_namespace,control,"Unknown"); + private _assetCount = count _assignedAssets; + //LOG_3("Area: %1 _assetCount: %2 _max: %3",_marker,_assetCount,_max); + if ( + (_assetCount < _max) && + {!_assigned} && + {!(_controlStatus in ["EnemyControlled", "Contested"])} + ) then { + LOG_2("Sending group %1 to area %2",_group,_displayName); + _assigned = true; + [_group,_namespace] call FUNC(assignToArea); + }; + } foreach GVAR(CommanderAreasParsed); + if !(_assigned) then { + ERROR_1("Could not find area suitable for: %1 sending to default zone",_group); + [_group,(missionNamespace getVariable (GVAR(CommanderAreasParsed) select 0))] call FUNC(assignToArea); + }; + }; +}; diff --git a/modules/headless_ai/functions/Commander/fn_CommanderHandler.sqf b/modules/headless_ai/functions/Commander/fn_CommanderHandler.sqf index ba77e90b..6c2bc18b 100644 --- a/modules/headless_ai/functions/Commander/fn_CommanderHandler.sqf +++ b/modules/headless_ai/functions/Commander/fn_CommanderHandler.sqf @@ -21,7 +21,22 @@ GVAR(CommanderAreasHandlerPFH) = [{ private _terrainMode = GETVAR(_namespace,terrainMode,"Auto"); private _importance = GETVAR(_namespace,importance,_forEachIndex); private _assignedAssets = GETVAR(_namespace,assignedAssets,[]); - private _controlStatus = GETVAR(_namespace,control,"Neutral"); + private _knownEnemies = [GVAR(CommanderSide)] call FUNC(enemyArray); + private _enemiesInArea = {_x inArea _marker} count _knownEnemies; + private _assetsInArea = {leader _x inArea _marker} count _assignedAssets; + private _controlStatus = if (_assetsInArea > 0) then { + if (_enemiesInArea isEqualTo 0) then { + "Friendly" + } else { + "Contested" + }; + } else { + if (_enemiesInArea isEqualTo 0) then { + "Unknown" + } else { + "Enemy" + }; + }; if (GVAR(CommanderDebug)) then { private _markerColour = switch (_terrainMode) do { diff --git a/modules/headless_ai/functions/Commander/fn_CommanderInit.sqf b/modules/headless_ai/functions/Commander/fn_CommanderInit.sqf index 7a0063da..b64a9413 100644 --- a/modules/headless_ai/functions/Commander/fn_CommanderInit.sqf +++ b/modules/headless_ai/functions/Commander/fn_CommanderInit.sqf @@ -7,21 +7,21 @@ GVAR(CommanderAreasParsed) = []; { private _area = _x; _area params [ - ["_displayName", "", [""]], - ["_marker", "", [""]], - ["_mission", "Patrol", [""]], - ["_min",0,[0]], - ["_max",10,[10]], - ["_threshold",1,[1]], - ["_QRFSupport",true,[true]], - ["_assetSupport",true,[true]], - ["_withdrawalEnabled",true,[true]], - ["_resourceUse",true,[true]], - ["_preferredTypes",["ALL"],[[]]], - ["_terrainMode","Auto",[""]], - ["_importance",_foreachIndex,[0]], - ["_assignedAssets",[],[[]]], - ["_control","Neutral",["Neutral"]] + /*1*/ ["_displayName", "", [""]], + /*2*/ ["_marker", "", [""]], + /*3*/ ["_mission", "Patrol", [""]], + /*4*/ ["_min",0,[0]], + /*5*/ ["_max",10,[10]], + /*6*/ ["_threshold",1,[1]], + /*7*/ ["_QRFSupport",true,[true]], + /*8*/ ["_assetSupport",true,[true]], + /*9*/ ["_withdrawalEnabled",true,[true]], + /*10*/ ["_resourceUse",true,[true]], + /*11*/ ["_preferredTypes",["ALL"],[[]]], + /*12*/ ["_terrainMode","Auto",[""]], + /*13*/ ["_importance",_foreachIndex,[0]], + /*14*/ ["_assignedAssets",[],[[]]], + /*15*/ ["_control","Neutral",["Neutral"]] ]; TRACE_1("",_area); if (_displayName isEqualTo "") then { diff --git a/modules/headless_ai/functions/Commander/fn_assignToArea.sqf b/modules/headless_ai/functions/Commander/fn_assignToArea.sqf index 15693ea8..de02b14a 100644 --- a/modules/headless_ai/functions/Commander/fn_assignToArea.sqf +++ b/modules/headless_ai/functions/Commander/fn_assignToArea.sqf @@ -26,7 +26,7 @@ private _areaMarker = GETVAR(_namespace,marker,""); //private _areaTerrainMode = GETVAR(_namespace,terrainMode,"Auto"); //private _areaImportance = GETVAR(_namespace,importance,_forEachIndex); private _areaAssignedAssets = GETVAR(_namespace,assignedAssets,[]); -//private _areaControlStatus = GETVAR(_namespace,control,"Neutral"); +//private _areaControlStatus = GETVAR(_namespace,control,"Unknown"); LOG_2("assigning %1 to Area: %2",_group,_areaDisplayName); SETVAR(_group,areaAssigned,_areaMarker); diff --git a/modules/headless_ai/functions/Diag/fn_ClosestEnemy.sqf b/modules/headless_ai/functions/Diag/fn_ClosestEnemy.sqf index a5c0bfcd..59fe3980 100644 --- a/modules/headless_ai/functions/Diag/fn_ClosestEnemy.sqf +++ b/modules/headless_ai/functions/Diag/fn_ClosestEnemy.sqf @@ -3,8 +3,7 @@ params ["_unit", ["_randomSelect", false, [false]]]; -private _group = group _unit; -private _enemyArray = [_group] call FUNC(EnemyArray); +private _enemyArray = [side _unit] call FUNC(EnemyArray); if (_enemyArray isEqualTo []) exitwith {objnull}; diff --git a/modules/headless_ai/functions/Diag/fn_ClosestObject.sqf b/modules/headless_ai/functions/Diag/fn_ClosestObject.sqf index dc7ec4f7..1b3c8204 100644 --- a/modules/headless_ai/functions/Diag/fn_ClosestObject.sqf +++ b/modules/headless_ai/functions/Diag/fn_ClosestObject.sqf @@ -5,7 +5,7 @@ params [["_list",[],[[]]],["_object",objnull,[objnull]],["_randomSelect",false,[ if ("_object" isEqualTo objnull) exitWith {}; if ("_list" isEqualTo []) exitWith {}; - + private _DistanceArray = []; { diff --git a/modules/headless_ai/functions/Diag/fn_EnemyArray.sqf b/modules/headless_ai/functions/Diag/fn_EnemyArray.sqf index eeefea32..fb7a716b 100644 --- a/modules/headless_ai/functions/Diag/fn_EnemyArray.sqf +++ b/modules/headless_ai/functions/Diag/fn_EnemyArray.sqf @@ -1,41 +1,54 @@ #include "script_component.hpp" -params ["_group", ["_forced", false, [false]]]; +params [["_side", blufor, [blufor]], ["_forced", false, [false]]]; -private _side = side _group; -private _sideEnemies = switch (_side) do { - case west: {QGVAR(EnemyArray_West)}; - case east: {QGVAR(EnemyArray_East)}; - case independent: {QGVAR(EnemyArray_Ind)}; - case civilian: {QGVAR(EnemyArray_Civ)}; - default {QGVAR(EnemyArray_West)}; -}; -private _sideUpdateTime = switch (_side) do { - case west: {QGVAR(enemyArrayUpdateTime_West)}; - case east: {QGVAR(enemyArrayUpdateTime_East)}; - case independent: {QGVAR(enemyArrayUpdateTime_Ind)}; - case civilian: {QGVAR(enemyArrayUpdateTime_Civ)}; - default {QGVAR(enemyArrayUpdateTime_West)}; +private _sideEnemies = QGVAR(bluforEnemyArray); +private _enemySides = GVAR(bluforEnemies); +private _sideUpdateTime = QGVAR(bluforEnemyArrayUpdateTime); +switch (_side) do { + case east: { + _sideEnemies = QGVAR(opforEnemyArray); + _enemySides = GVAR(opforEnemies); + _sideUpdateTime = QGVAR(opforEnemyArrayUpdateTime); + }; + case independent: { + _sideEnemies = QGVAR(indforEnemyArray); + _enemySides = GVAR(indforEnemies); + _sideUpdateTime = QGVAR(indforEnemyArrayUpdateTime); + }; + case civilian: { + _sideEnemies = QGVAR(civforEnemyArrays); + _enemySides = GVAR(bluforEnemies); + _sideUpdateTime = QGVAR(civEnemyArrayUpdateTime); + }; + default { + _sideEnemies = QGVAR(bluforEnemyArray); + _enemySides = GVAR(bluforEnemies); + _sideUpdateTime = QGVAR(bluforEnemyArrayUpdateTime); + }; }; + private _enemyArray = missionNamespace getVariable [_sideEnemies, []]; + if ( _forced || {_enemyArray isEqualTo []} || {CBA_MissionTime >= (missionNamespace getVariable [_sideUpdateTime, CBA_MissionTime - 5]) + (GETMVAR(EnemyUpdateFrequency,5))} ) then { - private _unitSide = side _group; - private _newEnemyArray = ((allUnits + vehicles) - allCurators) select { + //_enemyArray = ((allUnits + vehicles) - allCurators) select { + private _list = []; + _enemySides apply {_list append units _x}; + _enemyArray = _list select { !isNull _x && + {[_x] call EFUNC(FW,isAlive)} && {!(_x isKindOf "TargetSoldierBase")} && {!(_x isKindOf "HeadlessClient_F")} && {!(_x isKindOf "B_UAV_AI")} && {!(_x isKindOf "O_UAV_AI")} && - {!(_x isKindOf "I_UAV_AI")} && - {[_unitSide, side _x] call BIS_fnc_sideIsEnemy} && - {[_x] call EFUNC(FW,isAlive)} + {!(_x isKindOf "I_UAV_AI")} }; missionNamespace setVariable [_sideUpdateTime, CBA_MissionTime]; - missionNamespace setVariable [_sideEnemies, _newEnemyArray]; + missionNamespace setVariable [_sideEnemies, _enemyArray]; }; _enemyArray diff --git a/modules/headless_ai/functions/Diag/fn_clearSight.sqf b/modules/headless_ai/functions/Diag/fn_clearSight.sqf new file mode 100644 index 00000000..4cb83585 --- /dev/null +++ b/modules/headless_ai/functions/Diag/fn_clearSight.sqf @@ -0,0 +1,15 @@ +#include "script_component.hpp" + + +params [["_unit", objNull, [objNull]]]; + +if (_unit isEqualTo objNull) exitWith { + ERROR_1("null unit call for clearSight",_unit); + false +}; + +private _response = ((_unit nearEntities ["Man", 3]) findIf { + [getPosATL _unit, getDir _unit, 5, getPosATL _x] call BIS_fnc_inAngleSector +}) isEqualTo -1; + +_response diff --git a/modules/headless_ai/functions/Diag/fn_nearbyFriendlyEntities.sqf b/modules/headless_ai/functions/Diag/fn_nearbyFriendlyEntities.sqf index 0d1f646d..63139e10 100644 --- a/modules/headless_ai/functions/Diag/fn_nearbyFriendlyEntities.sqf +++ b/modules/headless_ai/functions/Diag/fn_nearbyFriendlyEntities.sqf @@ -1,15 +1,50 @@ #include "script_component.hpp" -params ["_unit", ["_distance", 50, [50]]]; +params [ + "_unit", + ["_distance", 5, [5]], + ["_infantryOnly", false, [false]] +]; -private _nearbyInfantry = (_unit nearEntities ["CAManBase", _distance]) select {side commander _x isEqualTo _unit}; -private _nearbyCars = (_unit nearEntities ["Car", _distance]) select {side commander _x isEqualTo _unit}; -private _nearbyAPCs = (_unit nearEntities [["TrackedAPC", "WheeledAPC"], _distance]) select {side commander _x isEqualTo _unit}; -private _nearbyTanks = (_unit nearEntities ["Tank", _distance]) select {side commander _x isEqualTo _unit}; +if (_infantryOnly) exitWith { + private _nearbyInfantry = (_unit nearEntities [[ + "CAManBase" + ], _distance]) select { + side _x isEqualTo side _unit + }; + private _nearbyEntities = [_nearbyInfantry, [], [], []]; + _nearbyEntities +}; -private _nearbyEntities = [_nearbyInfantry, _nearbyCars, _nearbyAPCs, _nearbyTanks]; +private _list = _unit nearEntities [[ + "CAManBase", + "Car", + "WheeledAPC", + "TrackedAPC", + "Tank" +], _distance]; -_nearbyEntities +private _nearbyInfantry = _list select { + side _x isEqualTo side _unit && + {_x isKindOf "CAManBase"} +}; +private _nearbyCars = _list select { + side _x isEqualTo side _unit && + {_x isKindOf "CAManBase"} +}; +private _nearbyAPCs = _list select { + side _x isEqualTo side _unit && + { + _x isKindOf "TrackedAPC" || + {_x isKindOf "WheeledAPC"} + } +}; +private _nearbyTanks = _list select { + side _x isEqualTo side _unit && + {_x isKindOf "Tank"} +}; +private _nearbyEntities = [_nearbyInfantry, _nearbyCars, _nearbyAPCs, _nearbyTanks]; +_nearbyEntities diff --git a/modules/headless_ai/functions/Main/fn_GroupHandler.sqf b/modules/headless_ai/functions/Main/fn_GroupHandler.sqf index 1cee49cb..9f10a1c7 100644 --- a/modules/headless_ai/functions/Main/fn_GroupHandler.sqf +++ b/modules/headless_ai/functions/Main/fn_GroupHandler.sqf @@ -34,33 +34,33 @@ GVAR(GroupHandlerPFH) = [{ _target = objNull; SETVAR(_group,CurrentTarget,objNull); }; - //if (_target isEqualTo objNull && {assignedTarget _leader isNotEqualTo objNull}) then { - // TRACE_2("set target on active group",_group,_target); - // _target = leader (assignedTarget _leader); - // if (_target isEqualTo objNull) then { - // private _targetCounter = GETVAR(_group,NullTargetCounter,0); - // if (_targetCounter >= 5) then { - // TRACE_1("no longer in combat, exiting and resetting",_group); - // SETVAR(_group,NullTargetCounter,0); - // private _originalBeh = GETVAR(_group,behaviour,"AWARE"); - // private _originalCM = GETVAR(_group,combatMode,"YELLOW"); - // private _originalSpeed = GETVAR(_group,speed,"normal"); - // private _originalForm = GETVAR(_group,formation,"wedge"); - // [_group,_originalBeh,_originalCM,_originalSpeed,_originalForm] call FUNC(setGroupBehaviour); - // private _originalTask = GETVAR(_group,OriginalTask,"PATROL"); - // private _originalPos = GETVAR(_group,Pos,getPos leader _group); - // private _originalRadius = GETVAR(_group,taskRadius,30); - // [_group,_originalTask,_originalPos,_originalRadius] call FUNC(taskAssign); - // } else { - // _targetCounter = _targetCounter + 1; - // SETVAR(_group,NullTargetCounter,_targetCounter); - // }; - // } else { - // SETVAR(_group,CurrentTarget,_target); - // }; - //} else { - // SETVAR(_group,NullTargetCounter,0); - //}; + if (_target isEqualTo objNull && {assignedTarget _leader isNotEqualTo objNull}) then { + TRACE_2("set target on active group",_group,_target); + _target = leader (assignedTarget _leader); + if (_target isEqualTo objNull) then { + private _targetCounter = GETVAR(_group,NullTargetCounter,0); + if (_targetCounter >= 5) then { + TRACE_1("no longer in combat, exiting and resetting",_group); + SETVAR(_group,NullTargetCounter,0); + private _originalBeh = GETVAR(_group,behaviour,"AWARE"); + private _originalCM = GETVAR(_group,combatMode,"YELLOW"); + private _originalSpeed = GETVAR(_group,speed,"normal"); + private _originalForm = GETVAR(_group,formation,"wedge"); + [_group,_originalBeh,_originalCM,_originalSpeed,_originalForm] call FUNC(setGroupBehaviour); + private _originalTask = GETVAR(_group,OriginalTask,"PATROL"); + private _originalPos = GETVAR(_group,Pos,getPos leader _group); + private _originalRadius = GETVAR(_group,taskRadius,30); + [_group,_originalTask,_originalPos,_originalRadius] call FUNC(taskAssign); + } else { + _targetCounter = _targetCounter + 1; + SETVAR(_group,NullTargetCounter,_targetCounter); + }; + } else { + SETVAR(_group,CurrentTarget,_target); + }; + } else { + SETVAR(_group,NullTargetCounter,0); + }; if (GETMVAR(UseMarkers,false)) then { //TRACE_2("",GVAR(markerTrackedGroups),str _group); GVAR(markerTrackedGroups) set [str _group, [ @@ -117,82 +117,12 @@ GVAR(GroupHandlerPFH) = [{ }; }; }; - //commander handling if ( (GETMVAR(CommanderEnabled,false)) && {!(GETVAR(_group,CommanderExempt,false))} && {side _group isEqualTo (GETMVAR(CommanderSide,east))} ) then { - if (_areaAssigned isEqualTo "NONE") then { - //check zones for assignments - private _assigned = false; - { - private _namespace = missionNamespace getVariable _x; - private _displayName = GETVAR(_namespace,displayName,""); - //private _mission = GETVAR(_namespace,mission,"Patrol"); - //private _marker = GETVAR(_namespace,marker,""); - //private _min = GETVAR(_namespace,min,0); - private _max = GETVAR(_namespace,max,10); - //private _threshold = GETVAR(_namespace,threshold,1); - //private _QRFSupport = GETVAR(_namespace,QRFSupport,true); - //private _assetSupport = GETVAR(_namespace,assetSupport,true); - //private _withdrawalEnabled = GETVAR(_namespace,withdrawalEnabled,true); - //private _resourceUse = GETVAR(_namespace,resourceUse,true); - private _preferredTypes = GETVAR(_namespace,preferredTypes,"ALL"); - //private _terrainMode = GETVAR(_namespace,terrainMode,"Auto"); - //private _importance = GETVAR(_namespace,importance,_forEachIndex); - private _assignedAssets = GETVAR(_namespace,assignedAssets,[]); - private _controlStatus = GETVAR(_namespace,control,"Neutral"); - private _assetCount = count _assignedAssets; - //LOG_3("Area: %1 _assetCount: %2 _max: %3",_displayName,_assetCount,_max); - if ( - (_assetCount < _max) && - {!_assigned} && - {!(_controlStatus in ["EnemyControlled", "Contested"])} && - {(_assetType in _preferredTypes) || (_preferredTypes isEqualTo ["ALL"])} - ) then { - LOG_2("Sending group %1 to area %2",_group,_displayName); - _assigned = true; - [_group,_namespace] call FUNC(assignToArea); - }; - } foreach GVAR(CommanderAreasParsed); - if !(_assigned) then { - ERROR_1("Could not find area suitable for: %1 type %2 ignoring preferred types",_group,_assetType); - { - private _namespace = missionNamespace getVariable _x; - private _displayName = GETVAR(_namespace,displayName,""); - //private _mission = GETVAR(_namespace,mission,"Patrol"); - //private _marker = GETVAR(_namespace,marker,""); - //private _min = GETVAR(_namespace,min,0); - private _max = GETVAR(_namespace,max,10); - //private _threshold = GETVAR(_namespace,threshold,1); - //private _QRFSupport = GETVAR(_namespace,QRFSupport,true); - //private _assetSupport = GETVAR(_namespace,assetSupport,true); - //private _withdrawalEnabled = GETVAR(_namespace,withdrawalEnabled,true); - //private _resourceUse = GETVAR(_namespace,resourceUse,true); - //private _preferredTypes = GETVAR(_namespace,preferredTypes,"ALL"); - //private _terrainMode = GETVAR(_namespace,terrainMode,"Auto"); - //private _importance = GETVAR(_namespace,importance,_forEachIndex); - private _assignedAssets = GETVAR(_namespace,assignedAssets,[]); - private _controlStatus = GETVAR(_namespace,control,"Neutral"); - private _assetCount = count _assignedAssets; - //LOG_3("Area: %1 _assetCount: %2 _max: %3",_marker,_assetCount,_max); - if ( - (_assetCount < _max) && - {!_assigned} && - {!(_controlStatus in ["EnemyControlled", "Contested"])} - ) then { - LOG_2("Sending group %1 to area %2",_group,_displayName); - _assigned = true; - [_group,_namespace] call FUNC(assignToArea); - }; - } foreach GVAR(CommanderAreasParsed); - if !(_assigned) then { - ERROR_1("Could not find area suitable for: %1 sending to default zone",_group); - [_group,(missionNamespace getVariable (GVAR(CommanderAreasParsed) select 0))] call FUNC(assignToArea); - }; - }; - }; + [_group, _areaAssigned, _assetType] call FUNC(commanderGroupHandler) }; SETVAR(_group,lastTimeChecked,CBA_missionTime); }; diff --git a/modules/headless_ai/functions/Main/fn_MapMarkers.sqf b/modules/headless_ai/functions/Main/fn_MapMarkers.sqf index 7f491718..f84f54de 100644 --- a/modules/headless_ai/functions/Main/fn_MapMarkers.sqf +++ b/modules/headless_ai/functions/Main/fn_MapMarkers.sqf @@ -4,17 +4,17 @@ GVAR(GroupMarkersPFH) = [{ { private _key = _x; _y params [ - "_group", - "_side", - "_leader", - "_groupcount", - "_task", - "_behaviour", - "_target", - "_position", - "_areaAssigned", - "_assetType", - ["_usedMarkers", [], [[]]] + /*1*/ "_group", + /*2*/ "_side", + /*3*/ "_leader", + /*4*/ "_groupcount", + /*5*/ "_task", + /*6*/ "_behaviour", + /*7*/ "_target", + /*8*/ "_position", + /*9*/ "_areaAssigned", + /*10*/ "_assetType", + /*11*/ ["_usedMarkers", [], [[]]] ]; if ( _group isEqualTo grpNull || @@ -163,17 +163,17 @@ GVAR(GroupMarkersPFH) = [{ _targetMarker ]; GVAR(markerTrackedGroups) set [_key, [ - _group, - _side, - _leader, - _groupcount, - _task, - _behaviour, - _target, - _position, - _areaAssigned, - _assetType, - _usedMarkers + /*1*/ _group, + /*2*/ _side, + /*3*/ _leader, + /*4*/ _groupcount, + /*5*/ _task, + /*6*/ _behaviour, + /*7*/ _target, + /*8*/ _position, + /*9*/ _areaAssigned, + /*10*/ _assetType, + /*11*/ _usedMarkers ]] } } forEach GVAR(markerTrackedGroups); diff --git a/modules/headless_ai/functions/SightAidSM/fn_SA_onSEEnemyInRange.sqf b/modules/headless_ai/functions/SightAidSM/fn_SA_onSEEnemyInRange.sqf index 5c461b48..e1472cb8 100644 --- a/modules/headless_ai/functions/SightAidSM/fn_SA_onSEEnemyInRange.sqf +++ b/modules/headless_ai/functions/SightAidSM/fn_SA_onSEEnemyInRange.sqf @@ -4,7 +4,7 @@ params ["_unit"]; private _enemyInRange = []; -private _enemyArray = group _unit call FUNC(EnemyArray); +private _enemyArray = side _unit call FUNC(EnemyArray); if (_enemyArray isNotEqualTo []) then { _enemyInRange = _enemyArray select { vehicle _unit distance2d _x <= GETMVAR(SightAidDistance,600) && diff --git a/modules/headless_ai/preInitGlobal.sqf b/modules/headless_ai/preInitGlobal.sqf index 227fb5e4..8aaab80b 100644 --- a/modules/headless_ai/preInitGlobal.sqf +++ b/modules/headless_ai/preInitGlobal.sqf @@ -154,6 +154,16 @@ TRACE_1("",GVAR(CommanderAreas)); //exit clients AI_EXEC_CHECK(HC); +GVAR(bluforEnemies) = [opfor, independent] select { + [blufor, _x] call BIS_fnc_sideIsEnemy +}; +GVAR(opforEnemies) = [blufor, independent] select { + [opfor, _x] call BIS_fnc_sideIsEnemy +}; +GVAR(indforEnemies) = [blufor, opfor] select { + [independent, _x] call BIS_fnc_sideIsEnemy +}; + [QGVAR(HCReceiveArrayDataEvent), { LOG_1("Received Array Data: %1",_this); GVAR(zoneEntities) = createHashMap; diff --git a/modules/headless_ai/settings.hpp b/modules/headless_ai/settings.hpp index 1215e8dd..55e9c78b 100644 --- a/modules/headless_ai/settings.hpp +++ b/modules/headless_ai/settings.hpp @@ -7,7 +7,7 @@ of reinforcements or subsequent AOs. // Array objects // eg: ["mainEnemy", "patrol_1", "patrol_2", "patrol_3"] -arrayObjects[] = {"hc_spawn"}; +arrayObjects[] = {"hc_1", "hc_2", "hc_3"}; // Initial spawns are spawned upon init, at the start of the mission. // eg: ["mainEnemy"] diff --git a/modules/headless_ai/settings/commander.hpp b/modules/headless_ai/settings/commander.hpp index b2ecfe01..49c280c4 100644 --- a/modules/headless_ai/settings/commander.hpp +++ b/modules/headless_ai/settings/commander.hpp @@ -1,5 +1,5 @@ // AI commander options -WIP -feature = false; +feature = true; debug = true; side = "east"; //"Random" "Aggressive" "Defensive" "Guerilla" "Probing" @@ -25,9 +25,9 @@ assignStartZone = true; // Optional array elements: terrain manual define, QRF support for contact encountered in the area, minimum assets to assign for the area, asset threshold for the area (if threshold to assign cannot be met area will not be considered), maximum assets to assign for the area (leftover groups will be assigned to areas that aligns with preferred asset types), preferred asset types. // Preferred asset types will be determined from terrain setting if not manually defined. class Areas { - class Hangars { - marker = "area1"; - mission = "defend"; + class Town { + marker = "town"; + mission = "Defend"; minAssets = 1; maxAssets = 2; threshold = 0; @@ -38,8 +38,16 @@ class Areas { preferedTypes[] = {"Infantry", "Snipers"}; terrainMode = "Auto"; }; - class Runway: Hangars { - marker = "area2"; - mission = "patrol"; + class Hill: Town { + marker = "hill"; + mission = "Patrol"; + withdrawal = true; + }; + class Hill_1: Town { + marker = "hill_1"; + mission = "Ambush"; + withdrawal = true; + qrfSupport = false; + assetSupport = false; }; }; diff --git a/modules/headless_ai/settings/sight.hpp b/modules/headless_ai/settings/sight.hpp index c9c5d5c1..d321f757 100644 --- a/modules/headless_ai/settings/sight.hpp +++ b/modules/headless_ai/settings/sight.hpp @@ -22,7 +22,7 @@ usesmoke = false; // Do AI use UGLs forced by the statemachine? forceUGLs = true; // What percentage chance does the AI have in using a ugl? -UGLChance = 99; +UGLChance = 15; // What distance does the AI need to be within to use a ugl? UGLMaxRange = 200; // What distance does the AI need to be outside of to use a ugl? @@ -31,7 +31,7 @@ UGLMinRange = 50; // Do AI use launchers forced by the statemachine? forceAT = true; // What percentage chance does the AI have in using a laucnher? -ATChance = 99; +ATChance = 10; // What distance does the AI need to be within to use a laucnher? ATMaxRange = 300; // What distance does the AI need to be outside of to use a laucnher? From dbca5e242673fe3c5152028a16381bcca4d7e544 Mon Sep 17 00:00:00 2001 From: PiZZAD0X Date: Tue, 10 Jan 2023 22:12:08 -0800 Subject: [PATCH 04/19] cache hasRadio values for optimization --- .../functions/Diag/fn_HasRadioGroup.sqf | 16 ++++++++++++---- .../functions/Misc/fn_initPostMan.sqf | 7 +++++++ modules/headless_ai/preInitGlobal.sqf | 3 +++ 3 files changed, 22 insertions(+), 4 deletions(-) diff --git a/modules/headless_ai/functions/Diag/fn_HasRadioGroup.sqf b/modules/headless_ai/functions/Diag/fn_HasRadioGroup.sqf index c1b45b40..7db600a3 100644 --- a/modules/headless_ai/functions/Diag/fn_HasRadioGroup.sqf +++ b/modules/headless_ai/functions/Diag/fn_HasRadioGroup.sqf @@ -1,13 +1,21 @@ #include "script_component.hpp" - params [["_group", grpNull, [grpNull]]]; -private _return = (units _group) select { +if (_group isEqualTo grpNull) exitWith { + [false, -1] +}; + +private _units = units _group; +private _return = _units select { alive _x && {!(_x getVariable ["ACE_isUnconscious", false])} } findIf { - [_x] call acre_api_fnc_hasRadio + GETVAR(_x,hasRadio,false) }; -[_return isNotEqualTo -1, _return] +if (_return isEqualTo -1) then { + [false, []] +} else { + [true, _units select _return] +}; diff --git a/modules/headless_ai/functions/Misc/fn_initPostMan.sqf b/modules/headless_ai/functions/Misc/fn_initPostMan.sqf index 20f73e24..b56b2e7d 100644 --- a/modules/headless_ai/functions/Misc/fn_initPostMan.sqf +++ b/modules/headless_ai/functions/Misc/fn_initPostMan.sqf @@ -38,3 +38,10 @@ private _init = GETVAR(_unit,init,false); if (_init isEqualType {}) then { _unit call _init; }; + +private _acreItems = uniqueUnitItems _unit; +private _hasRadio = (GVAR(acreRadiosArray) findIf { + _x in _acreItems +}) isNotEqualTo -1; +TRACE_2("radio check",_unit,_hasRadio); +SETVAR(_unit,hasRadio,_hasRadio); diff --git a/modules/headless_ai/preInitGlobal.sqf b/modules/headless_ai/preInitGlobal.sqf index 8aaab80b..ca254fb1 100644 --- a/modules/headless_ai/preInitGlobal.sqf +++ b/modules/headless_ai/preInitGlobal.sqf @@ -164,6 +164,9 @@ GVAR(indforEnemies) = [blufor, opfor] select { [independent, _x] call BIS_fnc_sideIsEnemy }; +private _acreRadios = [] call ACRE_api_fnc_getallradios; +GVAR(acreRadiosArray) = (_acreRadios select 0) + (_acreRadios select 1); + [QGVAR(HCReceiveArrayDataEvent), { LOG_1("Received Array Data: %1",_this); GVAR(zoneEntities) = createHashMap; From 8d08f7ff40ba51714da17254095e4d9ef69c1038 Mon Sep 17 00:00:00 2001 From: PiZZAD0X Date: Tue, 10 Jan 2023 23:45:59 -0800 Subject: [PATCH 05/19] HC unit track fix for some units that have longer EH times --- core/functions/fn_eventSpawned.sqf | 18 +++++++---- core/functions/fn_untrackUnit.sqf | 29 +++++++++++++----- core/preinitServer.sqf | 28 ++++++++--------- .../headless_ai/functions/CfgFunctions.hpp | 2 +- .../functions/Combat/fn_RadioReportThreat.sqf | 6 ---- .../Commander/fn_RadioReportThreat.sqf | 5 ++++ .../functions/Diag/fn_ClosestEnemy.sqf | 15 ++++++---- .../functions/Main/fn_GroupHandler.sqf | 30 ++++++++++++------- .../functions/Misc/fn_deleteVehicles.sqf | 17 ++++++----- .../SightAidSM/fn_SA_OnSECombatMode.sqf | 4 +-- modules/headless_ai/settings.hpp | 2 +- 11 files changed, 97 insertions(+), 59 deletions(-) delete mode 100644 modules/headless_ai/functions/Combat/fn_RadioReportThreat.sqf create mode 100644 modules/headless_ai/functions/Commander/fn_RadioReportThreat.sqf diff --git a/core/functions/fn_eventSpawned.sqf b/core/functions/fn_eventSpawned.sqf index 982f4adc..945af97c 100644 --- a/core/functions/fn_eventSpawned.sqf +++ b/core/functions/fn_eventSpawned.sqf @@ -19,8 +19,9 @@ params ["_unit"]; SETPVAR(_unit,Side,(side _unit)); if ( - (isPlayer _unit || - {!(GETVAR(_unit,DontTrack,false))}) && + !isNull _unit && + {isPlayer _unit || + {!(GETVAR(_unit,DontTrack,false))}} && {!(GETVAR(_unit,Tracked,false))} ) then { SETPVAR(_unit,Tracked,true); @@ -29,12 +30,17 @@ if ( _x params ["_name", "_side", "_type", "_total", "_current"]; if ( ((GETVAR(_unit,Side,sideUnknown)) isEqualto _side) && - {(isPlayer _unit && {_type != "ai"}) || {_type == "ai"}} + { + (isPlayer _unit && {_type != "ai"}) || + {!isPlayer _unit && {_type == "ai"}} + } ) exitWith { if (_unit call FUNC(isAlive)) then { - TRACE_3("Setting new alive count",_unit,_total,_current); - _x set [3, _total + 1]; - _x set [4, _current + 1]; + private _newCurrent = _current + 1; + private _newTotal = _total + 1; + TRACE_3("Setting new alive count",_unit,_newTotal,_newCurrent); + _x set [3, _newTotal]; + _x set [4, _newCurrent]; }; }; }; diff --git a/core/functions/fn_untrackUnit.sqf b/core/functions/fn_untrackUnit.sqf index 1cfa71d1..7faacbf9 100644 --- a/core/functions/fn_untrackUnit.sqf +++ b/core/functions/fn_untrackUnit.sqf @@ -14,18 +14,33 @@ #include "script_component.hpp" -params ["_unit"]; +params ["_unit", ["_forcedSide", sideEmpty, [sideEmpty]]]; -if (GETVAR(_unit,Tracked,false)) then { +TRACE_2("untrackUnit",_unit,_forced); +private _forced = _forcedSide isNotEqualTo sideEmpty; + +if (GETVAR(_unit,Tracked,false) || {_forced}) then { GVAR(Teams) apply { _x params ["", "_side", "_type", "_total", "_current"]; if ( - ((_unit getVariable [QGVAR(Side), sideEmpty]) isEqualTo _side) && - {(((_type != "ai") && {isPlayer _unit}) || (_type == "ai"))} + ( + (GETVAR(_unit,Side,sideUnknown)) isEqualto _side || + {_forced && {_forcedSide isEqualto _side}} + ) && + { + (isPlayer _unit && {_type != "ai"} )|| + {!isPlayer _unit && {_type == "ai"}} + } ) exitWith { - if (_unit call FUNC(isAlive)) then { - _x set [3, _total - 1]; - _x set [4, _current - 1]; + if ( + _forced || + {_unit call FUNC(isAlive)} + ) then { + private _newCurrent = _current - 1; + private _newTotal = _total - 1; + TRACE_3("Setting new alive count",_unit,_newTotal,_newCurrent); + _x set [3, _newTotal]; + _x set [4, _newCurrent]; }; }; }; diff --git a/core/preinitServer.sqf b/core/preinitServer.sqf index 23eca9cb..41e01ca6 100644 --- a/core/preinitServer.sqf +++ b/core/preinitServer.sqf @@ -8,25 +8,25 @@ GVAR(MissionEnded) = false; //Mission has not ended [QGVAR(spawnedEvent), { params ["_unit"]; - //LOG_1("spawnedEvent started: %1",_unit); + TRACE_1("spawned Event",_unit); _unit call FUNC(eventSpawned); }] call CBA_fnc_addEventHandler; [QGVAR(untrackEvent), { - params ["_unit"]; - //LOG_1("untrackEvent started: %1",_unit); - _unit call FUNC(untrackUnit); + params ["_unit", ["_forced", sideEmpty, [sideEmpty]]]; + TRACE_2("untrack Event",_unit,_forced); + [_unit, _forced] call FUNC(untrackUnit); }] call CBA_fnc_addEventHandler; [QGVAR(killedEvent), { params [["_unit", objNull, [objNull]], ["_killer", objNull, [objNull]]]; - //LOG_1("killedevent started: %1",_unit); + TRACE_2("killed Event",_unit,_killer); [_unit, _killer] call FUNC(EventKilled); }] call CBA_fnc_addEventHandler; [QGVAR(respawnEvent), { params [["_unit", objNull, [objNull]], ["_spectator", false, [false]]]; - LOG_2("respawnEvent started: %1 spectator: %2",_unit,_spectator); + TRACE_2("respawnEvent started",_unit,_spectator); [_unit, _spectator] call FUNC(EventRespawned); }] call CBA_fnc_addEventHandler; @@ -168,8 +168,8 @@ if (isClass (missionConfigFile >> QGVAR(serverSettings) >> "Teams" >> "west")) t GVAR(EndScreenDisplay_West) = ([missionConfigFile >> QGVAR(serverSettings) >> "Teams" >> "west" >> "endScreenDisplay", "number", 1] call CBA_fnc_getConfigEntry) isEqualTo 1; private _westTeam = [ west, - [missionConfigFile >> QGVAR(serverSettings) >> "Teams" >> "west" >> "name", "string", "USMC"] call CBA_fnc_getConfigEntry, - [missionConfigFile >> QGVAR(serverSettings) >> "Teams" >> "west" >> "type", "string", "player"] call CBA_fnc_getConfigEntry + [missionConfigFile >> QGVAR(serverSettings) >> "Teams" >> "west" >> "name", "STRING", "USMC"] call CBA_fnc_getConfigEntry, + [missionConfigFile >> QGVAR(serverSettings) >> "Teams" >> "west" >> "type", "STRING", "player"] call CBA_fnc_getConfigEntry ]; _westTeam call FUNC(AddTeam); }; @@ -177,8 +177,8 @@ if (isClass (missionConfigFile >> QGVAR(serverSettings) >> "Teams" >> "east")) t GVAR(EndScreenDisplay_East) = ([missionConfigFile >> QGVAR(serverSettings) >> "Teams" >> "east" >> "endScreenDisplay", "number", 1] call CBA_fnc_getConfigEntry) isEqualTo 1; private _eastTeam = [ east, - [missionConfigFile >> QGVAR(serverSettings) >> "Teams" >> "east" >> "name", "string", "VDV"] call CBA_fnc_getConfigEntry, - [missionConfigFile >> QGVAR(serverSettings) >> "Teams" >> "east" >> "type", "string", "ai"] call CBA_fnc_getConfigEntry + [missionConfigFile >> QGVAR(serverSettings) >> "Teams" >> "east" >> "name", "STRING", "VDV"] call CBA_fnc_getConfigEntry, + [missionConfigFile >> QGVAR(serverSettings) >> "Teams" >> "east" >> "type", "STRING", "ai"] call CBA_fnc_getConfigEntry ]; _eastTeam call FUNC(AddTeam); }; @@ -186,8 +186,8 @@ if (isClass (missionConfigFile >> QGVAR(serverSettings) >> "Teams" >> "independe GVAR(EndScreenDisplay_Ind) = ([missionConfigFile >> QGVAR(serverSettings) >> "Teams" >> "independent" >> "endScreenDisplay", "number", 1] call CBA_fnc_getConfigEntry) isEqualTo 1; private _indTeam = [ independent, - [missionConfigFile >> QGVAR(serverSettings) >> "Teams" >> "independent" >> "name", "string", "Local Militia"] call CBA_fnc_getConfigEntry, - [missionConfigFile >> QGVAR(serverSettings) >> "Teams" >> "independent" >> "type", "string", "ai"] call CBA_fnc_getConfigEntry + [missionConfigFile >> QGVAR(serverSettings) >> "Teams" >> "independent" >> "name", "STRING", "Local Militia"] call CBA_fnc_getConfigEntry, + [missionConfigFile >> QGVAR(serverSettings) >> "Teams" >> "independent" >> "type", "STRING", "ai"] call CBA_fnc_getConfigEntry ]; _indTeam call FUNC(AddTeam); }; @@ -195,8 +195,8 @@ if (isClass (missionConfigFile >> QGVAR(serverSettings) >> "Teams" >> "civilian" GVAR(EndScreenDisplay_Civ) = ([missionConfigFile >> QGVAR(serverSettings) >> "Teams" >> "civilian" >> "endScreenDisplay", "number", 1] call CBA_fnc_getConfigEntry) isEqualTo 1; private _civTeam = [ civilian, - [missionConfigFile >> QGVAR(serverSettings) >> "Teams" >> "civilian" >> "name", "string", "Local Civilians"] call CBA_fnc_getConfigEntry, - [missionConfigFile >> QGVAR(serverSettings) >> "Teams" >> "civilian" >> "type", "string", "ai"] call CBA_fnc_getConfigEntry + [missionConfigFile >> QGVAR(serverSettings) >> "Teams" >> "civilian" >> "name", "STRING", "Local Civilians"] call CBA_fnc_getConfigEntry, + [missionConfigFile >> QGVAR(serverSettings) >> "Teams" >> "civilian" >> "type", "STRING", "ai"] call CBA_fnc_getConfigEntry ]; _civTeam call FUNC(AddTeam); }; diff --git a/modules/headless_ai/functions/CfgFunctions.hpp b/modules/headless_ai/functions/CfgFunctions.hpp index 5ba94539..a14ed917 100644 --- a/modules/headless_ai/functions/CfgFunctions.hpp +++ b/modules/headless_ai/functions/CfgFunctions.hpp @@ -55,7 +55,6 @@ class COMPONENT { class PlaceMine {}; class RadioCallForSupport {}; class RadioCommsEnemy {}; - class RadioReportThreat {}; class ReinforcementResponse {}; class FireWeapon {}; class SuppressDirection {}; @@ -72,6 +71,7 @@ class COMPONENT { class CommanderHandler {}; class CommanderGroupHandler {}; class CommanderInit {}; + class RadioReportThreat {}; }; class create { diff --git a/modules/headless_ai/functions/Combat/fn_RadioReportThreat.sqf b/modules/headless_ai/functions/Combat/fn_RadioReportThreat.sqf deleted file mode 100644 index 389c037e..00000000 --- a/modules/headless_ai/functions/Combat/fn_RadioReportThreat.sqf +++ /dev/null @@ -1,6 +0,0 @@ -#include "script_component.hpp" - - -params ["_groupcaller", "_enemycaller", "_sidecaller"]; - - diff --git a/modules/headless_ai/functions/Commander/fn_RadioReportThreat.sqf b/modules/headless_ai/functions/Commander/fn_RadioReportThreat.sqf new file mode 100644 index 00000000..90093978 --- /dev/null +++ b/modules/headless_ai/functions/Commander/fn_RadioReportThreat.sqf @@ -0,0 +1,5 @@ +#include "script_component.hpp" + +params ["_group", "_target"]; + +TRACE_2("reporting threat",_group,_target); diff --git a/modules/headless_ai/functions/Diag/fn_ClosestEnemy.sqf b/modules/headless_ai/functions/Diag/fn_ClosestEnemy.sqf index 59fe3980..6d35bfae 100644 --- a/modules/headless_ai/functions/Diag/fn_ClosestEnemy.sqf +++ b/modules/headless_ai/functions/Diag/fn_ClosestEnemy.sqf @@ -1,14 +1,19 @@ #include "script_component.hpp" -params ["_unit", ["_randomSelect", false, [false]]]; +params [ + ["_unit", objNull, [objNull]], + ["_randomSelect", false, [false]] +]; -private _enemyArray = [side _unit] call FUNC(EnemyArray); +if (_unit isEqualTo objNull) exitwith {objNull}; -if (_enemyArray isEqualTo []) exitwith {objnull}; +private _enemyArray = [side _unit] call FUNC(EnemyArray); +if (_enemyArray isEqualTo []) exitwith {objNull}; private _distanceArray = _enemyArray select { - [_x] call EFUNC(FW,isAlive) + !isNull _x && + {[_x] call EFUNC(FW,isAlive)} } apply { private _enemyDistance = _unit distance2d _x; [_enemyDistance, _x] @@ -17,7 +22,7 @@ private _distanceArray = _enemyArray select { _distanceArray sort true; private _selectIndex = if (_randomSelect) then { - random ((count _distanceArray) / 2) + floor random (count _distanceArray / 2) } else { 0 }; diff --git a/modules/headless_ai/functions/Main/fn_GroupHandler.sqf b/modules/headless_ai/functions/Main/fn_GroupHandler.sqf index 9f10a1c7..26b12f4d 100644 --- a/modules/headless_ai/functions/Main/fn_GroupHandler.sqf +++ b/modules/headless_ai/functions/Main/fn_GroupHandler.sqf @@ -36,7 +36,7 @@ GVAR(GroupHandlerPFH) = [{ }; if (_target isEqualTo objNull && {assignedTarget _leader isNotEqualTo objNull}) then { TRACE_2("set target on active group",_group,_target); - _target = leader (assignedTarget _leader); + _target = assignedTarget _leader; if (_target isEqualTo objNull) then { private _targetCounter = GETVAR(_group,NullTargetCounter,0); if (_targetCounter >= 5) then { @@ -77,9 +77,13 @@ GVAR(GroupHandlerPFH) = [{ ]] }; if (CBA_missionTime >= _lastTimeChecked + 3) then { - private _inCombat = (_behaviour in ["COMBAT","STEALTH"]) && {!(GETVAR(_group,taskCombatModeSet,false))}; - //TRACE_2("inCombat check",_group,_inCombat); - if (_inCombat || {(_target isNotEqualTo objnull)}) then { + if ( + ( + _behaviour in ["COMBAT","STEALTH"] && + {!(GETVAR(_group,taskCombatModeSet,false))} + ) || + {_target isNotEqualTo objnull} + ) then { //switch tasks on actions //handle for special loiter task - regroup if (_task isEqualTo "LOITER") then { @@ -93,17 +97,23 @@ GVAR(GroupHandlerPFH) = [{ }; //radio for help if ((GETMVAR(RadioDistance,2000)) > 0) then { - if (!(GETMVAR(RadioNeedRadio,false)) || {(_group call FUNC(hasRadioGroup)) select 0}) then { + if ( + !(GETMVAR(RadioNeedRadio,false)) || + {(_group call FUNC(hasRadioGroup)) select 0} + ) then { private _radioWait = GETMVAR(RadioWait,30); private _lastCallTime = GETVAR(_group,LastCallTime,(CBA_MissionTime - _radioWait)); - if (CBA_MissionTime >= (_LastCallTime + _radioWait) && {!(GETVAR(_group,Reinforcing,false))}) then { + if ( + CBA_MissionTime >= (_LastCallTime + _radioWait) && + {!(GETVAR(_group,Reinforcing,false))} + ) then { TRACE_1("radio call for support",_group); SETVAR(_group,LastCallTime,CBA_MissionTime); - //if (GVAR(CommanderEnabled)) then { - // [_group,_target,_side] call FUNC(RadioReportThreat); - //} else { + if (GVAR(CommanderEnabled)) then { + [_group,_target] call FUNC(RadioReportThreat); + } else { [_group,_target,_side] call FUNC(RadioCallForSupport); - //}; + }; }; }; }; diff --git a/modules/headless_ai/functions/Misc/fn_deleteVehicles.sqf b/modules/headless_ai/functions/Misc/fn_deleteVehicles.sqf index 50983015..ee25da14 100644 --- a/modules/headless_ai/functions/Misc/fn_deleteVehicles.sqf +++ b/modules/headless_ai/functions/Misc/fn_deleteVehicles.sqf @@ -3,18 +3,21 @@ params ["_arr"]; -{ +_arr apply { private _vehicle = _x; - if (!(_vehicle isKindOf "Logic") && {!isNull _vehicle}) then { - if (EGETVAR(_vehicle,FW,Tracked,false)) then { - [QEGVAR(FW,untrackEvent), [_vehicle]] call CBA_fnc_serverEvent; - }; + if ( + !(_vehicle isKindOf "Logic") && + {!isNull _vehicle} + ) then { + private _tracked = EGETVAR(_vehicle,FW,Tracked,false); + TRACE_2("deleting HC Synced object",_vehicle, _tracked); + TRACE_2("deleting HC Synced tracked",_vehicle, side _vehicle); + [QEGVAR(FW,untrackEvent), [_vehicle, side _vehicle]] call CBA_fnc_serverEvent; { private _object = _x; detach _object; deleteVehicle _object; } foreach attachedObjects _vehicle; deleteVehicle _vehicle; - deleteGroup (group _vehicle); }; -} forEach _arr; +}; diff --git a/modules/headless_ai/functions/SightAidSM/fn_SA_OnSECombatMode.sqf b/modules/headless_ai/functions/SightAidSM/fn_SA_OnSECombatMode.sqf index 799496a2..6506b35c 100644 --- a/modules/headless_ai/functions/SightAidSM/fn_SA_OnSECombatMode.sqf +++ b/modules/headless_ai/functions/SightAidSM/fn_SA_OnSECombatMode.sqf @@ -14,10 +14,10 @@ if (_distance > GETMVAR(SightAidDistance,600)) exitwith {}; private _knowsabouttarget = _unit knowsabout _enemyTarget; private _cansee = [objNull, "VIEW"] checkVisibility [eyePos _Unit, eyePos _enemyTarget]; if (_knowsabouttarget < 4) then { - if ((_cansee > 0.6) && {(_distance < GETMVAR(SightAidEngageDistance,200))}) then { + if (_cansee > 0.6 && {_distance < GETMVAR(SightAidEngageDistance,200)}) then { _unit reveal [_enemyTarget, 4]; } else { - if (_cansee > 0.05) then { + if (_cansee > 0.6) then { private _revealValue = linearConversion [100, GETMVAR(SightAidDistance,600), _distance, 4, GETMVAR(SightAidMinIncrease,1)]; _unit reveal [_enemyTarget, _knowsabouttarget + _revealValue]; if (GETMVAR(UseMarkers,false)) then { diff --git a/modules/headless_ai/settings.hpp b/modules/headless_ai/settings.hpp index 55e9c78b..1bcf8771 100644 --- a/modules/headless_ai/settings.hpp +++ b/modules/headless_ai/settings.hpp @@ -7,7 +7,7 @@ of reinforcements or subsequent AOs. // Array objects // eg: ["mainEnemy", "patrol_1", "patrol_2", "patrol_3"] -arrayObjects[] = {"hc_1", "hc_2", "hc_3"}; +arrayObjects[] = {"hc_1", "hc_2", "hc_3", "hc_4"}; // Initial spawns are spawned upon init, at the start of the mission. // eg: ["mainEnemy"] From b6168b49ff12a5f4f100fc8faec315564a2e84e6 Mon Sep 17 00:00:00 2001 From: PiZZAD0X Date: Fri, 13 Jan 2023 09:40:19 -0800 Subject: [PATCH 06/19] getGrenades optimization --- .../functions/Diag/fn_getGrenades.sqf | 41 ++++++++++++++----- .../functions/Diag/fn_getStance.sqf | 10 ++--- .../functions/set/fn_setStance.sqf | 2 +- 3 files changed, 37 insertions(+), 16 deletions(-) diff --git a/modules/headless_ai/functions/Diag/fn_getGrenades.sqf b/modules/headless_ai/functions/Diag/fn_getGrenades.sqf index 34077367..76637920 100644 --- a/modules/headless_ai/functions/Diag/fn_getGrenades.sqf +++ b/modules/headless_ai/functions/Diag/fn_getGrenades.sqf @@ -2,17 +2,38 @@ params ["_unit"]; -private _frags = []; -private _smokes = []; +if (isNil QGVAR(grenadeTypeNamespace)) then { + GVAR(grenadeTypeNamespace) = createHashMap; +}; -magazines _unit select { - _x call BIS_fnc_isThrowable && - {_x isKindOf ["HandGrenade", configFile >> "CfgMagazines"]} -} apply { - if (_x isKindOf ["SmokeShell", configFile >> "CfgMagazines"]) then { - _smokes pushBack _x - } else { - _frags pushBack _x +private _fncIsGrenadeType = { + params ["_type"]; + private _return = GVAR(grenadeTypeNamespace) getOrDefault [_type, -2]; + if (_return isEqualTo -2) then { + if ( + _type call BIS_fnc_isThrowable && + {_type isKindOf ["HandGrenade", configFile >> "CfgMagazines"]} + ) then { + _return = [1,2] select (_type isKindOf ["SmokeShell", configFile >> "CfgMagazines"]); + } else { + _return = -1; + }; + GVAR(grenadeTypeNamespace) set [_type, _return]; + }; + _return +}; + + +private _smokes = []; +private _frags = []; +magazines _unit apply { + private _gType = _x call _fncIsGrenadeType; + if (_gType isNotEqualTo -1) then { + if (_gType isEqualTo 2) then { + _smokes pushBack _x; + } else { + _frags pushBack _x; + }; }; }; diff --git a/modules/headless_ai/functions/Diag/fn_getStance.sqf b/modules/headless_ai/functions/Diag/fn_getStance.sqf index fa11250b..084a782f 100644 --- a/modules/headless_ai/functions/Diag/fn_getStance.sqf +++ b/modules/headless_ai/functions/Diag/fn_getStance.sqf @@ -2,11 +2,11 @@ params ["_stance"]; -private _return = switch (_stance) do { - case "STAND": {"UP";}; - case "CROUCH": {"MIDDLE";}; - case "PRONE": {"DOWN";}; - case "Auto": {"Auto"}; +private _return = switch (toLower _stance) do { + case "stand": {"UP";}; + case "crouch": {"MIDDLE";}; + case "prone": {"DOWN";}; + case "auto": {"Auto"}; default {"Auto"}; }; diff --git a/modules/headless_ai/functions/set/fn_setStance.sqf b/modules/headless_ai/functions/set/fn_setStance.sqf index 0b2665f0..3a38befb 100644 --- a/modules/headless_ai/functions/set/fn_setStance.sqf +++ b/modules/headless_ai/functions/set/fn_setStance.sqf @@ -9,7 +9,7 @@ params [ //LOG_1("setstance: %1",_this); TRACE_3("setstance",_unit,_groupStance,_unitStance); -private _stance = if ((_groupStance != "Auto") && {_unitStance == "Auto"}) then { +private _stance = if (_unitStance == "Auto") then { _groupStance } else { _unitStance From 793b2e175ed0d2fae6756b21205cacbbe76575b1 Mon Sep 17 00:00:00 2001 From: PiZZAD0X Date: Mon, 20 Feb 2023 13:56:26 -0700 Subject: [PATCH 07/19] unitStance machine stance value comparison fix --- modules/headless_ai/functions/UnitStanceSM/StateMachine.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/headless_ai/functions/UnitStanceSM/StateMachine.hpp b/modules/headless_ai/functions/UnitStanceSM/StateMachine.hpp index 4b124b4d..ca3c5c77 100644 --- a/modules/headless_ai/functions/UnitStanceSM/StateMachine.hpp +++ b/modules/headless_ai/functions/UnitStanceSM/StateMachine.hpp @@ -5,7 +5,7 @@ class GVAR(unitStanceStateMachine) { local _x && \ {!isPlayer _x} && \ {QGETVAR(_x,spawned,false)} && \ - {(QGETVAR(_x,stance,'') isEqualTo '') && {(QGETVAR(group _x,stance,'') isEqualTo '')}} && \ + {(QGETVAR(_x,stance,'AUTO') == 'AUTO') && {(QGETVAR(group _x,stance,'AUTO') == 'AUTO')}} && \ {!(QGETVAR(_x,NOAI,false))} && \ {!([group _x] call FUNC(isMoveTask))} && \ {(vehicle _x isEqualTo _x)} \ From 014022206efb8f895cbea4c9f32b3080d6bb72a8 Mon Sep 17 00:00:00 2001 From: PiZZAD0X Date: Mon, 20 Feb 2023 14:15:53 -0700 Subject: [PATCH 08/19] group stance check on unit setStance func call --- modules/headless_ai/functions/create/fn_createUnit.sqf | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/headless_ai/functions/create/fn_createUnit.sqf b/modules/headless_ai/functions/create/fn_createUnit.sqf index 4bd4b53d..3bed30c7 100644 --- a/modules/headless_ai/functions/create/fn_createUnit.sqf +++ b/modules/headless_ai/functions/create/fn_createUnit.sqf @@ -67,8 +67,8 @@ if (_storedVars isNotEqualTo []) then { _unit setvariable [_varName,_varValue]; }; }; - -if (_stance isNotEqualTo "AUTO") then { +private _groupStance = GETVAR(group _unit,stance,"AUTO"); +if (_stance != "AUTO" || {_groupStance != "AUTO"}) then { SETVAR(_unit,stance,_stance); }; if (_identity isNotEqualTo []) then { From 523b40122b3d1edd0f83445ac63b25df04cfd6b0 Mon Sep 17 00:00:00 2001 From: PiZZAD0X Date: Thu, 9 Mar 2023 09:00:38 -0700 Subject: [PATCH 09/19] commander AI threat detect and reporting --- .../headless_ai/functions/CfgFunctions.hpp | 1 - .../Combat/fn_RadioCallForSupport.sqf | 12 +- .../Commander/fn_CommanderGroupHandler.sqf | 106 ------ .../Commander/fn_CommanderHandler.sqf | 331 +++++++++++++++++- .../Commander/fn_RadioReportThreat.sqf | 59 +++- .../Diag/fn_nearbyFriendlyEntities.sqf | 2 +- .../functions/Main/fn_GroupHandler.sqf | 119 +++---- .../functions/Main/fn_initMain.sqf | 9 +- .../functions/task/fn_taskRelease.sqf | 3 +- .../functions/task/fn_taskStationary.sqf | 6 +- 10 files changed, 447 insertions(+), 201 deletions(-) delete mode 100644 modules/headless_ai/functions/Commander/fn_CommanderGroupHandler.sqf diff --git a/modules/headless_ai/functions/CfgFunctions.hpp b/modules/headless_ai/functions/CfgFunctions.hpp index a14ed917..ac334fde 100644 --- a/modules/headless_ai/functions/CfgFunctions.hpp +++ b/modules/headless_ai/functions/CfgFunctions.hpp @@ -69,7 +69,6 @@ class COMPONENT { file = "modules\headless_ai\functions\Commander"; class assignToArea {}; class CommanderHandler {}; - class CommanderGroupHandler {}; class CommanderInit {}; class RadioReportThreat {}; }; diff --git a/modules/headless_ai/functions/Combat/fn_RadioCallForSupport.sqf b/modules/headless_ai/functions/Combat/fn_RadioCallForSupport.sqf index c95193c1..c29812d1 100644 --- a/modules/headless_ai/functions/Combat/fn_RadioCallForSupport.sqf +++ b/modules/headless_ai/functions/Combat/fn_RadioCallForSupport.sqf @@ -1,13 +1,12 @@ #include "script_component.hpp" - params ["_groupcaller", ["_enemycaller", objnull, [objnull]]]; -private _sidecaller = side _groupcaller; +private _sideCaller = side _groupcaller; private _posCaller = getposATL leader _groupcaller; if (GVAR(Debug)) then { - TRACE_3("radiocomms params",_groupcaller,_enemycaller,_sidecaller); + TRACE_3("radiocomms params",_groupcaller,_enemycaller,_sideCaller); }; private _respondingInfantry = []; @@ -33,9 +32,10 @@ if (_knownEnemy) then { allGroups select { private _leader = leader _x; (GETVAR(_x,Spawned,false)) && - {(_groupcaller isNotEqualTo _x)} && + {_sideCaller isEqualTo side _leader} && + {_groupcaller isNotEqualTo _x} && {!(isNull _leader)} && - {(alive _leader)} && + {_leader call EFUNC(FW,isAlive)} && {!(GETVAR(_leader,NOAI,false))} && {!(isPlayer _leader)} && {!([_x] call FUNC(isInCombat))} && @@ -54,7 +54,7 @@ allGroups select { private _target = GETVAR(_group,CurrentTarget,objnull); private _distanceToGroup = (leader _groupcaller) distance2d _leader; if ( - ([_sidecaller, _side] call BIS_fnc_sideIsFriendly) && + ([_sideCaller, _side] call BIS_fnc_sideIsFriendly) && {!_knownEnemy || {_target isEqualTo objnull} || {!(_target in _nearbyEnemy)}} && {_distanceToGroup <= GVAR(RadioDistance)} && {!(GETMVAR(RadioNeedRadio,false)) || {(_group call FUNC(hasRadioGroup)) select 0}} diff --git a/modules/headless_ai/functions/Commander/fn_CommanderGroupHandler.sqf b/modules/headless_ai/functions/Commander/fn_CommanderGroupHandler.sqf deleted file mode 100644 index 599e3cec..00000000 --- a/modules/headless_ai/functions/Commander/fn_CommanderGroupHandler.sqf +++ /dev/null @@ -1,106 +0,0 @@ -#include "script_component.hpp" - -params [ - ["_group", grpNull, [grpNull]], - ["_areaAssigned", "NONE", [""]], - ["_assetType", "Infantry", [""]] -]; - -//commander handling -if (_areaAssigned isEqualTo "NONE") then { - //check zones for assignments - private _assigned = false; - if (GETMVAR(CommanderAssignStartZone,false)) then { - private _index = GVAR(CommanderAreasParsed) findIf { - private _namespace = missionNamespace getVariable _x; - private _marker = GETVAR(_namespace,marker,""); - leader _group inArea _marker - }; - if (_index isNotEqualTo -1) then { - private _namespace = missionNamespace getVariable (GVAR(CommanderAreasParsed) select _index); - private _displayName = GETVAR(_namespace,displayName,""); - private _max = GETVAR(_namespace,max,10); - private _assignedAssets = GETVAR(_namespace,assignedAssets,[]); - private _assetCount = count _assignedAssets; - private _controlStatus = GETVAR(_namespace,control,"Unknown"); - private _preferredTypes = GETVAR(_namespace,preferredTypes,"ALL"); - if ( - (_assetCount < _max) && - {!_assigned} && - {!(_controlStatus in ["EnemyControlled", "Contested"])} && - {(_assetType in _preferredTypes) || (_preferredTypes isEqualTo ["ALL"])} - ) then { - LOG_2("Sending group %1 to area %2",_group,_displayName); - _assigned = true; - [_group,_namespace] call FUNC(assignToArea); - }; - }; - } else { - { - private _namespace = missionNamespace getVariable _x; - private _displayName = GETVAR(_namespace,displayName,""); - //private _mission = GETVAR(_namespace,mission,"Patrol"); - //private _marker = GETVAR(_namespace,marker,""); - //private _min = GETVAR(_namespace,min,0); - private _max = GETVAR(_namespace,max,10); - //private _threshold = GETVAR(_namespace,threshold,1); - //private _QRFSupport = GETVAR(_namespace,QRFSupport,true); - //private _assetSupport = GETVAR(_namespace,assetSupport,true); - //private _withdrawalEnabled = GETVAR(_namespace,withdrawalEnabled,true); - //private _resourceUse = GETVAR(_namespace,resourceUse,true); - private _preferredTypes = GETVAR(_namespace,preferredTypes,"ALL"); - //private _terrainMode = GETVAR(_namespace,terrainMode,"Auto"); - //private _importance = GETVAR(_namespace,importance,_forEachIndex); - private _assignedAssets = GETVAR(_namespace,assignedAssets,[]); - private _controlStatus = GETVAR(_namespace,control,"Unknown"); - private _assetCount = count _assignedAssets; - //LOG_3("Area: %1 _assetCount: %2 _max: %3",_displayName,_assetCount,_max); - if ( - (_assetCount < _max) && - {!_assigned} && - {!(_controlStatus in ["EnemyControlled", "Contested"])} && - {(_assetType in _preferredTypes) || (_preferredTypes isEqualTo ["ALL"])} - ) then { - LOG_2("Sending group %1 to area %2",_group,_displayName); - _assigned = true; - [_group,_namespace] call FUNC(assignToArea); - }; - } foreach GVAR(CommanderAreasParsed); - }; - if !(_assigned) then { - ERROR_1("Could not find area suitable for: %1 type %2 ignoring preferred types",_group,_assetType); - { - private _namespace = missionNamespace getVariable _x; - private _displayName = GETVAR(_namespace,displayName,""); - //private _mission = GETVAR(_namespace,mission,"Patrol"); - //private _marker = GETVAR(_namespace,marker,""); - //private _min = GETVAR(_namespace,min,0); - private _max = GETVAR(_namespace,max,10); - //private _threshold = GETVAR(_namespace,threshold,1); - //private _QRFSupport = GETVAR(_namespace,QRFSupport,true); - //private _assetSupport = GETVAR(_namespace,assetSupport,true); - //private _withdrawalEnabled = GETVAR(_namespace,withdrawalEnabled,true); - //private _resourceUse = GETVAR(_namespace,resourceUse,true); - //private _preferredTypes = GETVAR(_namespace,preferredTypes,"ALL"); - //private _terrainMode = GETVAR(_namespace,terrainMode,"Auto"); - //private _importance = GETVAR(_namespace,importance,_forEachIndex); - private _assignedAssets = GETVAR(_namespace,assignedAssets,[]); - private _controlStatus = GETVAR(_namespace,control,"Unknown"); - private _assetCount = count _assignedAssets; - //LOG_3("Area: %1 _assetCount: %2 _max: %3",_marker,_assetCount,_max); - if ( - (_assetCount < _max) && - {!_assigned} && - {!(_controlStatus in ["EnemyControlled", "Contested"])} - ) then { - LOG_2("Sending group %1 to area %2",_group,_displayName); - _assigned = true; - [_group,_namespace] call FUNC(assignToArea); - }; - } foreach GVAR(CommanderAreasParsed); - if !(_assigned) then { - ERROR_1("Could not find area suitable for: %1 sending to default zone",_group); - [_group,(missionNamespace getVariable (GVAR(CommanderAreasParsed) select 0))] call FUNC(assignToArea); - }; - }; -}; diff --git a/modules/headless_ai/functions/Commander/fn_CommanderHandler.sqf b/modules/headless_ai/functions/Commander/fn_CommanderHandler.sqf index 6c2bc18b..0c176e0a 100644 --- a/modules/headless_ai/functions/Commander/fn_CommanderHandler.sqf +++ b/modules/headless_ai/functions/Commander/fn_CommanderHandler.sqf @@ -3,8 +3,119 @@ LOG("Starting CommanderHandler Function"); GVAR(AreaMarkerArray) = []; +GVAR(CommanderThreats) = []; -GVAR(CommanderAreasHandlerPFH) = [{ +GVAR(CommanderHandlerPFH) = [{ + // Handle Assets (groups) + { + private _group = _x; + private _assetType = GETVAR(_group,assetType,"NONE"); + if (_assetType isEqualTo "NONE") then { + _assetType = "Infantry"; + }; + private _areaAssigned = GETVAR(_group,areaAssigned,"NONE"); + if (_areaAssigned isEqualTo "NONE") then { + //check zones for assignments + private _assigned = false; + if ( + (GETMVAR(CommanderAssignStartZone,false)) && + { + GVAR(CommanderAreasParsed) findIf { + private _namespace = missionNamespace getVariable _x; + private _marker = GETVAR(_namespace,marker,""); + leader _group inArea _marker + } isNotEqualTo -1 + } + ) then { + private _namespace = missionNamespace getVariable (GVAR(CommanderAreasParsed) select _index); + private _displayName = GETVAR(_namespace,displayName,""); + private _max = GETVAR(_namespace,max,10); + private _assignedAssets = GETVAR(_namespace,assignedAssets,[]); + private _assetCount = count _assignedAssets; + private _controlStatus = GETVAR(_namespace,control,"Unknown"); + private _preferredTypes = GETVAR(_namespace,preferredTypes,"ALL"); + if ( + (_assetCount < _max) && + {!_assigned} && + {!(_controlStatus in ["EnemyControlled", "Contested"])} && + {(_assetType in _preferredTypes) || (_preferredTypes isEqualTo ["ALL"])} + ) then { + LOG_2("Sending group %1 to area %2",_group,_displayName); + _assigned = true; + [_group,_namespace] call FUNC(assignToArea); + }; + } else { + { + private _namespace = missionNamespace getVariable _x; + private _displayName = GETVAR(_namespace,displayName,""); + //private _mission = GETVAR(_namespace,mission,"Patrol"); + //private _marker = GETVAR(_namespace,marker,""); + //private _min = GETVAR(_namespace,min,0); + private _max = GETVAR(_namespace,max,10); + //private _threshold = GETVAR(_namespace,threshold,1); + //private _QRFSupport = GETVAR(_namespace,QRFSupport,true); + //private _assetSupport = GETVAR(_namespace,assetSupport,true); + //private _withdrawalEnabled = GETVAR(_namespace,withdrawalEnabled,true); + //private _resourceUse = GETVAR(_namespace,resourceUse,true); + private _preferredTypes = GETVAR(_namespace,preferredTypes,"ALL"); + //private _terrainMode = GETVAR(_namespace,terrainMode,"Auto"); + //private _importance = GETVAR(_namespace,importance,_forEachIndex); + private _assignedAssets = GETVAR(_namespace,assignedAssets,[]); + private _controlStatus = GETVAR(_namespace,control,"Unknown"); + private _assetCount = count _assignedAssets; + //LOG_3("Area: %1 _assetCount: %2 _max: %3",_displayName,_assetCount,_max); + if ( + (_assetCount < _max) && + {!_assigned} && + {!(_controlStatus in ["EnemyControlled", "Contested"])} && + {(_assetType in _preferredTypes) || (_preferredTypes isEqualTo ["ALL"])} + ) then { + LOG_2("Sending group %1 to area %2",_group,_displayName); + _assigned = true; + [_group,_namespace] call FUNC(assignToArea); + }; + } foreach GVAR(CommanderAreasParsed); + }; + if !(_assigned) then { + ERROR_1("Could not find area suitable for: %1 type %2 ignoring preferred types",_group,_assetType); + { + private _namespace = missionNamespace getVariable _x; + private _displayName = GETVAR(_namespace,displayName,""); + //private _mission = GETVAR(_namespace,mission,"Patrol"); + //private _marker = GETVAR(_namespace,marker,""); + //private _min = GETVAR(_namespace,min,0); + private _max = GETVAR(_namespace,max,10); + //private _threshold = GETVAR(_namespace,threshold,1); + //private _QRFSupport = GETVAR(_namespace,QRFSupport,true); + //private _assetSupport = GETVAR(_namespace,assetSupport,true); + //private _withdrawalEnabled = GETVAR(_namespace,withdrawalEnabled,true); + //private _resourceUse = GETVAR(_namespace,resourceUse,true); + //private _preferredTypes = GETVAR(_namespace,preferredTypes,"ALL"); + //private _terrainMode = GETVAR(_namespace,terrainMode,"Auto"); + //private _importance = GETVAR(_namespace,importance,_forEachIndex); + private _assignedAssets = GETVAR(_namespace,assignedAssets,[]); + private _controlStatus = GETVAR(_namespace,control,"Unknown"); + private _assetCount = count _assignedAssets; + //LOG_3("Area: %1 _assetCount: %2 _max: %3",_marker,_assetCount,_max); + if ( + (_assetCount < _max) && + {!_assigned} && + {!(_controlStatus in ["EnemyControlled", "Contested"])} + ) then { + LOG_2("Sending group %1 to area %2",_group,_displayName); + _assigned = true; + [_group,_namespace] call FUNC(assignToArea); + }; + } foreach GVAR(CommanderAreasParsed); + if !(_assigned) then { + ERROR_1("Could not find area suitable for: %1 sending to default zone",_group); + [_group,(missionNamespace getVariable (GVAR(CommanderAreasParsed) select 0))] call FUNC(assignToArea); + }; + }; + }; + + } forEach GVAR(CommanderAssets); + // Handle Areas { private _namespace = missionNamespace getVariable _x; private _displayName = GETVAR(_namespace,displayName,""); @@ -57,9 +168,9 @@ GVAR(CommanderAreasHandlerPFH) = [{ _debugMarkerName setMarkerSize (getMarkerSize _marker); _debugMarkerName setMarkerDir (markerDir _marker); _debugMarkerName setMarkerBrush "FDiagonal"; - _debugMarkerName setmarkercolor _markerColour; - _debugMarkerName setmarkerpos (getmarkerpos _marker); - _debugMarkerName setmarkeralpha 0.55; + _debugMarkerName setMarkerColor _markerColour; + _debugMarkerName setMarkerPos (getmarkerpos _marker); + _debugMarkerName setMarkerAlpha 0.55; private _debugMarkerBorderName = format ["PZAI_Area_M_%1_Border",_marker]; if !(_debugMarkerBorderName in GVAR(AreaMarkerArray)) then { private _markerAreaBorder = createMarker [_debugMarkerBorderName,[0,0]]; @@ -69,19 +180,221 @@ GVAR(CommanderAreasHandlerPFH) = [{ _debugMarkerBorderName setMarkerSize (getMarkerSize _marker); _debugMarkerBorderName setMarkerDir (markerDir _marker); _debugMarkerBorderName setMarkerBrush "Border"; - _debugMarkerBorderName setmarkercolor _markerColour; - _debugMarkerBorderName setmarkerpos (getmarkerpos _marker); - _debugMarkerBorderName setmarkeralpha 0.85; + _debugMarkerBorderName setMarkerColor _markerColour; + _debugMarkerBorderName setMarkerPos (getmarkerpos _marker); + _debugMarkerBorderName setMarkerAlpha 0.85; private _debugMarkerIconName = format ["PZAI_Area_M_%1_Icon",_marker]; if !(_debugMarkerIconName in GVAR(AreaMarkerArray)) then { private _markerAreaIcon = createMarker [_debugMarkerIconName,[0,0]]; GVAR(AreaMarkerArray) pushback _markerAreaIcon; }; - _debugMarkerIconName setmarkercolor _markerColour; + _debugMarkerIconName setMarkerColor _markerColour; _debugMarkerIconName setMarkerShape "ICON"; _debugMarkerIconName setMarkerType "hd_dot"; _debugMarkerIconName setMarkerPos (getmarkerpos _marker); _debugMarkerIconName setMarkerText (format ["Area: %1 Mission: %2 Assigned: %3 Control: %4 Importance: %5 Terrain: %6",_displayName,_mission,(count _assignedAssets),_controlStatus,_importance,_terrainMode]); }; - } foreach GVAR(CommanderAreasParsed); + } forEach GVAR(CommanderAreasParsed); + // Handle Threats + private _updatedThreats = []; + GVAR(CommanderThreats) apply { + _x params [ + ["_targetGroup", grpNull, [grpNull,[]]], + ["_targetMarkers", ["", ""], [[]]], + ["_reportedLocation", [0,0,0], [[]]], + ["_lastTimeUpdated", -1, [0]], + ["_enemyType", "Infantry", [""]], + ["_enemyInfantryCount", 0, [0]], + ["_enemyHasVehicles", false, [false]], + ["_enemyHasArmored", false, [false]], + ["_lastTimeAddressed", -1, [0]], + ["_threatPriority", -1, [0]], + ["_nearestArea", "", [""]] + ]; + _targetMarkers params [ + ["_areaMarker", "", [""]], + ["_textMarker", "", [""]] + ]; + private _groupMembers = if (_targetGroup isEqualType []) then { + private _tempCount = 0; + { + _tempCount = _tempCount + count units _x; + } forEach _targetGroup; + } else { + count units _targetGroup + }; + // remove empty/dead threats before iteration + if (_groupMembers == 0) then { + if ( + (_areaMarker isNotEqualTo "") && + {markerColor _areaMarker isNotEqualTo ""} + ) then { + deleteMarker _areaMarker; + deleteMarker _textMarker; + }; + } else { + // check for other nearby threats and combine + private _searchIndex = GVAR(CommanderThreats) findIf { + private _otherThreat = _x; + if (_otherThreat select 0 isEqualTo _targetGroup) then { + // exclude same group obviously + false + } else { + private _otherPos = _otherThreat select 2; + _reportedLocation distance2D _otherPos <= 50 + }; + }; + if (_searchIndex isNotEqualTo -1) then { + // "add" to other threat + (GVAR(CommanderThreats) select _searchIndex) params [ + ["_otherTargetGroup", grpNull, [grpNull, []]], + ["_otherTargetMarkers", "", [""]], + ["_otherReportedLocation", [0,0,0], [[]]], + ["_otherLastTimeUpdated", -1, [0]], + ["_otherEnemyType", "Infantry", [""]], + ["_otherEnemyInfantryCount", 0, [0]], + ["_otherEnemyHasVehicles", false, [false]], + ["_otherEnemyHasArmored", false, [false]], + ["_otherLastTimeAddressed", -1, [0]], + ["_otherThreatPriority", -1, [0]], + ["_otherNearestArea", "", [""]] + ]; + // delete one of the markers + if ( + (_areaMarker isNotEqualTo "") && + {markerColor _areaMarker isNotEqualTo ""} + ) then { + deleteMarker _areaMarker; + deleteMarker _textMarker; + }; + // _g + _g2 + // [] + _g2 + // _g + [] + // [] + [] + // merge groups/arrays of groups + if (_otherTargetGroup isEqualType grpNull) then { + if (_targetGroup isEqualType grpNull) then { + _targetGroup = [_targetGroup, _otherTargetGroup]; + } else { + _targetGroup pushBackUnique _otherTargetGroup; + }; + } else { + if (_targetGroup isEqualType grpNull) then { + _targetGroup = _otherTargetGroup + _targetGroup; + } else { + _targetGroup append _otherTargetGroup; + }; + }; + // get last updated time + if (_otherLastTimeUpdated > _lastTimeUpdated) then { + _lastTimeUpdated = _otherLastTimeUpdated; + }; + if (_otherLastTimeAddressed > _lastTimeAddressed) then { + _lastTimeAddressed = _otherLastTimeAddressed; + }; + // merge other values + _enemyInfantryCount = _enemyInfantryCount + _otherEnemyInfantryCount; + if (!_enemyHasVehicles && _otherEnemyHasVehicles) then { + _enemyHasVehicles = true; + }; + if (!_enemyHasArmored && _otherEnemyHasArmored) then { + _enemyHasArmored = true; + }; + // set values for other threat and do not add this threat to updated threat array + private _setArray = [ + _targetGroup, + _otherTargetMarkers, + _otherReportedLocation, + _lastTimeUpdated, + _otherEnemyType, + _enemyInfantryCount, + _enemyHasVehicles, + _enemyHasArmored, + _lastTimeAddressed, + _otherThreatPriority, + _otherNearestArea + ]; + TRACE_2("merged threats",_targetGroup,_otherTargetGroup); + GVAR(CommanderThreats) set [_searchIndex, _setArray]; + } else { + // iterate through threat + private _targetSide = side _targetGroup; + private _threatMarkerSize = if (_enemyHasArmored || _enemyHasVehicles) then { + "LARGE" + } else { + if (_enemyInfantryCount > 8) then { + "MEDIUM" + } else { + "SMALL" + }; + }; + // debug marker for threat + if (GETMVAR(CommanderDebug,false)) then { + private _size = switch _threatMarkerSize do { + case "LARGE": { + [15,15] + }; + case "MEDIUM": { + [8,8] + }; + default { + [3,3] + }; + }; + private _markerText = format [" Report: %1 at: %2 type: %3",_targetGroup,_lastTimeUpdated,_enemyType]; + if ( + (_areaMarker isEqualTo "") || + markerColor _areaMarker isEqualTo "" + ) then { + // create marker + private _markerColour = switch (_targetSide) do { + case west: {"ColorBlue"}; + case east: {"ColorRed"}; + case independent: {"ColorGreen"}; + case civilian: {"ColorYellow"}; + default {"ColorBlack"}; + }; + private _areaMarker = format ["report_area_%1",_targetGroup]; + createMarker [_areaMarker, [0,0]]; + _areaMarker setMarkerShapeLocal "ELLIPSE"; + _areaMarker setMarkerBrushLocal "Border"; + _areaMarker setMarkerSizeLocal _size; + _areaMarker setMarkerColorLocal _markerColour; + _areaMarker setMarkerPos _reportedLocation; + + private _textMarker = format ["report_text_%1",_targetGroup]; + createMarker [_textMarker, [0,0]]; + _textMarker setMarkerShapeLocal "ICON"; + _textMarker setMarkerTypeLocal "mil_objective"; + _textMarker setMarkerSizeLocal [0.5,0.5]; + _textMarker setMarkerColorLocal _markerColour; + _textMarker setMarkerTextLocal _markerText; + _textMarker setMarkerPos _reportedLocation; + } else { + // update marker + _areaMarker setMarkerTextLocal _markerText; + _areaMarker setMarkerSizeLocal _size; + _areaMarker setMarkerPos _reportedLocation; + _textMarker setMarkerPos _reportedLocation; + }; + }; + private _setArray = [ + _targetGroup, + [_areaMarker, _textMarker], + _reportedLocation, + _lastTimeUpdated, + _enemyType, + _enemyInfantryCount, + _enemyHasVehicles, + _enemyHasArmored, + _lastTimeAddressed, + _threatPriority, + _nearestArea + ]; + _updatedThreats pushBack _setArray; + }; + }; + }; + //update GVAR with updated array + GVAR(CommanderThreats) = _updatedThreats; }, 3] call CBA_fnc_addPerFrameHandler; diff --git a/modules/headless_ai/functions/Commander/fn_RadioReportThreat.sqf b/modules/headless_ai/functions/Commander/fn_RadioReportThreat.sqf index 90093978..1ab2be1c 100644 --- a/modules/headless_ai/functions/Commander/fn_RadioReportThreat.sqf +++ b/modules/headless_ai/functions/Commander/fn_RadioReportThreat.sqf @@ -1,5 +1,60 @@ #include "script_component.hpp" -params ["_group", "_target"]; +params [ + ["_callerGroup", grpNull, [grpNull]], + ["_target", objNull, [objNull]] +]; -TRACE_2("reporting threat",_group,_target); +if (_callerGroup isEqualTo objNull || _target isEqualTo objNull) exitWith {}; + +private _callerSide = side leader _callerGroup; +private _targetGroup = group _target; + +//IGNORE_PRIVATE_WARNING ["_x"] +private _nearbyEnemy = []; +_nearbyEnemy = [_target, 50] call FUNC(nearbyFriendlyEntities); +_nearbyEnemy params [ + ["_nearbyInfantry", [], [[]]], + ["_nearbyCars", [], [[]]], + ["_nearbyAPCs", [], [[]]], + ["_nearbyTanks", [], [[]]] +]; +private _enemyInfantryCount = count _nearbyInfantry; +private _enemyHasVehicles = _nearbyCars isNotEqualTo [] || + {_nearbyAPCs isNotEqualTo []} || + {_nearbyTanks isNotEqualTo []}; +private _enemyHasArmored = _enemyHasVehicles && + {(_nearbyAPCs isNotEqualTo []) || + {(_nearbyTanks isNotEqualTo [])} +}; +private _reportedLocation = [_nearbyEnemy select 0, 30] call CBA_fnc_randPos; +private _lastTimeUpdated = CBA_MissionTime; +private _enemyType = "Infantry"; + +private _threatArray = [ + _targetGroup, /* threat group */ + ["",""], /* threat debug markers */ + _reportedLocation, + _lastTimeUpdated, + _enemyType, + _enemyInfantryCount, + _enemyHasVehicles, + _enemyHasArmored +]; + +private _searchIndex = GVAR(CommanderThreats) findIf { + private _group = _x select 0; + if (_group isEqualType []) then { + _targetGroup in _group + } else { + _group isEqualTo _targetGroup + }; +}; + +if (_searchIndex isEqualTo -1) then { + GVAR(CommanderThreats) pushBackUnique _threatArray +} else { + GVAR(CommanderThreats) set [_searchIndex, _threatArray]; +}; + +TRACE_2("reporting threat",_callerGroup,_threatArray); diff --git a/modules/headless_ai/functions/Diag/fn_nearbyFriendlyEntities.sqf b/modules/headless_ai/functions/Diag/fn_nearbyFriendlyEntities.sqf index 63139e10..50c7b10b 100644 --- a/modules/headless_ai/functions/Diag/fn_nearbyFriendlyEntities.sqf +++ b/modules/headless_ai/functions/Diag/fn_nearbyFriendlyEntities.sqf @@ -31,7 +31,7 @@ private _nearbyInfantry = _list select { }; private _nearbyCars = _list select { side _x isEqualTo side _unit && - {_x isKindOf "CAManBase"} + {_x isKindOf "Car"} }; private _nearbyAPCs = _list select { side _x isEqualTo side _unit && diff --git a/modules/headless_ai/functions/Main/fn_GroupHandler.sqf b/modules/headless_ai/functions/Main/fn_GroupHandler.sqf index 26b12f4d..77be7f09 100644 --- a/modules/headless_ai/functions/Main/fn_GroupHandler.sqf +++ b/modules/headless_ai/functions/Main/fn_GroupHandler.sqf @@ -24,68 +24,24 @@ GVAR(GroupHandlerPFH) = [{ private _groupcount = count _aliveUnits; private _behaviour = behaviour _leader; private _target = GETVAR(_group,CurrentTarget,objNull); - if ( - _target isNotEqualTo objNull && - { - assignedTarget _leader isEqualTo objNull || - {!(_target call EFUNC(FW,isAlive))} - } - ) then { - _target = objNull; - SETVAR(_group,CurrentTarget,objNull); - }; - if (_target isEqualTo objNull && {assignedTarget _leader isNotEqualTo objNull}) then { - TRACE_2("set target on active group",_group,_target); - _target = assignedTarget _leader; - if (_target isEqualTo objNull) then { - private _targetCounter = GETVAR(_group,NullTargetCounter,0); - if (_targetCounter >= 5) then { - TRACE_1("no longer in combat, exiting and resetting",_group); - SETVAR(_group,NullTargetCounter,0); - private _originalBeh = GETVAR(_group,behaviour,"AWARE"); - private _originalCM = GETVAR(_group,combatMode,"YELLOW"); - private _originalSpeed = GETVAR(_group,speed,"normal"); - private _originalForm = GETVAR(_group,formation,"wedge"); - [_group,_originalBeh,_originalCM,_originalSpeed,_originalForm] call FUNC(setGroupBehaviour); - private _originalTask = GETVAR(_group,OriginalTask,"PATROL"); - private _originalPos = GETVAR(_group,Pos,getPos leader _group); - private _originalRadius = GETVAR(_group,taskRadius,30); - [_group,_originalTask,_originalPos,_originalRadius] call FUNC(taskAssign); - } else { - _targetCounter = _targetCounter + 1; - SETVAR(_group,NullTargetCounter,_targetCounter); - }; - } else { - SETVAR(_group,CurrentTarget,_target); + if (assignedTarget _leader isEqualTo objNull) then { + // reset target to objNull + if (_target isNotEqualTo objNull) then { + _target = objNull; + SETVAR(_group,CurrentTarget,objNull); }; + // reset back to original task? } else { - SETVAR(_group,NullTargetCounter,0); - }; - if (GETMVAR(UseMarkers,false)) then { - //TRACE_2("",GVAR(markerTrackedGroups),str _group); - GVAR(markerTrackedGroups) set [str _group, [ - _group, - _side, - _leader, - _groupcount, - _task, - _behaviour, - _target, - _position, - _areaAssigned, - _assetType - ]] - }; - if (CBA_missionTime >= _lastTimeChecked + 3) then { if ( - ( - _behaviour in ["COMBAT","STEALTH"] && - {!(GETVAR(_group,taskCombatModeSet,false))} - ) || - {_target isNotEqualTo objnull} + _target isEqualTo objNull && + {!(_target call EFUNC(FW,isAlive))} ) then { - //switch tasks on actions - //handle for special loiter task - regroup + TRACE_2("set target on active group",_group,_target); + _target = assignedTarget _leader; + SETVAR(_group,CurrentTarget,_target); + // react + // switch tasks on actions + // handle for special loiter task - regroup if (_task isEqualTo "LOITER") then { _group setSpeedMode "FULL"; _units apply {_x setUnitPos "Auto"; _x doFollow _leader}; @@ -104,12 +60,15 @@ GVAR(GroupHandlerPFH) = [{ private _radioWait = GETMVAR(RadioWait,30); private _lastCallTime = GETVAR(_group,LastCallTime,(CBA_MissionTime - _radioWait)); if ( - CBA_MissionTime >= (_LastCallTime + _radioWait) && + CBA_MissionTime >= (_lastCallTime + _radioWait) && {!(GETVAR(_group,Reinforcing,false))} ) then { TRACE_1("radio call for support",_group); SETVAR(_group,LastCallTime,CBA_MissionTime); - if (GVAR(CommanderEnabled)) then { + if ( + GVAR(CommanderEnabled) && + {side _group isEqualTo (GETMVAR(CommanderSide,east))} + ) then { [_group,_target] call FUNC(RadioReportThreat); } else { [_group,_target,_side] call FUNC(RadioCallForSupport); @@ -122,19 +81,41 @@ GVAR(GroupHandlerPFH) = [{ private _lastWaypointTime = GETVAR(_group,lastWaypointTime,CBA_MissionTime - 3); private _currentWaypoint = currentWaypoint _group; private _waypoints = waypoints _group; - if (_currentWaypoint > (count _waypoints - 1) && {(_group getVariable [QGVAR(Task), "PATROL"]) isEqualTo "MANUAL"}) then { + if ( + _currentWaypoint > (count _waypoints - 1) && + {(_group getVariable [QGVAR(Task), "PATROL"]) isEqualTo "MANUAL"} + ) then { [_group, _position] call FUNC(taskPatrol); }; }; }; - if ( - (GETMVAR(CommanderEnabled,false)) && - {!(GETVAR(_group,CommanderExempt,false))} && - {side _group isEqualTo (GETMVAR(CommanderSide,east))} - ) then { - [_group, _areaAssigned, _assetType] call FUNC(commanderGroupHandler) - }; - SETVAR(_group,lastTimeChecked,CBA_missionTime); + // no enemy detected - what do? + }; + if (GETMVAR(UseMarkers,false)) then { + //TRACE_2("",GVAR(markerTrackedGroups),str _group); + GVAR(markerTrackedGroups) set [str _group, [ + _group, + _side, + _leader, + _groupcount, + _task, + _behaviour, + _target, + _position, + _areaAssigned, + _assetType + ]] + }; + // AI Commander + if ( + (GETMVAR(CommanderEnabled,false)) && + {!(GETVAR(_group,CommanderExempt,false))} && + {side _group isEqualTo (GETMVAR(CommanderSide,east))} && + {!(_group in GVAR(CommanderAssets))} + ) then { + // add to commander asset array + GVAR(CommanderAssets) pushBackUnique _group; }; + SETVAR(_group,lastTimeChecked,CBA_missionTime); }; }, 1] call CBA_fnc_addPerFrameHandler; diff --git a/modules/headless_ai/functions/Main/fn_initMain.sqf b/modules/headless_ai/functions/Main/fn_initMain.sqf index 887bcc81..f7f544af 100644 --- a/modules/headless_ai/functions/Main/fn_initMain.sqf +++ b/modules/headless_ai/functions/Main/fn_initMain.sqf @@ -28,14 +28,15 @@ if (GVAR(stanceFeature)) then { //Main Functions [{ - [] call FUNC(GroupHandler); - if (GETMVAR(UseMarkers,false)) then { - [] call FUNC(MapMarkers); - }; //Commander Functions if (GVAR(CommanderEnabled)) then { + GVAR(CommanderAssets) = []; [] call FUNC(CommanderInit); }; + [] call FUNC(GroupHandler); + if (GETMVAR(UseMarkers,false)) then { + [] call FUNC(MapMarkers); + }; }, []] call CBA_fnc_execNextFrame; //Spawns initial HC arrays diff --git a/modules/headless_ai/functions/task/fn_taskRelease.sqf b/modules/headless_ai/functions/task/fn_taskRelease.sqf index efe55335..e7cf52c4 100644 --- a/modules/headless_ai/functions/task/fn_taskRelease.sqf +++ b/modules/headless_ai/functions/task/fn_taskRelease.sqf @@ -4,7 +4,8 @@ params ["_group"]; LOG_1("freeing %1",_group); -(units _group) apply { +units _group apply { _x forcespeed -1; _x enableAI "Path"; + SETVAR(_x,stationary,false); }; diff --git a/modules/headless_ai/functions/task/fn_taskStationary.sqf b/modules/headless_ai/functions/task/fn_taskStationary.sqf index e7c6b8f8..54cad97f 100644 --- a/modules/headless_ai/functions/task/fn_taskStationary.sqf +++ b/modules/headless_ai/functions/task/fn_taskStationary.sqf @@ -21,8 +21,10 @@ _group setCombatMode _combat; _group setSpeedMode _speed; _group setFormation _formation; private _units = units _group; -{ +_units apply { _x doWatch ((getPosATL _x) vectorAdd((vectorDir _x) vectorMultiply 100)); _x disableAI "PATH"; -} foreach _units; + SETVAR(_x,stationary,true); +}; + SETVAR(_group,Task,"STATIONARY"); From b042426c72b491e683cd4945aa473f0326cc79cd Mon Sep 17 00:00:00 2001 From: PiZZAD0X Date: Thu, 9 Mar 2023 12:54:02 -0700 Subject: [PATCH 10/19] group map marker dead/null group check --- .../functions/Main/fn_MapMarkers.sqf | 110 ++++++++++-------- 1 file changed, 60 insertions(+), 50 deletions(-) diff --git a/modules/headless_ai/functions/Main/fn_MapMarkers.sqf b/modules/headless_ai/functions/Main/fn_MapMarkers.sqf index f84f54de..35f51d10 100644 --- a/modules/headless_ai/functions/Main/fn_MapMarkers.sqf +++ b/modules/headless_ai/functions/Main/fn_MapMarkers.sqf @@ -18,8 +18,9 @@ GVAR(GroupMarkersPFH) = [{ ]; if ( _group isEqualTo grpNull || - {leader _group isEqualTo objNull} || - {!alive leader _group} + { + (units _group) findIf {_x call EFUNC(FW,isAlive)} isEqualTo -1 + } ) then { GVAR(markerTrackedGroups) deleteAt _key; if (_usedMarkers isNotEqualTo []) then { @@ -55,20 +56,6 @@ GVAR(GroupMarkersPFH) = [{ _tracker setMarkerColor _markercolour; }; _tracker setMarkerPos [getpos _leader select 0, getpos _leader select 1]; - private _usedest = _task in [ - "PATROL", - "PERIMPATROL", - "SENTRY", - "ATTACK", - "ASSAULT", - "FLANK", - "MOVE", - "MANUAL", - "BLDMOVE", - "BLDSEARCH", - "PICKUP", - "DROPOFF" - ]; private _usetarget = _target isNotEqualTo objnull; if !(_usetarget) then { _target = "NONE"; @@ -94,41 +81,64 @@ GVAR(GroupMarkersPFH) = [{ }; //LOG_1("MarkerText: %1",_text); _tracker setMarkerText _text; - if (_usedest) then { - if (_dest isEqualTo "") then { - _dest = format["dest_%1_%2",_side,_group]; - createMarker [_dest,[0,0]]; - _dest setMarkerShape "ICON"; - _dest setMarkerType "mil_marker"; - _dest setMarkerSize [0.25,0.25]; - _dest setmarkercolor _markercolour; - _destline = format ["destline_%1_%2",_side,_group]; - createMarker [_destline,[0,0]]; - _destline setMarkerShape "RECTANGLE"; - _destline setMarkerBrush "SOLID"; - _destline setmarkercolor _markercolour; - }; - private _wpArray = waypoints _group; - private _wppos = [0,0,0]; - if (_wpArray isNotEqualTo []) then { - private _wpindex = currentWaypoint _group; - _wppos = waypointPosition [_group,_wpindex]; - _dest setmarkerpos _wppos; + // find appropriate dest waypoint, if any + if (_task in [ + "PATROL", + "PERIMPATROL", + "SENTRY", + "ATTACK", + "ASSAULT", + "FLANK", + "MOVE", + "MANUAL", + "BLDMOVE", + "BLDSEARCH", + "PICKUP", + "DROPOFF" + ]) then { + private _groupWPs = waypoints _group; + if (_groupWPs isEqualTo []) then { + if (_dest isNotEqualTo "") then { + deletemarker _dest; + deletemarker _destline; + _dest = ""; + _destline = ""; + }; } else { - _dest setmarkerpos [0,0]; - }; - private _dist = (_position distance2D _wppos) / 2; - private _ang = _position getDir _wppos; - private _center = _position getPos [_dist, _ang]; - _destline setMarkerSize [1,_dist]; - _destline setMarkerDir _ang; - _destline setMarkerPos _center; - } else { - if (_dest isNotEqualTo "") then { - deletemarker _dest; - deletemarker _destline; - _dest = ""; - _destline = ""; + private _currentWP = currentWaypoint _group; + private _wpPos = waypointPosition [_group, _currentWP]; + if ( + _currentWP >= count _groupWPs && + {_wpPos isEqualTo [0,0,0]} + ) then { + if (_dest isNotEqualTo "") then { + deletemarker _dest; + deletemarker _destline; + _dest = ""; + _destline = ""; + }; + } else { + if (_dest isEqualTo "") then { + _dest = format["dest_%1_%2", _side, _group]; + createMarker [_dest, [0, 0]]; + _dest setMarkerShapeLocal "ICON"; + _dest setMarkerTypeLocal "mil_marker"; + _dest setMarkerSizeLocal [0.25, 0.25]; + _dest setMarkerColorLocal _markercolour; + _destline = format ["destline_%1_%2", _side, _group]; + createMarker [_destline, [0, 0]]; + _destline setMarkerShapeLocal "RECTANGLE"; + _destline setMarkerBrushLocal "SOLID"; + _destline setMarkerColorLocal _markercolour; + }; + _dest setMarkerPos _wpPos; + private _dist = (_position distance2D _wppos) / 2; + private _ang = _position getDir _wppos; + private _center = _position getPos [_dist, _ang]; + _destline setMarkerSizeLocal [1, _dist]; + _destline setMarkerDirLocal _ang; + _destline setMarkerPos _center; + }; }; }; if (_usetarget) then { From 7585acf638754e308d892506a413ff390f3874f6 Mon Sep 17 00:00:00 2001 From: PiZZAD0X Date: Thu, 9 Mar 2023 15:52:24 -0700 Subject: [PATCH 11/19] garrison task --- .../functions/Combat/fn_CombatGarrison.sqf | 50 +++++++++++++++---- .../functions/Get/fn_getBuildings.sqf | 11 ++-- .../functions/Main/fn_initMain.sqf | 2 +- .../functions/UnitStanceSM/StateMachine.hpp | 1 + .../functions/task/fn_taskGarrison.sqf | 21 +++++--- 5 files changed, 64 insertions(+), 21 deletions(-) diff --git a/modules/headless_ai/functions/Combat/fn_CombatGarrison.sqf b/modules/headless_ai/functions/Combat/fn_CombatGarrison.sqf index a7e9ee50..151170b9 100644 --- a/modules/headless_ai/functions/Combat/fn_CombatGarrison.sqf +++ b/modules/headless_ai/functions/Combat/fn_CombatGarrison.sqf @@ -3,25 +3,55 @@ params [ "_group", "_pos", - ["_radius",100,[0]] + ["_radius", 100, [0]], + ["_buildings", [], [[]]] ]; -//[_group, _pos, _radius] call CBA_fnc_taskDefend; +TRACE_2("Garrison Function:",_group,_buildings); -private _blgPos = [_pos, _radius, true] call FUNC(getBuildings); -private _firstPos = _blgPos select 0; +private _units = units _group select {!(INVEHICLE(_x))}; -doStop units _group; +private _allPositions = []; +_buildings apply { + (_x buildingPos -1) select {!(_x in GVAR(OccupiedPositions))} apply { + _allPositions pushBackUnique _x; + }; +}; +TRACE_2("Garrison Function:",count _units,count _allPositions); +private _largerSearch = true; -units _group select { - !(INVEHICLE(_x)) -} apply { - private _unitPos = if (_blgPos isEqualTo []) then {_firstPos} else {_blgPos deleteAt 0}; +_units apply { + if (_allPositions isEqualTo []) then { + TRACE_2("Ran out of positions",_group,_allPositions); + if !(_largerSearch) exitWith { + TRACE_1("Larger Search disabled, setting to misc defence for remaining units",_group); + }; + (nearestObjects [leader _group, ["House", "Strategic", "Ruins"], _radius * 3, true]) select { + ((_x buildingPos -1) select {!(_x in GVAR(OccupiedPositions))}) isNotEqualTo [] + } apply { + (_x buildingPos -1) select {!(_x in GVAR(OccupiedPositions))} apply { + _allPositions pushBackUnique _x; + }; + }; + TRACE_2("Ran larger search",_group,_allPositions); + }; + private _unit = _x; + private _pos = _allPositions deleteAt 0; + SETVAR(_unit,Busy,true); + GVAR(OccupiedPositions) pushBackUnique _pos; + doStop _unit; + TRACE_2("unit occupying position",_unit,_pos); [ { params ["_unit", "_pos"]; _unit moveTo _pos; _unit setDestination [_pos, "LEADER PLANNED", true]; - }, [_x, _unitPos], 0.5 + random 2 + [{ + (_this select 0) distance (_this select 1) <= 1 + }, { + params ["_unit", "_pos"]; + SETVAR(_unit,Busy,false); + }, [_unit, _pos]] call CBA_fnc_waitUntilAndExecute; + }, [_unit, _pos], 0.5 + random 2 ] call CBA_fnc_waitAndExecute; }; diff --git a/modules/headless_ai/functions/Get/fn_getBuildings.sqf b/modules/headless_ai/functions/Get/fn_getBuildings.sqf index c6843a4d..d67fdcd5 100644 --- a/modules/headless_ai/functions/Get/fn_getBuildings.sqf +++ b/modules/headless_ai/functions/Get/fn_getBuildings.sqf @@ -21,17 +21,20 @@ params [ ["_unit", objNull, [objNull, []]], ["_range", 100, [0]], + ["_excludeUsedHouses", false, [false]], ["_useHousePos", false, [false]], ["_onlyIndoor", false, [false]], ["_findDoors", false, [false]] ]; // houses -private _houses = nearestObjects [_unit, ["House", "Strategic", "Ruins"], _range, true]; -_houses = _houses select {((_x buildingPos -1) isNotEqualTo [])}; +private _houses = (nearestObjects [_unit, ["House", "Strategic", "Ruins"], _range, true]) select { + (_x buildingPos -1) isNotEqualTo [] +}; +if (!_useHousePos) exitWith {_houses}; // return if not use House Pos // find house positions -if (!_useHousePos) exitWith {_houses}; // return if not use House Pos + private _housePos = []; { private _house = _x; @@ -53,4 +56,4 @@ if (_onlyIndoor) then { }; }; // return -_housePos +[_housePos] diff --git a/modules/headless_ai/functions/Main/fn_initMain.sqf b/modules/headless_ai/functions/Main/fn_initMain.sqf index f7f544af..06594f46 100644 --- a/modules/headless_ai/functions/Main/fn_initMain.sqf +++ b/modules/headless_ai/functions/Main/fn_initMain.sqf @@ -5,7 +5,7 @@ GVAR(BasicCheckCurrent) = 0; GVAR(LeaderExecuteCurrent) = 0; GVAR(MarkerArray) = []; GVAR(markerTrackedGroups) = createHashMap; - +GVAR(OccupiedPositions) = []; //StateMachines LOG("creating bunkerStateMachine"); diff --git a/modules/headless_ai/functions/UnitStanceSM/StateMachine.hpp b/modules/headless_ai/functions/UnitStanceSM/StateMachine.hpp index ca3c5c77..57d5ed59 100644 --- a/modules/headless_ai/functions/UnitStanceSM/StateMachine.hpp +++ b/modules/headless_ai/functions/UnitStanceSM/StateMachine.hpp @@ -8,6 +8,7 @@ class GVAR(unitStanceStateMachine) { {(QGETVAR(_x,stance,'AUTO') == 'AUTO') && {(QGETVAR(group _x,stance,'AUTO') == 'AUTO')}} && \ {!(QGETVAR(_x,NOAI,false))} && \ {!([group _x] call FUNC(isMoveTask))} && \ + {!(QGETVAR(_x,Busy,false))} && \ {(vehicle _x isEqualTo _x)} \ }); skipNull = 1; diff --git a/modules/headless_ai/functions/task/fn_taskGarrison.sqf b/modules/headless_ai/functions/task/fn_taskGarrison.sqf index 1956d8cc..743fd9e4 100644 --- a/modules/headless_ai/functions/task/fn_taskGarrison.sqf +++ b/modules/headless_ai/functions/task/fn_taskGarrison.sqf @@ -11,14 +11,23 @@ params [ ["_formation", "NO CHANGE", [""]] ]; -private _buildings = _pos nearObjects ["Building", _radius]; -_buildings = _buildings select { - private _positions = _x buildingPos -1; - count _positions >= 3 +private _excludeClaimedHouses = true; +private _largerSearch = true; +private _houses = (nearestObjects [leader _group, ["House", "Strategic", "Ruins"], _radius, true]) select { + ((_x buildingPos -1) select {!(_x in GVAR(OccupiedPositions))}) isNotEqualTo [] && + {!_excludeClaimedHouses || !(GETVAR(_x,claimed,false))} }; -if (_buildings isNotEqualTo []) then { +if (_houses isEqualTo [] && _largerSearch) then { + _houses = (nearestObjects [leader _group, ["House", "Strategic", "Ruins"], _radius * 3, true]) select { + ((_x buildingPos -1) select {!(_x in GVAR(OccupiedPositions))}) isNotEqualTo [] && + {!_excludeClaimedHouses || !(GETVAR(_x,claimed,false))} + }; +}; +TRACE_2("Garrison Choice:",_group,_houses); + +if (_houses isNotEqualTo []) then { SETVAR(_group,Task,"GARRISON"); - [_group, _pos, _radius] call FUNC(combatGarrison); + [_group, _pos, _radius, _houses] call FUNC(combatGarrison); } else { SETVAR(_group,Task,"DEFEND"); [_group] call FUNC(combatDefend); From 2bca95a34a33dacfbf889d5edec46dab5b9d3b0c Mon Sep 17 00:00:00 2001 From: PiZZAD0X Date: Thu, 9 Mar 2023 19:11:18 -0700 Subject: [PATCH 12/19] insideBuilding check for stance --- .../functions/UnitStanceSM/fn_US_onSEUnitChecks.sqf | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/modules/headless_ai/functions/UnitStanceSM/fn_US_onSEUnitChecks.sqf b/modules/headless_ai/functions/UnitStanceSM/fn_US_onSEUnitChecks.sqf index 18aa042e..1de61052 100644 --- a/modules/headless_ai/functions/UnitStanceSM/fn_US_onSEUnitChecks.sqf +++ b/modules/headless_ai/functions/UnitStanceSM/fn_US_onSEUnitChecks.sqf @@ -18,12 +18,8 @@ if ( SETVAR(_unit,US_SetStance,true); //LOG_1("Set to MIDDLE",_unit); } else { - //LOG_1("stance: %1 failed middle check!",_unit); - if ([_unit, _unitDir, 1.7] call FUNC(checkView)) then { - _unit setUnitPos "UP"; - SETVAR(_unit,US_SetStance,true); - //LOG_1("Set to UP",_unit); - }; + _unit setUnitPos "UP"; + SETVAR(_unit,US_SetStance,true); }; } else { //LOG_1("stance: %1 was NOT prone!",_unit); @@ -31,6 +27,7 @@ if ( (stance _unit isEqualTo "CROUCH") && {!(GETVAR(_unit,reloading,false))} && {([_unit, _unitDir, 0.25] call FUNC(checkView))} + && {(insideBuilding _unit) > 0.5} ) then { //LOG_1("stance: %1 was crouched, can see prone!",_unit); _unit setUnitPos "DOWN"; From 1b10ca0219d582fe3e0584aaaced60731cb27a58 Mon Sep 17 00:00:00 2001 From: PiZZAD0X Date: Fri, 10 Mar 2023 09:20:26 -0700 Subject: [PATCH 13/19] determine closest area, rudimentary threat level calc --- .../Commander/fn_CommanderHandler.sqf | 32 +++++++++++++++++-- .../Commander/fn_RadioReportThreat.sqf | 2 +- modules/headless_ai/preInitClient.sqf | 2 +- modules/headless_ai/settings/commander.hpp | 12 +++---- 4 files changed, 36 insertions(+), 12 deletions(-) diff --git a/modules/headless_ai/functions/Commander/fn_CommanderHandler.sqf b/modules/headless_ai/functions/Commander/fn_CommanderHandler.sqf index 0c176e0a..bc723bce 100644 --- a/modules/headless_ai/functions/Commander/fn_CommanderHandler.sqf +++ b/modules/headless_ai/functions/Commander/fn_CommanderHandler.sqf @@ -59,7 +59,7 @@ GVAR(CommanderHandlerPFH) = [{ //private _resourceUse = GETVAR(_namespace,resourceUse,true); private _preferredTypes = GETVAR(_namespace,preferredTypes,"ALL"); //private _terrainMode = GETVAR(_namespace,terrainMode,"Auto"); - //private _importance = GETVAR(_namespace,importance,_forEachIndex); + private _importance = GETVAR(_namespace,importance,_forEachIndex); private _assignedAssets = GETVAR(_namespace,assignedAssets,[]); private _controlStatus = GETVAR(_namespace,control,"Unknown"); private _assetCount = count _assignedAssets; @@ -208,7 +208,7 @@ GVAR(CommanderHandlerPFH) = [{ ["_enemyHasVehicles", false, [false]], ["_enemyHasArmored", false, [false]], ["_lastTimeAddressed", -1, [0]], - ["_threatPriority", -1, [0]], + ["_threatLevel", -1, [0]], ["_nearestArea", "", [""]] ]; _targetMarkers params [ @@ -378,6 +378,32 @@ GVAR(CommanderHandlerPFH) = [{ _textMarker setMarkerPos _reportedLocation; }; }; + //detemine closest area + private _areaDistances = GVAR(CommanderAreasParsed) select { + private _namespace = missionNamespace getVariable _x; + !(GETVAR(_namespace,deactivated,false)) + } apply { + private _namespace = missionNamespace getVariable _x; + private _marker = GETVAR(_namespace,marker,""); + private _markerPos = getMarkerPos _marker; + private _importance = GETVAR(_namespace,importance,0); + [_reportedLocation distance2D _markerPos, _x, _importance] + }; + _areaDistances sort true; + _nearestArea = _areaDistances select 0 select 1; + private _importance = _areaDistances select 0 select 2; + TRACE_3("nearestArea calc",_targetGroup,_nearestArea,_importance); + // detemine effective threat level - threat equation + // threat level base (marker size calc) + importance of area zone (0 is highest) + private _size = switch _threatMarkerSize do { + case "LARGE": {15}; + case "MEDIUM": {8}; + default {3}; + }; + private _threatLevel = (_size select 0) + (10 - (_importance * 2)); + TRACE_2("threat level calc",_targetGroup,_threatLevel); + // address with assets + private _setArray = [ _targetGroup, [_areaMarker, _textMarker], @@ -388,7 +414,7 @@ GVAR(CommanderHandlerPFH) = [{ _enemyHasVehicles, _enemyHasArmored, _lastTimeAddressed, - _threatPriority, + _threatLevel, _nearestArea ]; _updatedThreats pushBack _setArray; diff --git a/modules/headless_ai/functions/Commander/fn_RadioReportThreat.sqf b/modules/headless_ai/functions/Commander/fn_RadioReportThreat.sqf index 1ab2be1c..a457c6e3 100644 --- a/modules/headless_ai/functions/Commander/fn_RadioReportThreat.sqf +++ b/modules/headless_ai/functions/Commander/fn_RadioReportThreat.sqf @@ -1,3 +1,4 @@ + #include "script_component.hpp" params [ @@ -10,7 +11,6 @@ if (_callerGroup isEqualTo objNull || _target isEqualTo objNull) exitWith {}; private _callerSide = side leader _callerGroup; private _targetGroup = group _target; -//IGNORE_PRIVATE_WARNING ["_x"] private _nearbyEnemy = []; _nearbyEnemy = [_target, 50] call FUNC(nearbyFriendlyEntities); _nearbyEnemy params [ diff --git a/modules/headless_ai/preInitClient.sqf b/modules/headless_ai/preInitClient.sqf index 6d6aedb2..27825975 100644 --- a/modules/headless_ai/preInitClient.sqf +++ b/modules/headless_ai/preInitClient.sqf @@ -2,7 +2,7 @@ LOG("HC Client Pre Init"); -private _version = "0.2.6"; +private _version = "0.2.7"; ["Headless AI", "Spawns AI via logic sync and provides custom AI system", "PIZZADOX", _version] call EFUNC(FW,RegisterModule); diff --git a/modules/headless_ai/settings/commander.hpp b/modules/headless_ai/settings/commander.hpp index 49c280c4..d98b300f 100644 --- a/modules/headless_ai/settings/commander.hpp +++ b/modules/headless_ai/settings/commander.hpp @@ -2,7 +2,7 @@ feature = true; debug = true; side = "east"; -//"Random" "Aggressive" "Defensive" "Guerilla" "Probing" +//"Random" "Aggressive" "Defensive" "Guerilla" personality = "Random"; delay = 3; skill = 5; @@ -14,7 +14,7 @@ roam = false; withdrawal = false; arty[] = {}; airStrikes[] = {}; -paradrops[] = {[]}; +paradrops[] = {}; // Commander fills zones to maximum asset values then starts assigning to next zone, or commander assigns evenly to zones in order of precedent until max values filled // "FILL" or "EVEN" fillAssignMode = "FILL"; @@ -42,12 +42,10 @@ class Areas { marker = "hill"; mission = "Patrol"; withdrawal = true; - }; - class Hill_1: Town { - marker = "hill_1"; - mission = "Ambush"; - withdrawal = true; qrfSupport = false; assetSupport = false; }; + class Hill_1: Hill { + marker = "hill_1"; + }; }; From 6855c0ef75273b6c48d7aca1566ef0cbffe0f79e Mon Sep 17 00:00:00 2001 From: PiZZAD0X Date: Sat, 11 Mar 2023 15:51:15 -0700 Subject: [PATCH 14/19] randPos fnc, loiter changes, assault and attack radius params --- .../headless_ai/functions/CfgFunctions.hpp | 2 +- .../functions/Combat/fn_CombatAssault.sqf | 4 +- .../functions/Combat/fn_CombatAttack.sqf | 3 +- .../functions/Combat/fn_CombatResponse.sqf | 43 ++-- .../functions/Combat/fn_GroupLoiter.sqf | 26 -- .../functions/Combat/fn_LoiterAction.sqf | 237 +++++------------- .../headless_ai/functions/Diag/fn_randPos.sqf | 55 ++++ .../functions/task/fn_taskAssault.sqf | 9 +- .../functions/task/fn_taskAttack.sqf | 2 +- .../functions/task/fn_taskLoiter.sqf | 13 +- 10 files changed, 151 insertions(+), 243 deletions(-) delete mode 100644 modules/headless_ai/functions/Combat/fn_GroupLoiter.sqf create mode 100644 modules/headless_ai/functions/Diag/fn_randPos.sqf diff --git a/modules/headless_ai/functions/CfgFunctions.hpp b/modules/headless_ai/functions/CfgFunctions.hpp index ac334fde..97087346 100644 --- a/modules/headless_ai/functions/CfgFunctions.hpp +++ b/modules/headless_ai/functions/CfgFunctions.hpp @@ -46,7 +46,6 @@ class COMPONENT { class ForceHeal {}; class FormationChange {}; class FragmentMove {}; - class GroupLoiter {}; class GroupPatrol {}; class LightGarrison {}; class LoiterAction {}; @@ -132,6 +131,7 @@ class COMPONENT { class LOSCheck {}; class tempRemovePrimaryMags {}; class nearbyFriendlyEntities {}; + class randPos {}; }; class Eventhandlers { diff --git a/modules/headless_ai/functions/Combat/fn_CombatAssault.sqf b/modules/headless_ai/functions/Combat/fn_CombatAssault.sqf index 9359de11..23efdea6 100644 --- a/modules/headless_ai/functions/Combat/fn_CombatAssault.sqf +++ b/modules/headless_ai/functions/Combat/fn_CombatAssault.sqf @@ -1,6 +1,6 @@ #include "script_component.hpp" -params ["_group", "_targetPos", ["_compradius", 250, [0]], ["_radius", 50, [0]]]; +params ["_group", "_targetPos", ["_radius", 50, [0]]]; LOG_1("combatAssault started _this: %1",_this); private _leader = leader _group; @@ -138,6 +138,6 @@ private _assaultTaskPFH = [{ _unit setSuppression 0; }; }; -}, 4, [_group, _targetPos, _compradius]] call CBA_fnc_addPerFrameHandler; +}, 4, [_group, _targetPos, _radius]] call CBA_fnc_addPerFrameHandler; SETVAR(_group,Task,"ASSAULT"); diff --git a/modules/headless_ai/functions/Combat/fn_CombatAttack.sqf b/modules/headless_ai/functions/Combat/fn_CombatAttack.sqf index ec14ec14..1d0ccfec 100644 --- a/modules/headless_ai/functions/Combat/fn_CombatAttack.sqf +++ b/modules/headless_ai/functions/Combat/fn_CombatAttack.sqf @@ -1,9 +1,8 @@ #include "script_component.hpp" -params ["_group", "_targetPos"]; +params ["_group", "_targetPos", "_radius"]; private _enemyDir = leader _group getDir _targetPos; -private _radius = 100; //private _formation = if ((random 2) > 1) then {"LINE"} else {"WEDGE"}; //_group setFormation _formation; diff --git a/modules/headless_ai/functions/Combat/fn_CombatResponse.sqf b/modules/headless_ai/functions/Combat/fn_CombatResponse.sqf index 3e1965e5..30e3519f 100644 --- a/modules/headless_ai/functions/Combat/fn_CombatResponse.sqf +++ b/modules/headless_ai/functions/Combat/fn_CombatResponse.sqf @@ -25,69 +25,72 @@ switch _currentmission do { case "PATROL": { if (_enemydist <= 150) then { if (_reinforcement) then { - [_Group, _currenttarget] call FUNC(CombatAttack); + [_group, _currenttarget] call FUNC(CombatAttack); } else { - [_Group, _currenttarget] call FUNC(CombatDefend); + [_group, _currenttarget] call FUNC(CombatDefend); }; } else { if (_reinforcement) then { - [_Group, _currenttarget] call FUNC(CombatMoveTo); + [_group, _currenttarget] call FUNC(CombatMoveTo); } else { - [_Group, _currenttarget] call FUNC(CombatDefend); + [_group, _currenttarget] call FUNC(CombatDefend); }; }; }; case "LOITER": { - _Group setSpeedMode "FULL"; - {_x setUnitPos "Auto";} foreach (units _group); + _group setSpeedMode "FULL"; + units _group apply { + _x doFollow leader _group; + _x setUnitPos "Auto"; + }; if (_reinforcement) then { - [_Group, _currenttarget] call FUNC(CombatAttack); + [_group, _currenttarget] call FUNC(CombatAttack); } else { - [_Group, _currenttarget] call FUNC(CombatDefend); + [_group, _currenttarget] call FUNC(CombatDefend); }; }; //regroups unit via a different function case "IDLE": { if (_enemydist < 150) then { if (_reinforcement) then { - [_Group, _currenttarget] call FUNC(CombatAttack); + [_group, _currenttarget] call FUNC(CombatAttack); } else { - [_Group, _currenttarget] call FUNC(CombatDefend); + [_group, _currenttarget] call FUNC(CombatDefend); }; } else { if (_reinforcement) then { - [_Group,_currenttarget,_enemydir] call FUNC(CombatMoveTo); + [_group,_currenttarget,_enemydir] call FUNC(CombatMoveTo); } else { - [_Group,_currenttarget,_enemydir] call FUNC(CombatDefend); + [_group,_currenttarget,_enemydir] call FUNC(CombatDefend); }; }; }; case "NONE": { if (_enemydist < 150) then { if (_reinforcement) then { - [_Group, _currenttarget] call FUNC(CombatAttack); + [_group, _currenttarget] call FUNC(CombatAttack); } else { - [_Group, _currenttarget] call FUNC(CombatDefend); + [_group, _currenttarget] call FUNC(CombatDefend); }; } else { if (_reinforcement) then { - [_Group, _currenttarget] call FUNC(CombatMoveTo); + [_group, _currenttarget] call FUNC(CombatMoveTo); } else { - [_Group, _currenttarget] call FUNC(CombatDefend); + [_group, _currenttarget] call FUNC(CombatDefend); }; }; }; default { if (_enemydist < 150) then { if (_reinforcement) then { - [_Group, _currenttarget] call FUNC(CombatAttack); + [_group, _currenttarget] call FUNC(CombatAttack); } else { - [_Group, _currenttarget] call FUNC(CombatDefend); + [_group, _currenttarget] call FUNC(CombatDefend); }; } else { if (_reinforcement) then { - [_Group, _currenttarget] call FUNC(CombatMoveTo); + [_group, _currenttarget] call FUNC(CombatMoveTo); } else { - [_Group, _currenttarget] call FUNC(CombatDefend); + [_group, _currenttarget] call FUNC(CombatDefend); }; }; }; diff --git a/modules/headless_ai/functions/Combat/fn_GroupLoiter.sqf b/modules/headless_ai/functions/Combat/fn_GroupLoiter.sqf deleted file mode 100644 index 5a28f32c..00000000 --- a/modules/headless_ai/functions/Combat/fn_GroupLoiter.sqf +++ /dev/null @@ -1,26 +0,0 @@ -#include "script_component.hpp" - -//This script will dictate how the loiter WP works for the AI -params ["_Unit", "_Group","_thisFSM"]; - -private _Unitleader = leader _Group; -SETVAR(_group,Task,"LOITER"); - -//We need a list of actions that the AI can do for loitering. -private _UnitArray = units _Group; -_UnitArray apply { - if (_x isEqualTo (vehicle _x)) then - { - //Each AI will need to join their own group. The plan is to make them re-form when combat starts. - //[_x] joinsilent grpnull; - //(group _x)SETVAR(,Mission,"LOITERING"); - SETVAR(_x,LOITERINGACT,0); - [_x,_UnitArray] spawn FUNC(LoiterAction); - }; -}; - -[_Unitleader,_UnitArray,_group] spawn { - params ["_Unitleader","_UnitArray","_group"]; - waituntil {({if ((behaviour _x) in ["COMBAT","STEALTH","AWARE"]) then {if (true) exitwith {true}} else {if (true) exitwith {false}}} foreach _UnitArray) || ((GETVAR(_group,CurrentTarget,objnull)) isNotEqualTo objnull)}; - [_Group] call FUNC(CombatResponse); -}; diff --git a/modules/headless_ai/functions/Combat/fn_LoiterAction.sqf b/modules/headless_ai/functions/Combat/fn_LoiterAction.sqf index 40ccf5e1..e4bd094c 100644 --- a/modules/headless_ai/functions/Combat/fn_LoiterAction.sqf +++ b/modules/headless_ai/functions/Combat/fn_LoiterAction.sqf @@ -1,177 +1,68 @@ #include "script_component.hpp" -params [["_unit", objNull, [objNull]], ["_unitsInGroup", [], [[]]]]; -(group _unit) setBehaviour "SAFE"; -(group _unit) setSpeedMode "LIMITED"; -_unit setUnitPos "UP"; -while {((behaviour _unit ) != "COMBAT") && ((behaviour _unit ) != "STEALTH") && ((behaviour _unit ) != "AWARE") && (alive _unit)} do { - while { (diag_fps < 15) } do { - sleep 60; - }; - scopeName "SAFE_Loop1"; - _pos = getPos _unit; - if ( (isOnRoad (getPos _unit)) && (alive _unit )) then { - while { isOnRoad _pos } do { - _pos = _unit getPos [4, (random 360)]; - sleep 0.1; - }; - _unit doMove _pos; - Waituntil {sleep 4; unitReady _unit;}; - }; - _CurrentAction = GETVAR(_unit,LOITERINGACT,0); - if (((behaviour _unit) == "COMBAT") || ((behaviour _unit) == "AWARE") || ((behaviour _unit) == "STEALTH")) then { breakOut "SAFE_Loop1";}; - _RandomAction = selectRandom ([1,3,4] - [_CurrentAction]); - switch (_RandomAction) do { - case 1: - { - //Wander around and play random animation - //Get random position - SETVAR(_unit,LoiteringAct,1); - _rnd = random 10; - _dist = (_rnd + 5); - _dir = random 360; - _UnitPosition = getposworld _unit ; - _positions = [(_UnitPosition select 0) + (sin _dir) * _dist, (_UnitPosition select 1) + (cos _dir) * _dist, 0]; - if ( isOnRoad _positions) then { - while {isOnRoad _positions} do { - if (!(alive _unit ))exitWith {}; - _rnd = random 3; - _dist = (_rnd + 5); - _dir = random 360; - _UnitPosition = getposworld _unit ; - _positions = [(_UnitPosition select 0) + (sin _dir) * _dist, (_UnitPosition select 1) + (cos _dir) * _dist, 0]; - }; - }; - if (!(alive _unit ))exitWith {}; - _unit doMove _positions; - if (((behaviour _unit) == "COMBAT") || ((behaviour _unit) == "AWARE") || ((behaviour _unit) == "STEALTH")) then { breakOut "SAFE_Loop1";}; - WaitUntil {sleep 2; (_unit distance _positions) < 2}; - _RandomAnimationList = selectRandom ["Acts_CivilTalking_1","Acts_CivilTalking_2", "Acts_CivilIdle_1", "Acts_CivilIdle_2", "Acts_ShieldFromSun_loop"]; - [_unit ,_RandomAnimationList] remoteExec ["playMoveEverywhere",0]; - }; +params [ + ["_group", grpNull, [grpNull]] +]; - case 3: - { - if (!(alive _unit ))exitWith {}; - SETVAR(_unit,LOITERINGACT,3); - _ClosestUnit = [(_unitsInGroup - [_unit ]), _unit] call FUNC(ClosestObject); - SETVAR(_ClosestUnit,LOITERINGACT,3); - if (((behaviour _unit) == "COMBAT") || ((behaviour _unit) == "AWARE") || ((behaviour _unit) == "STEALTH")) then { breakOut "SAFE_Loop1";}; - _rnd = random 10; - _dist = (_rnd + 5); - _dir = random 360; - _UnitPosition = getposworld _unit ; - _positions = [(_UnitPosition select 0) + (sin _dir) * _dist, (_UnitPosition select 1) + (cos _dir) * _dist, 0]; - if ( isOnRoad _positions) then { - while {isOnRoad _positions} do { - _rnd = random 3; - _dist = (_rnd + 5); - _dir = random 360; - _UnitPosition = getposworld _unit ; - _positions = [(_UnitPosition select 0) + (sin _dir) * _dist, (_UnitPosition select 1) + (cos _dir) * _dist, 0]; - }; - }; - _unit doMove _positions; - _ClosestUnit doMove _positions; - _rnd = random 4; - _dist = (_rnd + 3); - _dir = random 360; - _positions2 = [(_positions select 0) + (sin _dir) * _dist, (_positions select 1) + (cos _dir) * _dist, 0]; - _ClosestUnit doMove _positions2; - WaitUntil {sleep 2;(_unit distance _positions) < 5 && (_ClosestUnit distance _positions) < 5}; +_group setBehaviour "SAFE"; +_group setSpeedMode "LIMITED"; - - if (!(alive _unit ))exitWith {}; - if ((behaviour _unit ) == "COMBAT") then { breakOut "SAFE_Loop1";}; - sleep 10; - - _ClosestUnit spawn - { - _Counter = 0; - While {(_Counter < 11) && (alive _this)} do - { - sleep (random 2); - _RandomAnimationList = selectRandom ["AmovPercMstpSnonWnonDnon_exercisePushup","Acts_AidlPercMstpSlowWrflDnon_pissing","Acts_ShieldFromSun_loop","Acts_CivilIdle_1"]; - [_this,_RandomAnimationList] remoteExec ["playMoveEverywhere",0]; - _Counter = _Counter + 1; - sleep 10; - }; - }; - if (!(alive _unit ))exitWith {}; - _unit spawn - { - _Counter = 0; - While { ((_Counter < 11) && (alive _this)) } do - { - sleep (random 2); - _RandomAnimationList = selectRandom ["AmovPercMstpSnonWnonDnon_exercisePushup","Acts_AidlPercMstpSlowWrflDnon_pissing","Acts_ShieldFromSun_loop","Acts_CivilIdle_1"]; - [_this,_RandomAnimationList] remoteExec ["playMoveEverywhere",0]; - _Counter = _Counter + 1; - sleep 12; - }; - }; - }; - - case 4: - { - //Wander around and sitdown - //Get random position - SETVAR(_unit,LOITERINGACT,4); - _rnd = random 10; - _dist = (_rnd + 5); - _dir = random 360; - _UnitPosition = getposworld _unit ; - _positions = [(_UnitPosition select 0) + (sin _dir) * _dist, (_UnitPosition select 1) + (cos _dir) * _dist, 0]; - if ( isOnRoad _positions) then { - while {isOnRoad _positions} do { - _rnd = random 3; - _dist = (_rnd + 5); - _dir = random 360; - _UnitPosition = getposworld _unit ; - _positions = [(_UnitPosition select 0) + (sin _dir) * _dist, (_UnitPosition select 1) + (cos _dir) * _dist, 0]; - }; - }; - if (((behaviour _unit) == "COMBAT") || ((behaviour _unit) == "AWARE") || ((behaviour _unit) == "STEALTH")) then { breakOut "SAFE_Loop1";}; - _unit doMove _positions; - WaitUntil {sleep 2;((getPos _unit) distance _positions) < 2}; - if (true) exitwith { - breakOut "SAFE_Loop1"; - sleep 0.5; - _unit setBehaviour "SAFE"; - sleep 2; - doStop _unit; - sleep 0.5; - _unit action ["SitDown", _unit]; - sleep 0.5; - doStop _unit; - }; - //sleep 2; - //doStop _unit; - //sleep 0.5; - //_unit action ["SitDown", _unit]; - //for "_i" from 0 to 10 do { - // if ((behaviour _unit ) == "COMBAT") then { breakOut "SAFE_Loop1";}; - // if (!(alive _unit ))exitWith {}; - // sleep 10; - //}; - //_unit action ["SitDown", _unit]; - }; - }; - - if (((behaviour _unit) == "COMBAT") || ((behaviour _unit) == "AWARE") || ((behaviour _unit) == "STEALTH")) then { breakOut "SAFE_Loop1";}; - for "_i" from 0 to 4 do { - if (((behaviour _unit) == "COMBAT") || ((behaviour _unit) == "AWARE") || ((behaviour _unit) == "STEALTH")) then { breakOut "SAFE_Loop1";}; - if (!(alive _unit ))exitWith {}; - sleep 5; - }; - if (((behaviour _unit) == "COMBAT") || ((behaviour _unit) == "AWARE") || ((behaviour _unit) == "STEALTH")) then { breakOut "SAFE_Loop1";}; -}; - -{ - deleteWaypoint _x; -} foreach waypoints (group _unit); - -sleep 300; -(group _unit) setBehaviour "SAFE"; -sleep 10; -Waituntil {sleep 60; (!(alive _unit)) || ((behaviour _unit) != "COMBAT")}; +[{ + params ["_argNested", "_idPFH"]; + _argNested params ["_group"]; + private _leader = leader _group; + // exit loiter upon enemy contact + if ( + behaviour _leader in ["COMBAT","STEALTH"] && + {_leader findNearestEnemy _leader isNotEqualTo objNull} + ) then { + [_group, _leader findNearestEnemy _leader] call FUNC(CombatResponse); + [_idPFH] call CBA_fnc_removePerFrameHandler; + }; + // choose random actions for units to do + units _group apply { + private _unit = _x; + _unit setUnitPos "AUTO"; + doStop _unit; + private _selectedAction = + if (GETVAR(_unit,Sitting,false)) then { + if (RNG(0.9)) then { + "Sitting" + } else { + selectRandom ["Wander", "Building"]; + }; + } else { + selectRandom ["Wander", "SitDown", "Building"]; + }; + switch _selectedAction do { + case "Sitting": { + // continue sitting + }; + case "SitDown": { + private _pos = [getPosATL _unit, 5 + random 10, "NO", "NO"] call FUNC(randPos); + _unit doMove _pos; + [{ + params ["_unit", "_pos"]; + _unit distance _pos <= 2 + }, { + params ["_unit", "_pos"]; + _unit action ["SitDown", _unit]; + SETVAR(_unit,Sitting,true); + }, [_unit, _pos], 8, {}] call CBA_fnc_waitUntilAndExecute; + }; + // default wander + default { + private _pos = [getPosATL _unit, 5 + random 10, "NO", "NO"] call FUNC(randPos); + _unit doMove _pos; + [{ + params ["_unit", "_pos"]; + _unit distance _pos <= 2 + }, { + params ["_unit", "_pos"]; + private _randomAnim = selectRandom ["Acts_CivilTalking_1","Acts_CivilTalking_2", "Acts_CivilIdle_1", "Acts_CivilIdle_2", "Acts_ShieldFromSun_loop"]; + [_unit, _randomAnim, 1] call ace_common_fnc_doAnimation; + }, [_unit, _pos], 8, {}] call CBA_fnc_waitUntilAndExecute; + }; + }; + }; +}, 10, [_group]] call CBA_fnc_addPerFrameHandler; diff --git a/modules/headless_ai/functions/Diag/fn_randPos.sqf b/modules/headless_ai/functions/Diag/fn_randPos.sqf new file mode 100644 index 00000000..0e9ac773 --- /dev/null +++ b/modules/headless_ai/functions/Diag/fn_randPos.sqf @@ -0,0 +1,55 @@ +#include "script_component.hpp" + +/* + * Author: PiZZADOX + * Generates a random position based on condition options. Extension of CBA_fnc_randPos function. + * + * Arguments: + * 0: Position + * 1: Radius + * 2: Road Mode ("NO", "YES", "ANY") + * 3: Water Mode ("NO", "YES", "ANY") + * + * Return Value: + * Position + * + * Example: + * [player, 50] call ace_[module]_fnc_[functionName] + * + * Public: No + */ + +params [ + ["_pos", [0,0,0], [[], objNull]], + ["_radius", 30, [0]], + ["_road", "NO", [""]], + ["_water", "NO", [""]] +]; + +if (_pos isEqualType objNull) then { + _pos = getPosATL _pos; +}; + +private _randomPos = [0,0,0]; + +for "_i" from 0 to 30 step 1 do { + private _tempPos = [_pos, _radius] call CBA_fnc_randPos; + if ( + (_road isEqualTo "ANY" || + (isOnRoad _tempPos && {_road in ["YES"]}) || + (!isOnRoad _tempPos && {_road in ["NO"]})) && + { + _water isEqualTo "ANY" || + (surfaceIsWater _tempPos && {_water in ["YES"]}) || + (!surfaceIsWater _tempPos && {_water in ["NO"]}) + } + ) exitWith { + _randomPos = _tempPos; + }; +}; + +if (_randomPos isEqualTo [0,0,0]) then { + TRACE_1("Failed to generate good position",_pos); +}; + +_randomPos diff --git a/modules/headless_ai/functions/task/fn_taskAssault.sqf b/modules/headless_ai/functions/task/fn_taskAssault.sqf index 345b3f61..18f6a3e2 100644 --- a/modules/headless_ai/functions/task/fn_taskAssault.sqf +++ b/modules/headless_ai/functions/task/fn_taskAssault.sqf @@ -16,7 +16,7 @@ params [ ]; if (_radius < 30) then { - ERROR_1("taskPatrol _group: %1 radius too small! Setting to default 30m",_group); + ERROR_1("taskAssault _group: %1 radius too small! Setting to default 30m",_group); _radius = 30; }; @@ -24,7 +24,7 @@ LOG_1("taskAssault started _this: %1",_this); _group = _group call CBA_fnc_getGroup; if !(local _group) exitWith {}; // Don't create waypoints on each machine -private _timeout = [(_wait*0.5), _wait, (_wait*1.5)]; +//private _timeout = [(_wait*0.5), _wait, (_wait*1.5)]; _attackPos = _attackPos call CBA_fnc_getPos; // Clear existing waypoints first @@ -33,7 +33,4 @@ _attackPos = _attackPos call CBA_fnc_getPos; SETVAR(_group,Task,"ASSAULT"); [_group] call FUNC(taskRelease); -_compradius = GETVAR(_group,taskCompRadius,150); -TRACE_2("",_group,_compradius); - -[_group, _attackPos, _compradius, _radius] call FUNC(combatAssault); +[_group, _attackPos, _radius] call FUNC(combatAssault); diff --git a/modules/headless_ai/functions/task/fn_taskAttack.sqf b/modules/headless_ai/functions/task/fn_taskAttack.sqf index 35d482c7..fd80e9eb 100644 --- a/modules/headless_ai/functions/task/fn_taskAttack.sqf +++ b/modules/headless_ai/functions/task/fn_taskAttack.sqf @@ -20,4 +20,4 @@ if !(local _group) exitWith {}; // Don't create waypoints on each machine _attackPos = _attackPos call CBA_fnc_getPos; -[_group, _attackPos] call FUNC(combatAttack); +[_group, _attackPos, _radius] call FUNC(combatAttack); diff --git a/modules/headless_ai/functions/task/fn_taskLoiter.sqf b/modules/headless_ai/functions/task/fn_taskLoiter.sqf index 24feeb70..7b816bc1 100644 --- a/modules/headless_ai/functions/task/fn_taskLoiter.sqf +++ b/modules/headless_ai/functions/task/fn_taskLoiter.sqf @@ -15,15 +15,4 @@ params [ _group setVariable [QGVAR(Task),"LOITER"]; [_group] call FUNC(taskRelease); -//We need a list of actions that the AI can do for loitering. -private _units = units _group; -_units apply { - if (_x isEqualTo (vehicle _x)) then { - //Each AI will need to join their own group. The plan is to make them re-form when combat starts. - //[_x] joinsilent grpnull; - //(group _x) setVariable [QGVAR(Mission),"LOITERING"]; - _x setVariable [QGVAR(LOITERINGACT),0]; - [_x, _units] spawn FUNC(LoiterAction); - }; -}; -true +[_group] call FUNC(LoiterAction); From 9d81758f40446cca494159d479404eab26aad850 Mon Sep 17 00:00:00 2001 From: PiZZAD0X Date: Tue, 14 Mar 2023 21:50:51 -0600 Subject: [PATCH 15/19] move settings to hpp, shiver frequency setting --- modules/snow/functions/snow/fn_shiver.sqf | 2 +- modules/snow/functions/snow/fn_snow_drop.sqf | 22 +++++++++++++++++++- modules/snow/preInitClient.sqf | 16 +++++++++++--- modules/snow/root.sqf | 6 ++++++ modules/snow/settings.hpp | 22 ++++++++++++++++++++ modules/snow/settings.sqf | 11 ---------- 6 files changed, 63 insertions(+), 16 deletions(-) create mode 100644 modules/snow/settings.hpp delete mode 100644 modules/snow/settings.sqf diff --git a/modules/snow/functions/snow/fn_shiver.sqf b/modules/snow/functions/snow/fn_shiver.sqf index d6aff0b6..9771bf36 100644 --- a/modules/snow/functions/snow/fn_shiver.sqf +++ b/modules/snow/functions/snow/fn_shiver.sqf @@ -9,7 +9,7 @@ if (CBA_missionTime >= GVAR(shiverCheckTime)) then { playSound _this; addCamShake [0.1,(5 + (random 10)) * 2,25]; }, _sound, 1] call CBA_fnc_waitAndExecute; - GVAR(shiverInterval) = 20 + (random 30); + GVAR(shiverInterval) = GVAR(shiverFrequency) + (random 30); GVAR(shiverTimer) = 0; } else { GVAR(shiverTimer) = GVAR(shiverTimer) + 5; diff --git a/modules/snow/functions/snow/fn_snow_drop.sqf b/modules/snow/functions/snow/fn_snow_drop.sqf index 18d68ede..dadd0a70 100644 --- a/modules/snow/functions/snow/fn_snow_drop.sqf +++ b/modules/snow/functions/snow/fn_snow_drop.sqf @@ -1 +1,21 @@ -drop [["\A3\data_f\ParticleEffects\Universal\Universal.p3d",16,12,8,1],"","Billboard",1,12,[_this select 0,_this select 1,_this select 2 + 25],[0,0,0],3,1.7,1,1,[0.05],[[1,1,1,1]],[1],1,1,"","",_this]; +drop [ + ["\A3\data_f\ParticleEffects\Universal\Universal.p3d",16,12,8,1], + "", + "Billboard", + 1, + 12, + [_this select 0,_this select 1,_this select 2 + 25], + [0,0,0], + 3, + 1.7, + 1, + 1, + [0.05], + [[1,1,1,1]], + [1], + 1, + 1, + "", + "", + _this +]; diff --git a/modules/snow/preInitClient.sqf b/modules/snow/preInitClient.sqf index 5451bb2a..c779f542 100644 --- a/modules/snow/preInitClient.sqf +++ b/modules/snow/preInitClient.sqf @@ -1,10 +1,20 @@ #include "script_component.hpp" -private _version = 0.1; +private _version = 0.2; -["Snow", "Snow and breath effects for winter.", "TinfoilHate & StatusRed", _version] call EFUNC(FW,RegisterModule); +["Snow", "Snow and breath effects for winter.", "TinfoilHate, StatusRed, & PiZZADOX", _version] call EFUNC(FW,RegisterModule); + +GVAR(snowfall) = ([missionConfigFile >> QGVAR(settings) >> "snowfall", "number", 1] call CBA_fnc_getConfigEntry) == 1; +GVAR(snowFog) = ([missionConfigFile >> QGVAR(settings) >> "snowFog", "number", 1] call CBA_fnc_getConfigEntry) == 1; +GVAR(breath) = ([missionConfigFile >> QGVAR(settings) >> "breath", "number", 1] call CBA_fnc_getConfigEntry) == 1; +GVAR(shiver) = ([missionConfigFile >> QGVAR(settings) >> "shiver", "number", 1] call CBA_fnc_getConfigEntry) == 1; +GVAR(shiverFrequency) = [missionConfigFile >> QGVAR(settings) >> "shiverFrequency", "number", 20] call CBA_fnc_getConfigEntry; +GVAR(postProcessing) = ([missionConfigFile >> QGVAR(settings) >> "postProcessing", "number", 0] call CBA_fnc_getConfigEntry) == 1; +GVAR(fog) = ([missionConfigFile >> QGVAR(settings) >> "fog", "number", 1] call CBA_fnc_getConfigEntry) == 1; +GVAR(density) = [missionConfigFile >> QGVAR(settings) >> "density", "number", 0.6] call CBA_fnc_getConfigEntry; +GVAR(decay) = [missionConfigFile >> QGVAR(settings) >> "decay", "number", 0] call CBA_fnc_getConfigEntry; +GVAR(baseHeight) = [missionConfigFile >> QGVAR(settings) >> "baseHeight", "number", 0] call CBA_fnc_getConfigEntry; -#include "settings.sqf" if (GVAR(postProcessing)) then { "colorCorrections" ppEffectAdjust [1, 1, 0, [0.01, 0.02, 0.04, 0.01], [0.87, 1.08, 1.196, 0.3], [0.399, 0.287, 0.014, 0.0]]; diff --git a/modules/snow/root.sqf b/modules/snow/root.sqf index 0422aba4..855ef5e8 100644 --- a/modules/snow/root.sqf +++ b/modules/snow/root.sqf @@ -14,4 +14,10 @@ #include "functions\CfgFunctions.hpp" #endif +#ifdef description + class GVAR(settings) { + #include "settings.hpp" + }; +#endif + #undef COMPONENT diff --git a/modules/snow/settings.hpp b/modules/snow/settings.hpp new file mode 100644 index 00000000..333131be --- /dev/null +++ b/modules/snow/settings.hpp @@ -0,0 +1,22 @@ +// Enables the snowfall feature +snowfall = false; +// Enables the snow fog feature +snowFog = true; +// Enables the cold breath feature +breath = true; +// Enables shivering +shiver = true; +// Frequency of shiver checks (still has randomization time applied in addition to this setting) +shiverFrequency = 20; +// Enables client post processing effects for snow - not recommended. +postProcessing = false; + +// Fog Settings +// Enables additional fog system +fog = true; +// Fog density from 0 - 1 +density = 0.6; //Scale from 0-1 +// Fog decay over distance +decay = 0; +// Fog base height. Mimics A3 fog height setting. +baseHeight = 0; diff --git a/modules/snow/settings.sqf b/modules/snow/settings.sqf deleted file mode 100644 index 81082173..00000000 --- a/modules/snow/settings.sqf +++ /dev/null @@ -1,11 +0,0 @@ -GVAR(snowfall) = false; -GVAR(snowFog) = true; -GVAR(breath) = true; -GVAR(shiver) = true; -GVAR(postProcessing) = false; - -//Fog Settings -GVAR(fog) = true; -GVAR(density) = 0.6; //Scale from 0-1 -GVAR(decay) = 0; -GVAR(baseHeight) = 0; \ No newline at end of file From a10569f0aa805007b005f658aa40d2fe5e98f2e3 Mon Sep 17 00:00:00 2001 From: PiZZAD0X Date: Tue, 14 Mar 2023 22:05:23 -0600 Subject: [PATCH 16/19] JIP deny settings, type setting --- modules/jip/functions/JIP/fn_teleport.sqf | 6 ------ modules/jip/postInitClient.sqf | 10 ++++++---- modules/jip/preInitClient.sqf | 8 ++++---- 3 files changed, 10 insertions(+), 14 deletions(-) diff --git a/modules/jip/functions/JIP/fn_teleport.sqf b/modules/jip/functions/JIP/fn_teleport.sqf index 39d81936..d84bf60a 100644 --- a/modules/jip/functions/JIP/fn_teleport.sqf +++ b/modules/jip/functions/JIP/fn_teleport.sqf @@ -1,7 +1,5 @@ #include "script_component.hpp" -/* diag_log format ["INFO: In teleport action! this = %1", _this]; */ - params ["_target"]; if !( @@ -34,10 +32,6 @@ if !( }; }; -/* diag_log format ["INFO _target = %1", _target]; -diag_log format ["INFO in vehicle? = %1", (INVEHICLE(_target))]; -diag_log format ["INFO player = %1", player]; */ - if (_target isNotEqualTo objnull) then { ["ace_common_displayTextStructured", [["%1 joined the mission and is teleporting to you in 5 seconds", name player], 1.5, _target], [_target]] call CBA_fnc_targetEvent; [player, 1, ["ACE_SelfActions", QGVAR(TeleportAction)]] call ace_interact_menu_fnc_removeActionFromObject; diff --git a/modules/jip/postInitClient.sqf b/modules/jip/postInitClient.sqf index bd53b666..5279bcc1 100644 --- a/modules/jip/postInitClient.sqf +++ b/modules/jip/postInitClient.sqf @@ -1,7 +1,6 @@ #include "script_component.hpp" -if !(hasInterface) exitWith {}; -if !(didJIP) exitWith {}; +if (!hasInterface || !didJIP) exitWith {}; private _west_locationString = ([missionConfigFile >> QGVAR(settings) >> "west" >> "spawnLocation", "string", ""] call CBA_fnc_getConfigEntry); GVAR(west_spawnLocation) = missionNamespace getVariable [_west_locationString, objNull]; @@ -73,7 +72,10 @@ switch side player do { }; }; -if (missionNamespace getVariable [QGVAR(_typeVar), "TELEPORT"] isEqualTo "DENY" && {missionNamespace getVariable [QGVAR(_deniedVar), false]}) exitWith { +if ( + missionNamespace getVariable [_typeVar, "TELEPORT"] isEqualTo "DENY" && + {missionNamespace getVariable [_deniedVar, false]} +) exitWith { [{ player call EFUNC(FW,UntrackUnit); player setDamage 1; @@ -97,7 +99,7 @@ if (_spawnLoc isNotEqualTo objNull) then { GVAR(JIPSpawnPos) = getPosATL _spawnLoc; }; -if (missionNamespace getVariable [QGVAR(_typeVar), "TELEPORT"] isEqualTo "NONE") exitWith { +if (missionNamespace getVariable [_typeVar, "TELEPORT"] isEqualTo "NONE") exitWith { ["JIP set to regular spawn, no transport or teleport option available."] call EFUNC(FW,parsedTextDisplay); }; diff --git a/modules/jip/preInitClient.sqf b/modules/jip/preInitClient.sqf index a77e21bf..8882012d 100644 --- a/modules/jip/preInitClient.sqf +++ b/modules/jip/preInitClient.sqf @@ -4,22 +4,22 @@ private _version = 0.3; ["JIP Manager", "Handles JIPs in different ways depending on the module's settings.", "Olsen, Starfox64, StatusRed & PiZZADOX", _version] call EFUNC(FW,RegisterModule); -GVAR(west_type) = toUpper ([missionConfigFile >> QGVAR(settings) >> "west" >> "denyTime", "string", "TELEPORT"] call CBA_fnc_getConfigEntry); +GVAR(west_type) = toUpper ([missionConfigFile >> QGVAR(settings) >> "west" >> "type", "string", "TELEPORT"] call CBA_fnc_getConfigEntry); GVAR(west_distance) = [missionConfigFile >> QGVAR(settings) >> "west" >> "distance", "number", 50] call CBA_fnc_getConfigEntry; GVAR(west_spawnDistance) = [missionConfigFile >> QGVAR(settings) >> "west" >> "spawnDistance", "number", 200] call CBA_fnc_getConfigEntry; GVAR(west_dismountVehicles) = [missionConfigFile >> QGVAR(settings) >> "west" >> "dismountVehicles", "boolean", true] call CBA_fnc_getConfigEntry; -GVAR(east_type) = toUpper ([missionConfigFile >> QGVAR(settings) >> "east" >> "denyTime", "string", "TELEPORT"] call CBA_fnc_getConfigEntry); +GVAR(east_type) = toUpper ([missionConfigFile >> QGVAR(settings) >> "east" >> "type", "string", "TELEPORT"] call CBA_fnc_getConfigEntry); GVAR(east_distance) = [missionConfigFile >> QGVAR(settings) >> "east" >> "distance", "number", 50] call CBA_fnc_getConfigEntry; GVAR(east_spawnDistance) = [missionConfigFile >> QGVAR(settings) >> "east" >> "spawnDistance", "number", 200] call CBA_fnc_getConfigEntry; GVAR(east_dismountVehicles) = [missionConfigFile >> QGVAR(settings) >> "east" >> "dismountVehicles", "boolean", true] call CBA_fnc_getConfigEntry; -GVAR(independent_type) = toUpper ([missionConfigFile >> QGVAR(settings) >> "independent" >> "denyTime", "string", "TELEPORT"] call CBA_fnc_getConfigEntry); +GVAR(independent_type) = toUpper ([missionConfigFile >> QGVAR(settings) >> "independent" >> "type", "string", "TELEPORT"] call CBA_fnc_getConfigEntry); GVAR(independent_distance) = [missionConfigFile >> QGVAR(settings) >> "independent" >> "distance", "number", 50] call CBA_fnc_getConfigEntry; GVAR(independent_spawnDistance) = [missionConfigFile >> QGVAR(settings) >> "independent" >> "spawnDistance", "number", 200] call CBA_fnc_getConfigEntry; GVAR(independent_dismountVehicles) = [missionConfigFile >> QGVAR(settings) >> "independent" >> "dismountVehicles", "boolean", true] call CBA_fnc_getConfigEntry; -GVAR(civilian_type) = toUpper ([missionConfigFile >> QGVAR(settings) >> "civilian" >> "denyTime", "string", "TELEPORT"] call CBA_fnc_getConfigEntry); +GVAR(civilian_type) = toUpper ([missionConfigFile >> QGVAR(settings) >> "civilian" >> "type", "string", "TELEPORT"] call CBA_fnc_getConfigEntry); GVAR(civilian_distance) = [missionConfigFile >> QGVAR(settings) >> "civilian" >> "distance", "number", 50] call CBA_fnc_getConfigEntry; GVAR(civilian_spawnDistance) = [missionConfigFile >> QGVAR(settings) >> "civilian" >> "spawnDistance", "number", 200] call CBA_fnc_getConfigEntry; GVAR(civilian_dismountVehicles) = [missionConfigFile >> QGVAR(settings) >> "civilian" >> "dismountVehicles", "boolean", true] call CBA_fnc_getConfigEntry; From b1110e062fd0505e4eefa5744a6735da34f2b18e Mon Sep 17 00:00:00 2001 From: PiZZAD0X Date: Thu, 16 Mar 2023 17:40:57 -0600 Subject: [PATCH 17/19] commander marker check, task garrison building pos check --- .../functions/Commander/fn_CommanderInit.sqf | 5 +++++ .../headless_ai/functions/task/fn_taskGarrison.sqf | 12 ++++++++++-- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/modules/headless_ai/functions/Commander/fn_CommanderInit.sqf b/modules/headless_ai/functions/Commander/fn_CommanderInit.sqf index b64a9413..ca747e17 100644 --- a/modules/headless_ai/functions/Commander/fn_CommanderInit.sqf +++ b/modules/headless_ai/functions/Commander/fn_CommanderInit.sqf @@ -24,6 +24,7 @@ GVAR(CommanderAreasParsed) = []; /*15*/ ["_control","Neutral",["Neutral"]] ]; TRACE_1("",_area); + private _markerSuccess = false; if (_displayName isEqualTo "") then { _displayName = _marker; ERROR_1("%1 has no display name! defaulting to marker name",_displayName); @@ -37,8 +38,12 @@ GVAR(CommanderAreasParsed) = []; LOG_1("passed check for area: %1",_displayName); //hide marker _marker setMarkerAlpha 0; + _markerSuccess = true; }; }; + if !(_markerSuccess) then { + continue; + }; if (_min < 0) then { ERROR_2("%1 min value below minimum! _min: %2",_displayName,_min); _min = 0; diff --git a/modules/headless_ai/functions/task/fn_taskGarrison.sqf b/modules/headless_ai/functions/task/fn_taskGarrison.sqf index 743fd9e4..d7587508 100644 --- a/modules/headless_ai/functions/task/fn_taskGarrison.sqf +++ b/modules/headless_ai/functions/task/fn_taskGarrison.sqf @@ -14,12 +14,20 @@ params [ private _excludeClaimedHouses = true; private _largerSearch = true; private _houses = (nearestObjects [leader _group, ["House", "Strategic", "Ruins"], _radius, true]) select { - ((_x buildingPos -1) select {!(_x in GVAR(OccupiedPositions))}) isNotEqualTo [] && + private _bPosArray = _x buildingPos -1; + (count _bPosArray >= 3) && + { + (_bPosArray select {!(_x in GVAR(OccupiedPositions))}) isNotEqualTo [] + } && {!_excludeClaimedHouses || !(GETVAR(_x,claimed,false))} }; if (_houses isEqualTo [] && _largerSearch) then { _houses = (nearestObjects [leader _group, ["House", "Strategic", "Ruins"], _radius * 3, true]) select { - ((_x buildingPos -1) select {!(_x in GVAR(OccupiedPositions))}) isNotEqualTo [] && + private _bPosArray = _x buildingPos -1; + (count _bPosArray >= 3) && + { + (_bPosArray select {!(_x in GVAR(OccupiedPositions))}) isNotEqualTo [] + } && {!_excludeClaimedHouses || !(GETVAR(_x,claimed,false))} }; }; From 51e9d5f3678a81fb7e72952df5c7403fefeef283 Mon Sep 17 00:00:00 2001 From: PiZZAD0X Date: Thu, 16 Mar 2023 17:41:13 -0600 Subject: [PATCH 18/19] Update settings.hpp --- modules/headless_ai/settings.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/headless_ai/settings.hpp b/modules/headless_ai/settings.hpp index 1bcf8771..8b574714 100644 --- a/modules/headless_ai/settings.hpp +++ b/modules/headless_ai/settings.hpp @@ -7,7 +7,7 @@ of reinforcements or subsequent AOs. // Array objects // eg: ["mainEnemy", "patrol_1", "patrol_2", "patrol_3"] -arrayObjects[] = {"hc_1", "hc_2", "hc_3", "hc_4"}; +arrayObjects[] = {"hc_1", "hc_2", "hc_3", "hc_4", "hc_5"}; // Initial spawns are spawned upon init, at the start of the mission. // eg: ["mainEnemy"] From 7536376e5daf39e614de26a43c34e149d19d5434 Mon Sep 17 00:00:00 2001 From: PiZZAD0X Date: Thu, 16 Mar 2023 17:41:42 -0600 Subject: [PATCH 19/19] loiter fnc, randPos function --- .../functions/Combat/fn_LoiterAction.sqf | 91 ++++++++++++++----- .../headless_ai/functions/Diag/fn_randPos.sqf | 6 +- modules/headless_ai/settings/commander.hpp | 2 +- 3 files changed, 73 insertions(+), 26 deletions(-) diff --git a/modules/headless_ai/functions/Combat/fn_LoiterAction.sqf b/modules/headless_ai/functions/Combat/fn_LoiterAction.sqf index e4bd094c..e911a177 100644 --- a/modules/headless_ai/functions/Combat/fn_LoiterAction.sqf +++ b/modules/headless_ai/functions/Combat/fn_LoiterAction.sqf @@ -6,63 +6,110 @@ params [ _group setBehaviour "SAFE"; _group setSpeedMode "LIMITED"; +private _leaderPos = getPosATL leader _group; [{ params ["_argNested", "_idPFH"]; - _argNested params ["_group"]; + _argNested params ["_group", "_leaderPos"]; private _leader = leader _group; // exit loiter upon enemy contact if ( behaviour _leader in ["COMBAT","STEALTH"] && {_leader findNearestEnemy _leader isNotEqualTo objNull} - ) then { + ) exitWith { + units _group apply { + [_x, "", 1] call ace_common_fnc_doAnimation; + _x doFollow _leader; + }; [_group, _leader findNearestEnemy _leader] call FUNC(CombatResponse); [_idPFH] call CBA_fnc_removePerFrameHandler; }; // choose random actions for units to do units _group apply { private _unit = _x; - _unit setUnitPos "AUTO"; - doStop _unit; - private _selectedAction = - if (GETVAR(_unit,Sitting,false)) then { + private _selectedAction = if (GETVAR(_unit,Sitting,false)) then { if (RNG(0.9)) then { "Sitting" } else { - selectRandom ["Wander", "Building"]; + [_unit, "", 1] call ace_common_fnc_doAnimation; + SETVAR(_unit,Sitting,false); + selectRandom ["Wander", "Building"] }; } else { - selectRandom ["Wander", "SitDown", "Building"]; + selectRandom [ + //"Wander", + "SitDown"//, + //"Building" + ] }; + private _sitting = GETVAR(_unit,Sitting,false); + TRACE_3("",_unit,_selectedAction,_sitting); switch _selectedAction do { case "Sitting": { // continue sitting + if (animationState _unit != "AidlPsitMstpSnonWnonDnon_ground00") then { + private _sitType = selectRandom ["AidlPsitMstpSnonWnonDnon_ground00"]; + [_unit, _sitType, 1] call ace_common_fnc_doAnimation; + [_unit, "AnimDone", { + _this params ["_unit", "_anim"]; + if (_anim == "AidlPsitMstpSnonWnonDnon_ground00") then { + doStop _unit; + SETVAR(_unit,Sitting,false); + _unit removeEventHandler [_thisType, _thisID]; + }; + }, []] call CBA_fnc_addBISEventHandler; + }; }; case "SitDown": { - private _pos = [getPosATL _unit, 5 + random 10, "NO", "NO"] call FUNC(randPos); + [_unit, "", 1] call ace_common_fnc_doAnimation; + _unit setUnitPos "AUTO"; + private _pos = [_leaderPos, 5 + random 10] call FUNC(randPos); _unit doMove _pos; [{ params ["_unit", "_pos"]; _unit distance _pos <= 2 }, { params ["_unit", "_pos"]; - _unit action ["SitDown", _unit]; + //doStop _unit; + private _sitType = selectRandom ["AidlPsitMstpSnonWnonDnon_ground00"]; + [_unit, _sitType, 1] call ace_common_fnc_doAnimation; + [_unit, "AnimDone", { + _this params ["_unit", "_anim"]; + if (_anim == "AidlPsitMstpSnonWnonDnon_ground00") then { + doStop _unit; + SETVAR(_unit,Sitting,false); + _unit removeEventHandler [_thisType, _thisID]; + }; + }, []] call CBA_fnc_addBISEventHandler; SETVAR(_unit,Sitting,true); - }, [_unit, _pos], 8, {}] call CBA_fnc_waitUntilAndExecute; + }, [_unit, _pos], 5, { + params ["_unit", "_pos"]; + [_unit, "AnimDone", { + _this params ["_unit", "_anim"]; + if (_anim == "AidlPsitMstpSnonWnonDnon_ground00") then { + doStop _unit; + SETVAR(_unit,Sitting,false); + _unit removeEventHandler [_thisType, _thisID]; + }; + }, []] call CBA_fnc_addBISEventHandler; + }] call CBA_fnc_waitUntilAndExecute; }; // default wander default { - private _pos = [getPosATL _unit, 5 + random 10, "NO", "NO"] call FUNC(randPos); - _unit doMove _pos; - [{ - params ["_unit", "_pos"]; - _unit distance _pos <= 2 - }, { - params ["_unit", "_pos"]; - private _randomAnim = selectRandom ["Acts_CivilTalking_1","Acts_CivilTalking_2", "Acts_CivilIdle_1", "Acts_CivilIdle_2", "Acts_ShieldFromSun_loop"]; - [_unit, _randomAnim, 1] call ace_common_fnc_doAnimation; - }, [_unit, _pos], 8, {}] call CBA_fnc_waitUntilAndExecute; + //[_unit, ""] call ace_common_fnc_doAnimation; + //_unit setUnitPos "AUTO"; + //doStop _unit; + //private _pos = [_leaderPos, 5 + random 10, "NO", "NO"] call FUNC(randPos); + //_unit doMove _pos; + //[{ + // params ["_unit", "_pos"]; + // _unit distance _pos <= 2 + //}, { + // params ["_unit", "_pos"]; + // private _randomAnim = selectRandom ["Acts_CivilTalking_1","Acts_CivilTalking_2", "Acts_CivilIdle_1", "Acts_CivilIdle_2", "Acts_ShieldFromSun_loop"]; + // [_unit, _randomAnim, 1] call ace_common_fnc_doAnimation; + //}, [_unit, _pos], 8, {}] call CBA_fnc_waitUntilAndExecute; }; }; }; -}, 10, [_group]] call CBA_fnc_addPerFrameHandler; +}, 10, [_group, _leaderPos]] call CBA_fnc_addPerFrameHandler; diff --git a/modules/headless_ai/functions/Diag/fn_randPos.sqf b/modules/headless_ai/functions/Diag/fn_randPos.sqf index 0e9ac773..eff7bf72 100644 --- a/modules/headless_ai/functions/Diag/fn_randPos.sqf +++ b/modules/headless_ai/functions/Diag/fn_randPos.sqf @@ -22,8 +22,8 @@ params [ ["_pos", [0,0,0], [[], objNull]], ["_radius", 30, [0]], - ["_road", "NO", [""]], - ["_water", "NO", [""]] + ["_road", "ANY", [""]], + ["_water", "ANY", [""]] ]; if (_pos isEqualType objNull) then { @@ -32,7 +32,7 @@ if (_pos isEqualType objNull) then { private _randomPos = [0,0,0]; -for "_i" from 0 to 30 step 1 do { +for "_i" from 0 to 10 step 1 do { private _tempPos = [_pos, _radius] call CBA_fnc_randPos; if ( (_road isEqualTo "ANY" || diff --git a/modules/headless_ai/settings/commander.hpp b/modules/headless_ai/settings/commander.hpp index d98b300f..1a038bd5 100644 --- a/modules/headless_ai/settings/commander.hpp +++ b/modules/headless_ai/settings/commander.hpp @@ -1,5 +1,5 @@ // AI commander options -WIP -feature = true; +feature = false; debug = true; side = "east"; //"Random" "Aggressive" "Defensive" "Guerilla"