From 07ac508f4d92547efcc8745cf7f7bcd9c341b8c9 Mon Sep 17 00:00:00 2001 From: John Jordan Date: Fri, 23 Aug 2024 19:07:03 +0100 Subject: [PATCH 1/2] Implement mortar/artillery support ranging shot and walking barrage --- .../functions/Supports/fn_SUP_artillery.sqf | 2 +- .../core/functions/Supports/fn_SUP_mortar.sqf | 2 +- .../Supports/fn_SUP_mortarRoutine.sqf | 100 ++++++++++-------- 3 files changed, 56 insertions(+), 48 deletions(-) diff --git a/A3A/addons/core/functions/Supports/fn_SUP_artillery.sqf b/A3A/addons/core/functions/Supports/fn_SUP_artillery.sqf index 55dc91f24b..121a55a867 100644 --- a/A3A/addons/core/functions/Supports/fn_SUP_artillery.sqf +++ b/A3A/addons/core/functions/Supports/fn_SUP_artillery.sqf @@ -59,7 +59,7 @@ if (_target isEqualType objNull) then { // name, side, suppType, pos, radius, remTargets, targets private _suppData = [_supportName, _side, "ARTILLERY", markerPos _base, _maxRange, _targArray, _minRange]; A3A_activeSupports pushBack _suppData; -[_suppData, _vehicle, _group, _delay, _reveal] spawn A3A_fnc_SUP_mortarRoutine; +[_suppData, _vehicle, _group, _delay, _reveal, true] spawn A3A_fnc_SUP_mortarRoutine; [_reveal, _side, "ARTILLERY", _targPos, _delay] spawn A3A_fnc_showInterceptedSetupCall; diff --git a/A3A/addons/core/functions/Supports/fn_SUP_mortar.sqf b/A3A/addons/core/functions/Supports/fn_SUP_mortar.sqf index 51b7ba5e32..611ad0c58e 100644 --- a/A3A/addons/core/functions/Supports/fn_SUP_mortar.sqf +++ b/A3A/addons/core/functions/Supports/fn_SUP_mortar.sqf @@ -78,7 +78,7 @@ if (_target isEqualType objNull) then { // name, side, suppType, pos, radius, remTargets, targets private _suppData = [_supportName, _side, "MORTAR", _spawnParams#0, _maxRange, _targArray, _minRange]; A3A_activeSupports pushBack _suppData; -[_suppData, _vehicle, _group, _delay, _reveal] spawn A3A_fnc_SUP_mortarRoutine; +[_suppData, _vehicle, _group, _delay, _reveal, false] spawn A3A_fnc_SUP_mortarRoutine; [_reveal, _side, "MORTAR", _targPos, _delay] spawn A3A_fnc_showInterceptedSetupCall; diff --git a/A3A/addons/core/functions/Supports/fn_SUP_mortarRoutine.sqf b/A3A/addons/core/functions/Supports/fn_SUP_mortarRoutine.sqf index 0da65a980a..6663c47bad 100644 --- a/A3A/addons/core/functions/Supports/fn_SUP_mortarRoutine.sqf +++ b/A3A/addons/core/functions/Supports/fn_SUP_mortarRoutine.sqf @@ -8,63 +8,52 @@ Arguments: Crew group of mortar/artillery vehicle Delay time in seconds Amount of information to reveal to rebels, 0-1 - + True if it's heavy artillery, false if mortar/light */ #include "..\..\script_component.hpp" FIX_LINE_NUMBERS() -params ["_suppData", "_mortar", "_crewGroup", "_sleepTime", "_reveal","_isHeavyArty"]; +params ["_suppData", "_mortar", "_crewGroup", "_sleepTime", "_reveal", "_isHeavyArty"]; _suppData params ["_supportName", "_side", "_suppType", "_suppCenter", "_suppRadius", "_target"]; //Sleep to simulate the time it would need to set the support up sleep _sleepTime; -//Decrease number of rounds and time alive if aggro is low -private _sideAggression = if(_side == Occupants) then {aggressionOccupants} else {aggressionInvaders}; -private _numberOfRounds = 24; private _timeAlive = 1200; - -//If the aggro is low, the mortar will shoot less and stay longer in one spot -if((30 + random 40) >_sideAggression) then -{ - _numberOfRounds = 12; - _timeAlive = 1800; -}; -private _shotsPerVolley = _numberOfRounds / 3; +private _shotsPerVolley = 8; +private _maxVolleys = 3; +private _reloadTime = [3,10] select _isHeavyArty; +private _spreadOffset = [100, 200] select _isHeavyArty; //A function to repeatedly fire onto a target without loops by using an EH private _fn_executeMortarFire = { params ["_mortar"]; - _mortar addEventHandler - [ - "Fired", - { - params ["_mortar"]; - - private _subTargets = _mortar getVariable ["FireOrder", []]; - if(count _subTargets == 0) exitWith - { - _mortar removeEventHandler ["Fired", _thisEventHandler]; - _mortar setVariable ["FireOrder", nil]; - }; - private _shellTarget = _subTargets deleteAt 0; - - [_shellTarget, _mortar] spawn - { - params ["_shellTarget", "_mortar"]; - sleep 1; - _mortar doArtilleryFire [_shellTarget, _mortar getVariable "shellType", 1]; - } + _mortar addEventHandler ["Fired", { + params ["_mortar"]; + + private _subTargets = _mortar getVariable ["FireOrder", []]; + if (_subTargets isEqualTo []) exitWith { + _mortar removeEventHandler ["Fired", _thisEventHandler]; + _mortar setVariable ["FireOrder", nil]; + }; + (_subTargets deleteAt 0) params ["_shotPos", "_delayTime"]; + + [_shotPos, _delayTime, _mortar] spawn { + params ["_shotPos", "_delayTime", "_mortar"]; + sleep _delayTime; + _mortar doArtilleryFire [_shotPos, _mortar getVariable "shellType", 1]; } - ]; + }]; - sleep 30; // Give players a bit more warning before the shells land private _subTargets = _mortar getVariable ["FireOrder", []]; - private _target = _subTargets deleteAt 0; - _mortar doArtilleryFire [_target, _mortar getVariable "shellType", 1]; + + // Fire first shot after specified delay + (_subTargets deleteAt 0) params ["_shotPos", "_delayTime"]; + sleep _delayTime; + _mortar doArtilleryFire [_shotPos, _mortar getVariable "shellType", 1]; }; @@ -101,34 +90,53 @@ while {time < _timeout} do if !(isNil {_mortar getVariable "FireOrder"}) then { continue }; // mortar still firing at last target - if (_numberOfRounds <= 0) exitWith { + if (_maxVolleys <= 0) exitWith { Info_1("%1 has no more rounds left to fire, aborting routine", _supportName); }; // Read in new target if there is one if (_target isEqualTo []) then { continue }; // no new target added yet + _mortar setVehicleAmmo 1; private _targetPos = _target select 1; // only use position here, not target object _target resize 0; // clear target array so that a new one can be added externally Debug_2("%1 Next target is %2", _supportName, _targetPos); - // 50m circular spread because it's easy + private _flightTime = _mortar getArtilleryETA [_targetPos, _mortar getVariable "shellType"]; private _subTargets = []; - for "_i" from 1 to _shotsPerVolley do { - _subTargets pushBack (_targetPos getPos [random 50, random 360]); + _subTargets pushBack [_targetPos getPos [_spreadOffset, random 360], 20]; // ranging shot + + // Other shots draw a line through the target + private _targDir = getPosATL _mortar vectorFromTo _targetPos; + private _startPos = _targetPos vectorAdd (_targDir vectorMultiply -0.5*_spreadOffset); + private _increment = _targDir vectorMultiply (_spreadOffset / (_shotsPerVolley-2)); + + _subTargets pushBack [_startPos, _flightTime]; + for "_i" from 1 to (_shotsPerVolley-2) do { + private _shotPos = _startPos vectorAdd (_increment vectorMultiply _i); + _subTargets pushBack [_shotPos, _reloadTime]; }; +/* + // First shot 100/200m ranging, last on point, rest 50m random spread because it's easy + private _firstShotPos = _targetPos getPos [[100, 200] select _isHeavyArty, random 360]; + _subTargets pushBack [_firstShotPos, 20]; + _subTargets pushBack [_targetPos getPos [random 50, random 360], _flightTime]; + for "_i" from 3 to (_shotsPerVolley-1) do { + _subTargets pushBack [_targetPos getPos [random 50, random 360], _reloadTime]; + }; + _subTargets pushBack [_targetPos, _reloadTime]; +*/ // Start shooting _mortar setVariable ["FireOrder", _subTargets]; [_mortar, _targetPos] spawn _fn_rotateToTarget; [_mortar] spawn _fn_executeMortarFire; - _numberOfRounds = _numberOfRounds - _shotsPerVolley; - _timeout = _timeout max (time + 60); // don't cleanup until the volley is done + _maxVolleys = _maxVolleys - 1; //Makes sure that all units escape before attacking // [_side, _targetMarker] spawn A3A_fnc_clearTargetArea; - private _flightTime = _mortar getArtilleryETA [_targetPos, _mortar getVariable "shellType"]; - private _reloadTime = [10,3] select (_mortar isKindOf "StaticMortar"); - [_reveal, _targetPos, _side, _suppType, 150, 30+_flightTime+_reloadTime*_numberOfRounds] spawn A3A_fnc_showInterceptedSupportCall; + private _volleyTime = 20 + _flightTime + _reloadTime*_shotsPerVolley; + [_reveal, _targetPos, _side, _suppType, 150, _volleyTime] spawn A3A_fnc_showInterceptedSupportCall; + _timeout = _timeout max (time + _volleyTime); // don't cleanup until the volley is done }; _mortar removeAllEventHandlers "Fired"; From c1f0b91ff7fc40660b78f6ba9ac2aa28759567fb Mon Sep 17 00:00:00 2001 From: John Jordan Date: Fri, 23 Aug 2024 21:42:03 +0100 Subject: [PATCH 2/2] Artillery support tweaks: - Reduced change of using area supports when aggro is low. - Mortars & artillery may take two ranging shots at longer distances. - Fixed marker timeout. --- .../Supports/fn_SUP_mortarRoutine.sqf | 33 +++++++++---------- .../functions/Supports/fn_requestSupport.sqf | 7 ++-- 2 files changed, 21 insertions(+), 19 deletions(-) diff --git a/A3A/addons/core/functions/Supports/fn_SUP_mortarRoutine.sqf b/A3A/addons/core/functions/Supports/fn_SUP_mortarRoutine.sqf index 6663c47bad..ddec7b08e1 100644 --- a/A3A/addons/core/functions/Supports/fn_SUP_mortarRoutine.sqf +++ b/A3A/addons/core/functions/Supports/fn_SUP_mortarRoutine.sqf @@ -21,7 +21,7 @@ _suppData params ["_supportName", "_side", "_suppType", "_suppCenter", "_suppRad sleep _sleepTime; private _timeAlive = 1200; -private _shotsPerVolley = 8; +private _shotsForEffect = 6; private _maxVolleys = 3; private _reloadTime = [3,10] select _isHeavyArty; private _spreadOffset = [100, 200] select _isHeavyArty; @@ -103,29 +103,31 @@ while {time < _timeout} do private _flightTime = _mortar getArtilleryETA [_targetPos, _mortar getVariable "shellType"]; private _subTargets = []; - _subTargets pushBack [_targetPos getPos [_spreadOffset, random 360], 20]; // ranging shot + + // Ranging shots + if (_mortar distance2d _targetPos - 1500 < random 1500) then { + _subTargets pushBack [_targetPos getPos [_spreadOffset, random 360], 20]; + } else { + _subTargets pushBack [_targetPos getPos [_spreadOffset*1.5, random 360], 20]; + _subTargets pushBack [_targetPos getPos [_spreadOffset*0.75, random 360], _flightTime]; + }; // Other shots draw a line through the target private _targDir = getPosATL _mortar vectorFromTo _targetPos; private _startPos = _targetPos vectorAdd (_targDir vectorMultiply -0.5*_spreadOffset); - private _increment = _targDir vectorMultiply (_spreadOffset / (_shotsPerVolley-2)); + private _increment = _targDir vectorMultiply (_spreadOffset / (_shotsForEffect-1)); _subTargets pushBack [_startPos, _flightTime]; - for "_i" from 1 to (_shotsPerVolley-2) do { + for "_i" from 1 to (_shotsForEffect-1) do { private _shotPos = _startPos vectorAdd (_increment vectorMultiply _i); _subTargets pushBack [_shotPos, _reloadTime]; }; -/* - // First shot 100/200m ranging, last on point, rest 50m random spread because it's easy - private _firstShotPos = _targetPos getPos [[100, 200] select _isHeavyArty, random 360]; - _subTargets pushBack [_firstShotPos, 20]; - _subTargets pushBack [_targetPos getPos [random 50, random 360], _flightTime]; - for "_i" from 3 to (_shotsPerVolley-1) do { - _subTargets pushBack [_targetPos getPos [random 50, random 360], _reloadTime]; - }; - _subTargets pushBack [_targetPos, _reloadTime]; -*/ + private _volleyTime = 0; + { _volleyTime = _volleyTime + (_x#1) } forEach _subTargets; + _timeout = _timeout max (time + _volleyTime); // don't cleanup until the volley is done + [_reveal, _targetPos, _side, _suppType, 150, _volleyTime] spawn A3A_fnc_showInterceptedSupportCall; + // Start shooting _mortar setVariable ["FireOrder", _subTargets]; [_mortar, _targetPos] spawn _fn_rotateToTarget; @@ -134,9 +136,6 @@ while {time < _timeout} do //Makes sure that all units escape before attacking // [_side, _targetMarker] spawn A3A_fnc_clearTargetArea; - private _volleyTime = 20 + _flightTime + _reloadTime*_shotsPerVolley; - [_reveal, _targetPos, _side, _suppType, 150, _volleyTime] spawn A3A_fnc_showInterceptedSupportCall; - _timeout = _timeout max (time + _volleyTime); // don't cleanup until the volley is done }; _mortar removeAllEventHandlers "Fired"; diff --git a/A3A/addons/core/functions/Supports/fn_requestSupport.sqf b/A3A/addons/core/functions/Supports/fn_requestSupport.sqf index 4b3e26e3ea..a09019a878 100644 --- a/A3A/addons/core/functions/Supports/fn_requestSupport.sqf +++ b/A3A/addons/core/functions/Supports/fn_requestSupport.sqf @@ -69,10 +69,13 @@ private _classWeightsHM = call { // Shortcut this for air targets if (_target isKindOf "Air") exitWith { createHashMapFromArray [["AREA", 0], ["TROOPS", 0], ["TARGET", 1]] }; - // AREA has stronger reduction than TROOPS but over a smaller area - private _weightArea = 1; + // Some general aggro weighting for area supports + private _aggro = [aggressionInvaders, aggressionOccupants] select (_side == Occupants); + private _weightArea = 0.5 + (_aggro/200); private _weightTarget = 1; private _weightTroops = 1; + + // AREA has stronger reduction than TROOPS but over a smaller area { _x params ["_sside", "_btype", "_starg", "_endtime", "_dur", "_pow"]; if (_sside != _side or time >= _endtime) then { continue };