Skip to content

Commit

Permalink
Improvements to vehicle Brain (#349)
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
nk3nny authored Feb 18, 2024
1 parent 4e6b530 commit 515f2d9
Show file tree
Hide file tree
Showing 8 changed files with 80 additions and 52 deletions.
80 changes: 49 additions & 31 deletions addons/danger/functions/fnc_brainVehicle.sqf
Original file line number Diff line number Diff line change
Expand Up @@ -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];
Expand All @@ -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
};
Expand Down Expand Up @@ -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 {
Expand All @@ -130,45 +141,53 @@ 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});
_cargo append ((fullCrew [_vehicle, "turret"]) apply {_x select 0});
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
Expand All @@ -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;
};

Expand Down
2 changes: 1 addition & 1 deletion addons/danger/functions/fnc_tacticsAssess.sqf
Original file line number Diff line number Diff line change
Expand Up @@ -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)];
Expand Down
2 changes: 1 addition & 1 deletion addons/danger/functions/fnc_tacticsFlank.sqf
Original file line number Diff line number Diff line change
Expand Up @@ -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);};
Expand Down
14 changes: 9 additions & 5 deletions addons/main/functions/GroupAction/fnc_doGroupFlank.sqf
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
7 changes: 4 additions & 3 deletions addons/main/functions/UnitAction/fnc_doFleeing.sqf
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
8 changes: 6 additions & 2 deletions addons/main/functions/VehicleAction/fnc_doVehicleAssault.sqf
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
17 changes: 9 additions & 8 deletions addons/main/functions/VehicleAction/fnc_doVehicleRotate.sqf
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down

0 comments on commit 515f2d9

Please sign in to comment.