From 515f2d95e4735534d0d19bc8136bedeb40c6a5fc Mon Sep 17 00:00:00 2001 From: nk3nny Date: Sun, 18 Feb 2024 13:44:07 +0100 Subject: [PATCH] Improvements to vehicle Brain (#349) Improved the way DangerPos is handled in the vehicle brain, stopping even more cases of knowledge the AI shouldn't have-- and fixing an issue where the AI would sometimes suppress the sky! Added troops manning static weapons will now abandon them if they run out of ammo Added - soft-skinned, wheeled vehicles will try to JINK if explosions hit nearby. Improved dismount/rotate logic of IFVs and APCs Improved taskFlank use of vehicles. (on the last cycle, vehicles will move to move position) Improved doFleeing handling of vehicles Improved doVehicleRotate performance in minor ways Fixed issue where AI would have more knowledge than appropriate Fixed rare issue where assessing or flanking units would abandon vehicles Fixed - Groups will now ignore empty static weapons. Fixed Rare issue where doVehicleAssault could target empty spots in the sky Misc. performance improvements. --- addons/danger/functions/fnc_brainVehicle.sqf | 80 ++++++++++++------- addons/danger/functions/fnc_tacticsAssess.sqf | 2 +- addons/danger/functions/fnc_tacticsFlank.sqf | 2 +- .../GroupAction/fnc_doGroupFlank.sqf | 14 ++-- .../GroupAction/fnc_doGroupStaticFind.sqf | 2 +- .../functions/UnitAction/fnc_doFleeing.sqf | 7 +- .../VehicleAction/fnc_doVehicleAssault.sqf | 8 +- .../VehicleAction/fnc_doVehicleRotate.sqf | 17 ++-- 8 files changed, 80 insertions(+), 52 deletions(-) diff --git a/addons/danger/functions/fnc_brainVehicle.sqf b/addons/danger/functions/fnc_brainVehicle.sqf index 1cd890e8..991a95d1 100644 --- a/addons/danger/functions/fnc_brainVehicle.sqf +++ b/addons/danger/functions/fnc_brainVehicle.sqf @@ -51,7 +51,15 @@ _causeArray params ["_cause", "_dangerPos", "", "_dangerCausedBy"]; // "_dangerU _unit setVariable [QEGVAR(main,FSMDangerCauseData), _causeArray, EGVAR(main,debug_functions)]; // is it an attack? -private _attack = _cause in [DANGER_ENEMYDETECTED, DANGER_ENEMYNEAR, DANGER_HIT, DANGER_CANFIRE, DANGER_BULLETCLOSE] && {(side _dangerCausedBy) isNotEqualTo (side _unit)}; +private _attack = _cause in [DANGER_ENEMYDETECTED, DANGER_ENEMYNEAR, DANGER_HIT, DANGER_CANFIRE, DANGER_BULLETCLOSE] && {(side _dangerCausedBy) isNotEqualTo (side _unit)} && {!isNull _dangerCausedBy}; + +// update dangerPos if attacking. Check that the position is not too far above, or below ground. +if (_attack) then { + private _dangerPos = _unit getHideFrom _dangerCausedBy; + if (_dangerPos isEqualTo [0, 0, 0]) exitWith {_attack = false;}; + _dangerPos = ASLtoAGL (ATLtoASL _dangerPos); + if ((_dangerPos select 2) > 6 || {(_dangerPos select 2) < 2}) then {_dangerPos set [2, 1]}; +}; // vehicle type ~ Artillery private _artillery = _vehicle getVariable [QEGVAR(main,isArtillery), getNumber (configOf _vehicle >> "artilleryScanner") > 0]; @@ -78,8 +86,8 @@ if (_vehicle isKindOf "Air") exitWith { private _static = _vehicle isKindOf "StaticWeapon"; if (_static) exitWith { - // get out if enemy near - if ((_unit findNearestEnemy _dangerPos) distance _vehicle < (6 + random 15)) then { + // get out if enemy near OR out of ammunition + if ((count (magazines _vehicle)) isEqualTo 0 || {(_vehicle findNearestEnemy _vehicle) distance _vehicle < (6 + random 15)}) then { (units _unit) orderGetIn false; _unit setSuppression 0.94; // to prevent instant laser aim on exiting vehicle }; @@ -122,6 +130,9 @@ if (_armored && {!isNull _dangerCausedBy}) exitWith { private _validTarget = (side _unit) isNotEqualTo (side _dangerCausedBy); private _distance = _vehicle distance _dangerCausedBy; + // keep cargo aboard! + _vehicle setUnloadInCombat [false, false]; + // vehicle jink private _oldDamage = _vehicle getVariable [QGVAR(vehicleDamage), 0]; if (_validTarget && {_distance < (12 + random 15) || {damage _vehicle > _oldDamage}}) exitWith { @@ -130,21 +141,6 @@ if (_armored && {!isNull _dangerCausedBy}) exitWith { [_timeout + _delay] + _causeArray }; - // tank assault - if (_attack && {speed _vehicle < 20}) then { - // rotate - [_vehicle, _dangerCausedBy] call EFUNC(main,doVehicleRotate); - - // assault - if (_distance < 750 && {_dangerCausedBy isKindOf "Man"}) then { - [ - {_this call EFUNC(main,doVehicleAssault)}, - [_unit, _dangerPos, _dangerCausedBy], - _delay - 1 - ] call CBA_fnc_waitAndExecute; - }; - }; - // foot infantry support ~ unload private _group = group _vehicle; private _cargo = ((fullCrew [_vehicle, "cargo"]) apply {_x select 0}); @@ -152,23 +148,46 @@ if (_armored && {!isNull _dangerCausedBy}) exitWith { if ( _validTarget && {_cargo isNotEqualTo []} - && {!(terrainIntersectASL [eyePos _vehicle, (eyePos _dangerCausedBy) vectorAdd [0, 0, 3]]) || {_distance < 300}} - && {_unit knowsAbout _dangerCausedBy > 1} - ) then { + && {speed _vehicle < 10} + && {_distance < 350} + && {_unit knowsAbout _dangerCausedBy > 2 || {_distance < 220}} + && {!(terrainIntersectASL [eyePos _vehicle, (eyePos _dangerCausedBy) vectorAdd [0, 0, 2]]) || {_distance < 200}} + ) exitWith { // define enemy direction _group setFormDir (_vehicle getDir _dangerCausedBy); + _cargo doMove _dangerPos; // delayed unload [ { params [["_cargo", []], ["_side", EAST], ["_vehicle", objNull]]; _cargo orderGetIn false; + _cargo allowGetIn false; if (EGVAR(main,debug_functions)) then {["%1 %2 unloading %3 carried troops", _side, getText (configOf _vehicle >> "displayName"), count _cargo] call EFUNC(main,debugLog);}; }, [_cargo, side _group, _vehicle], - _delay * 2 + 0.1 ] call CBA_fnc_waitAndExecute; + + // exit + [_timeout + _delay + 1] + _causeArray + }; + + // tank assault + if (_attack && {speed _vehicle < 20}) then { + + // rotate + [_vehicle, _dangerPos] call EFUNC(main,doVehicleRotate); + + // assault + if (_distance < 750 && {_dangerCausedBy isKindOf "Man"}) then { + [ + {_this call EFUNC(main,doVehicleAssault)}, + [_unit, _dangerPos, _dangerCausedBy], + _delay - 1 + ] call CBA_fnc_waitAndExecute; + }; }; // timeout @@ -183,20 +202,19 @@ if (_car) exitWith { private _delay = 0; private _slow = speed _vehicle < 30; - // look to danger - if (!isNull _dangerCausedBy && {_vehicle knowsAbout _dangerCausedBy > 3}) then {_vehicle doWatch ATLtoASL (_vehicle getHideFrom _dangerCausedBy);}; - - // escape - if (_slow && {_vehicle distance _dangerCausedBy < (15 + random 35)}) then { + // escape ~ if enemy within 15-50 meters or explosions are nearby! + if (_slow && {_cause isEqualTo DANGER_EXPLOSION || {_vehicle distanceSqr _dangerCausedBy < (225 + random 1225)}}) exitWith { [_unit] call EFUNC(main,doVehicleJink); - _slow = false; - _delay = 3; + [_timeout + 3] + _causeArray }; + // look to danger + if (_attack && {_vehicle knowsAbout _dangerCausedBy > 3}) then {_vehicle doWatch (AGLtoASL _dangerPos);}; + // suppression if (_attack && {_slow}) then { - [_unit, (_unit getHideFrom _dangerCausedBy) vectorAdd [0, 0, random 1]] call EFUNC(main,doVehicleSuppress); - [{_this call EFUNC(main,doVehicleSuppress)}, [_unit, _dangerPos], 3] call CBA_fnc_waitAndExecute; + [_unit, _dangerPos vectorAdd [0, 0, random 1]] call EFUNC(main,doVehicleSuppress); + [{_this call EFUNC(main,doVehicleSuppress)}, [_unit, _dangerPos vectorAdd [0, 0, random 2]], 3] call CBA_fnc_waitAndExecute; _delay = random 4; }; diff --git a/addons/danger/functions/fnc_tacticsAssess.sqf b/addons/danger/functions/fnc_tacticsAssess.sqf index 6db6870d..d0fabe6e 100644 --- a/addons/danger/functions/fnc_tacticsAssess.sqf +++ b/addons/danger/functions/fnc_tacticsAssess.sqf @@ -33,7 +33,7 @@ private _group = group _unit; // set variable _group setVariable [QGVAR(isExecutingTactic), true]; _group setVariable [QGVAR(contact), time + 600]; -_group enableAttack false; +if (isNull objectParent _unit) then {_group enableAttack false;}; // set current task _unit setVariable [QEGVAR(main,currentTarget), objNull, EGVAR(main,debug_functions)]; diff --git a/addons/danger/functions/fnc_tacticsFlank.sqf b/addons/danger/functions/fnc_tacticsFlank.sqf index 74f70142..4d353571 100644 --- a/addons/danger/functions/fnc_tacticsFlank.sqf +++ b/addons/danger/functions/fnc_tacticsFlank.sqf @@ -108,7 +108,7 @@ _group setFormation "FILE"; { _x setUnitPos "DOWN"; _x setVariable [QGVAR(forceMove), true]; -} foreach _units; +} foreach (_units select {isNull objectParent _x}); // leader smoke ~ deploy concealment to enable movement if (!GVAR(disableAutonomousSmokeGrenades)) then {[_unit, _overwatch] call EFUNC(main,doSmoke);}; diff --git a/addons/main/functions/GroupAction/fnc_doGroupFlank.sqf b/addons/main/functions/GroupAction/fnc_doGroupFlank.sqf index e79b3d90..53e516f0 100644 --- a/addons/main/functions/GroupAction/fnc_doGroupFlank.sqf +++ b/addons/main/functions/GroupAction/fnc_doGroupFlank.sqf @@ -46,11 +46,15 @@ private _posASL = AGLtoASL (selectRandom _pos); } foreach _units; // vehicles -{ - private _posAGL = selectRandom _pos; - _x doWatch _posAGL; - [_x, _posAGL] call FUNC(doVehicleSuppress); -} foreach _vehicles; +if (_cycle isEqualTo 1) then { + { + private _posAGL = selectRandom _pos; + _x doWatch _posAGL; + [_x, _posAGL] call FUNC(doVehicleSuppress); + } foreach _vehicles; +} else { + _vehicles doMove _overwatch; +}; // recursive cyclic if !(_cycle <= 1 || {_units isEqualTo []}) then { diff --git a/addons/main/functions/GroupAction/fnc_doGroupStaticFind.sqf b/addons/main/functions/GroupAction/fnc_doGroupStaticFind.sqf index 10334fba..4c35cfa9 100644 --- a/addons/main/functions/GroupAction/fnc_doGroupStaticFind.sqf +++ b/addons/main/functions/GroupAction/fnc_doGroupStaticFind.sqf @@ -35,7 +35,7 @@ if (_units isEqualTo []) exitWith { _units }; // man empty statics private _weapons = nearestObjects [_unit, ["StaticWeapon"], 75, true]; -_weapons = _weapons select { simulationEnabled _x && { !isObjectHidden _x } && { locked _x != 2 } && { (_x emptyPositions "Gunner") > 0 } }; +_weapons = _weapons select { simulationEnabled _x && { !isObjectHidden _x } && { locked _x != 2 } && { (_x emptyPositions "Gunner") > 0 } && { (count magazines _x) > 0 } }; // orders if !((_weapons isEqualTo []) || (_units isEqualTo [])) then { // De Morgan's laws FTW diff --git a/addons/main/functions/UnitAction/fnc_doFleeing.sqf b/addons/main/functions/UnitAction/fnc_doFleeing.sqf index 42300742..00bdae7d 100644 --- a/addons/main/functions/UnitAction/fnc_doFleeing.sqf +++ b/addons/main/functions/UnitAction/fnc_doFleeing.sqf @@ -39,12 +39,13 @@ _unit setVariable [QGVAR(currentTarget), objNull, GVAR(debug_functions)]; [QGVAR(OnFleeing), [_unit, group _unit]] call FUNC(eventCallback); // Abandon vehicles in need! +private _vehicle = vehicle _unit; if ( RND(0.5) && {!_onFoot} - && {canUnloadInCombat (vehicle _unit)} - && {(speed (vehicle _unit)) < 3} - && {isTouchingGround vehicle _unit} + && {canUnloadInCombat _vehicle || {_vehicle isKindOf "StaticWeapon"}} + && {(speed _vehicle) < 3} + && {isTouchingGround _vehicle} ) exitWith { [_unit] orderGetIn false; _unit setSuppression 1; // prevents instant laser aim - nkenny diff --git a/addons/main/functions/VehicleAction/fnc_doVehicleAssault.sqf b/addons/main/functions/VehicleAction/fnc_doVehicleAssault.sqf index 7eb5ff03..44c4d267 100644 --- a/addons/main/functions/VehicleAction/fnc_doVehicleAssault.sqf +++ b/addons/main/functions/VehicleAction/fnc_doVehicleAssault.sqf @@ -46,13 +46,17 @@ if (_buildings isNotEqualTo []) then { }; // add predicted location -- just to ensure shots fired! -if (_buildings isEqualTo []) then {_buildings pushBack _predictedPos;}; +if (_buildings isEqualTo []) then { + _predictedPos = ASLtoAGL (ATLtoASL _predictedPos); + if ((_predictedPos select 2) > 6) then {_predictedPos set [2, 0.5]}; + _buildings pushBack _predictedPos; +}; // pos _pos = selectRandom _buildings; // look at position -_vehicle doWatch _pos; +_vehicle doWatch (AGLtoASL _pos); // suppression private _suppression = [_unit, _pos] call FUNC(doVehicleSuppress); diff --git a/addons/main/functions/VehicleAction/fnc_doVehicleRotate.sqf b/addons/main/functions/VehicleAction/fnc_doVehicleRotate.sqf index ac8fc39e..def69989 100644 --- a/addons/main/functions/VehicleAction/fnc_doVehicleRotate.sqf +++ b/addons/main/functions/VehicleAction/fnc_doVehicleRotate.sqf @@ -23,24 +23,25 @@ params ["_unit", ["_target", []], ["_threshold", 18]]; if (_target isEqualTo []) then { - _target = getPosATL (_unit findNearestEnemy _unit); + _target = _unit getHideFrom (_unit findNearestEnemy _unit); }; +if (_target isEqualTo [0, 0, 0] || {_unit distanceSqr _target < 2}) exitWith {false}; // cannot move or moving -if (!canMove _unit || {currentCommand _unit isEqualTo "MOVE"}) exitWith {true}; +if (!canMove _unit || {currentCommand _unit isEqualTo "MOVE"}) exitWith {false}; -// CQB tweak -- look instead -if (_unit distance _target < 75) exitWith { - (vehicle _unit) doWatch _target; - true +// CQB tweak -- target within 75m - look instead +if (_unit distanceSqr _target < 5625) exitWith { + (vehicle _unit) doWatch (ATLtoASL _target); + false }; _unit setVariable [QGVAR(currentTarget), _target, GVAR(debug_functions)]; _unit setVariable [QGVAR(currentTask), "Vehicle Rotate", GVAR(debug_functions)]; -// within acceptble limits -- suppress instead +// within acceptble limits if (_unit getRelDir _target < _threshold || {_unit getRelDir _target > (360-_threshold)}) exitWith { - true + false }; // settings