Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add tank platoon support as alternative to CAS #3274

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions A3A/addons/core/CfgFunctions.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -665,6 +665,9 @@ class CfgFunctions
class SUP_SAM {};
class SUP_SAMAvailable {};
class SUP_SAMRoutine {};
class SUP_tank {};
class SUP_tankAvailable {};
class SUP_tankRoutine {};
class SUP_UAV {};
class SUP_UAVRoutine {};
};
Expand Down
3 changes: 3 additions & 0 deletions A3A/addons/core/Stringtable.xml
Original file line number Diff line number Diff line change
Expand Up @@ -10359,6 +10359,9 @@
<Korean>예상 설정 시간: %1분</Korean>
<Russian>Осталось времени: %1 мин.</Russian>
</Key>
<Key ID="STR_A3A_fn_support_showIntStpCll_TANK">
<Original>%1 just sent a tank platoon.</Original>
</Key>
<Key ID="STR_A3A_fn_support_showIntStpCll_UAV">
<Original>%1 is sending a spotting UAV.</Original>
<Korean>%1 세력이 감시형 UAV를 보냄</Korean>
Expand Down
10 changes: 6 additions & 4 deletions A3A/addons/core/functions/Base/fn_getVehiclesGroundSupport.sqf
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ Arguments:
Return value:
<ARRAY> [vehType, weight, vehType2, weight2, ...]
*/
params ["_side", "_level"];
params ["_side", "_level", ["_tanksOnly", false]];
ante185 marked this conversation as resolved.
Show resolved Hide resolved
_level = (_level max 1 min 10) - 1;
private _faction = [A3A_faction_occ, A3A_faction_inv] select (_side == Invaders);

Expand All @@ -36,14 +36,16 @@ if (_faction get "vehiclesHeavyTanks" isEqualTo []) then { _ltWeight = _ltWeight
if (_faction get "vehiclesLightTanks" isEqualTo []) then { _tankWeight = _tankWeight + _ltWeight };
if (_faction get "vehiclesTanks" isEqualTo []) then { _ltWeight = _ltWeight + _tankWeight };

[_faction get "vehiclesLightTanks", _ltWeight] call _fnc_addArrayToWeights;
[_faction get "vehiclesTanks", _tankWeight] call _fnc_addArrayToWeights;
[_faction get "vehiclesHeavyTanks", _hvytWeight] call _fnc_addArrayToWeights;
if (_tanksOnly) exitWith { _vehWeights };

// only occupants use militia vehicles?
if (_side == Occupants) then {
[_faction get "vehiclesMilitiaLightArmed", _milCarWeight] call _fnc_addArrayToWeights;
};
[_faction get "vehiclesLightArmed", _carWeight] call _fnc_addArrayToWeights;
[_faction get "vehiclesLightTanks", _ltWeight] call _fnc_addArrayToWeights;
[_faction get "vehiclesTanks", _tankWeight] call _fnc_addArrayToWeights;
[_faction get "vehiclesHeavyTanks", _hvytWeight] call _fnc_addArrayToWeights;
[_vehAA, _aaWeight] call _fnc_addArrayToWeights;

_vehWeights;
7 changes: 4 additions & 3 deletions A3A/addons/core/functions/CREATE/fn_createAttackForceLand.sqf
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ Arguments:
<INTEGER> Total number of vehicles to create
<INTEGER> Number of attack/support vehicles to create
<INTEGER> Optional, tier modifier to apply to vehicle selection (Default: 0)
<STRING> Optional, troop type to use (Default: "Normal")
<BOOL> Optional, true to only use tanks (Default: false)
// <STRING> Optional, troop type to use (Default: "Normal")

Return array:
<SCALAR> Resources spent
Expand All @@ -24,7 +25,7 @@ Return array:
#include "..\..\script_component.hpp"
FIX_LINE_NUMBERS()

params ["_side", "_base", "_target", "_resPool", "_vehCount", "_vehAttackCount", ["_tierMod", 0]];
params ["_side", "_base", "_target", "_resPool", "_vehCount", "_vehAttackCount", ["_tierMod", 0], ["_tanksOnly", false]];
private _targpos = if (_target isEqualType []) then { _target } else { markerPos _target };
private _transportRatio = 1 - _vehAttackCount / _vehCount;

Expand All @@ -34,7 +35,7 @@ private _crewGroups = [];
private _cargoGroups = [];

private _transportPool = [_side, tierWar+_tierMod] call A3A_fnc_getVehiclesGroundTransport;
private _supportPool = [_side, tierWar+_tierMod] call A3A_fnc_getVehiclesGroundSupport;
private _supportPool = [_side, tierWar+_tierMod, _tanksOnly] call A3A_fnc_getVehiclesGroundSupport;

private _numTransports = 0;
private _isTransport = _vehAttackCount < _vehCount; // normal case, first vehicle should be a transport
Expand Down
51 changes: 51 additions & 0 deletions A3A/addons/core/functions/Supports/fn_SUP_tank.sqf
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/* Sets up a land QRF support

Environment: Server, scheduled, internal

Arguments:
<STRING> The (unique) name of the support, mostly for logging
<SIDE> The side from which the support should be sent (occupants or invaders)
<STRING> Resource pool used for this support. Should be "attack" or "defence"
<SCALAR> Maximum resources to spend on this support. Must be greater than zero
<OBJECT|BOOL> Initial target, or "false" for none.
<POSITION> Estimated position of target, or center of target zone
<SCALAR> Reveal value 0-1, higher values mean more information provided about support
<SCALAR> Setup delay time in seconds, if negative will calculate based on war tier

Returns:
<SCALAR> Resource cost of support call, or -1 for failure
*/

#include "..\..\script_component.hpp"
FIX_LINE_NUMBERS()

params ["_suppName", "_side", "_resPool", "_maxSpend", "_target", "_targPos", "_reveal", "_delay"];

private _base = [_side, _targPos] call A3A_fnc_availableBasesLand;
ante185 marked this conversation as resolved.
Show resolved Hide resolved
if (isNil "_base") exitWith { Info("Tanks cancelled because no land bases available"); -1 };

// Prevent ground QRFs spawning on top of each other. Should be gone after a minute.
[_base, 1] call A3A_fnc_addTimeForIdle;

private _vehCount = 2 min ceil (_maxSpend / 200);
private _estResources = _vehCount * 200;

// Land QRF delay is purely dependent on travel as they're slow enough already
if (_delay < 0) then { _delay = 0 }; // land QRFs slow enough already
ante185 marked this conversation as resolved.
Show resolved Hide resolved

private _targArray = [];
if (_target isEqualType objNull and {!isNull _target}) then {
// Should probably put a partial "troops" entry in here too?
A3A_supportStrikes pushBack [_side, "TARGET", _target, time + 1800, 1800, 150*_vehCount];
_targArray = [_target, _targPos];
};

// name, side, suppType, center, radius, [target, targpos]
private _suppData = [_supportName, _side, "TANK", _targPos, 1000, _targArray];
A3A_activeSupports pushBack _suppData;
[_suppData, _resPool, _base, _vehCount, _delay, _estResources] spawn A3A_fnc_SUP_tankRoutine;

private _approxTime = _delay + (markerPos _base distance2D _targPos) / (30 / 3.6); // (badly) estimated travel time
[_reveal, _side, "TANK", _targPos, _approxTime] spawn A3A_fnc_showInterceptedSetupCall;

_estResources; // *estimated* resource cost of vehicles
24 changes: 24 additions & 0 deletions A3A/addons/core/functions/Supports/fn_SUP_tankAvailable.sqf
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/* Get tank support selection weight against target

Arguments:
<OBJECT> Target object
<SIDE> Side to send support from
<SCALAR> Max resource spend (not currently used)
<ARRAY> Array of strings of available types for this faction

Return value:
<SCALAR> Weight value, 0 for unavailable or useless
*/

#include "..\..\script_component.hpp"
FIX_LINE_NUMBERS()

params ["_target", "_side", "_maxSpend", "_availTypes"];

if (_target isKindOf "Air") exitWith { 0 }; // can't hit air

if (_target isKindOf "Man") exitWith { 0.001 }; // Don't spawn to attack meatsacks, but re-use active supports

// Against vehicles and statics, use more frequently against more dangerous stuff
private _threat = A3A_groundVehicleThreat getOrDefault [typeOf _target, 0];
0.001 + _threat / 80;
128 changes: 128 additions & 0 deletions A3A/addons/core/functions/Supports/fn_SUP_tankRoutine.sqf
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
/* Create and maintain close air support bomber

Environment: Server, must be spawned

Arguments:
<ARRAY> Active support data, see initSupports
<STRING> Resource pool of support, "attack" or "defence"
<STRING> Marker name of source land base
<NUMBER> Number of tanks to send
<SCALAR> Delay time in seconds
<SCALAR> Estimated resources already spent on support
// <SCALAR> Amount of information to reveal to rebels, 0-1
*/
#include "..\..\script_component.hpp"
FIX_LINE_NUMBERS()

Debug_1("tankRoutine called with %1", _this);

params ["_suppData", "_resPool", "_base", "_vehCount", "_sleepTime", "_estResources"];
_suppData params ["_supportName", "_side", "_suppType", "_suppCenter", "_suppRadius", "_suppTarget"];

sleep _sleepTime;

// Only spawn tanks
private _data = [_side, _base, _suppCenter, _resPool, _vehCount, _vehCount, 2, true] call A3A_fnc_createAttackForceLand;
_data params ["_resources", "_vehicles", "_crewGroups", "_cargoGroups"];
Info_1("Spawn performed: Vehicles %1", _vehicles apply { typeOf _x });

// Update the resource usage for the final value
[_estResources - _resources, _side, _resPool] remoteExec ["A3A_fnc_addEnemyResources", 2];


#define STATE_TRAVEL 1
#define STATE_ACQUIRE 2
#define STATE_ATTACK 3

private _timeOut = time + 1800;
private _remTargets = 2;
private _state = STATE_TRAVEL;
private _targetObj = objNull;

while {true} do
{
private _remVehicles = _vehicles select { canFire _x and canMove _x and side _x == _side };
if (_remVehicles isEqualTo []) exitWith {
Info_1("%1 has been defeated, starting retreat", _supportName);
};
if (time > _timeOut) exitWith {
Info_1("%1 has timed out, starting retreat", _supportName);
};
if (_remTargets <= 0) exitWith {
Info_1("%1 has run out of targets, aborting routine", _supportName);
};

switch (_state) do
{
case STATE_TRAVEL: {
if (_remVehicles inAreaArray [_suppCenter, _suppRadius, _suppRadius] isEqualTo []) exitWith { sleep 5 };

Debug_1("%1 reached patrol zone, acquiring target", _supportName);
_state = STATE_ACQUIRE;
continue;
};

case STATE_ACQUIRE: {
if (_suppTarget isEqualTo []) exitWith { sleep 5 };

_targetObj = _suppTarget select 0;
if !(_targetObj call A3A_fnc_canFight) exitWith {
_suppTarget resize 0;
Debug_1("%1 skips target, as it is already dead", _supportName);
};
Debug_2("Next target for %2 is %1", _suppTarget, _supportName);

private _lastKnownPos = _suppTarget select 1;
private _knownDist = _lastKnownPos distance2d getPosATL _targetObj;
private _knowledge = random 0.3 + _knownDist / _suppRadius;

{
// reveal based on proximity to last known pos
_x reveal [_targetObj, 4*_knowledge];

{ deleteWaypoint _x } forEachReversed (waypoints _x);
private _attackWP = _x addWaypoint [_targetObj, 0];
_attackWP setWaypointType "DESTROY";
_attackWP waypointAttachVehicle _targetObj;
private _sadWP = _x addWaypoint [_lastKnownPos, 0];
_sadWP setWaypointType "SAD";

_x setCurrentWaypoint ([_sadWP, _attackWP] select (_knowledge > random 0.5));
_x setBehaviourStrong "COMBAT";
_x setCombatMode "RED";

} forEach _crewGroups;

_timeout = _timeout + 300;
_state = STATE_ATTACK;
continue;
};

case STATE_ATTACK: {
if (alive _targetObj and {_targetObj distance2D _suppCenter < _suppRadius}) exitWith { sleep 5 };

_remTargets = _remTargets - 1;
_suppTarget resize 0; // clear target array so support routines can add the next

if !(alive _targetObj) then {
Debug_1("Target destroyed, %1 returns to cycle mode", _supportName);
} else {
Debug_1("Target evaded, %1 returns to cycle mode", _supportName);
};

{
_x setBehaviourStrong "AWARE";
_x setCombatMode "YELLOW";
} forEach _crewGroups;

_timeout = _timeout - 300;
_state = STATE_ACQUIRE;
continue;
};
};
};

_suppData set [4, 0]; // Set activesupport radius to 0, enables cleanup

{ [_x] spawn A3A_fnc_VEHDespawner } forEach _vehicles;
{ [_x] spawn A3A_fnc_enemyReturnToBase } forEach (_crewGroups + _cargoGroups);
3 changes: 2 additions & 1 deletion A3A/addons/core/functions/Supports/fn_initSupports.sqf
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,8 @@ private _initData = [
["ARTILLERY", "AREA", 0.5, 0.9, 150, 85, "", "vehiclesArtillery"], // balanced against mortars (50/50 at tier 10), total will be 0.5/0.9
["MORTAR", "AREA", 0.5, 0.9, 100, 50, "", "staticMortars"],
["ASF", "TARGET", 1.0, 0.4, 0, 100, "", "vehiclesPlanesAA"], // balanced against SAMs (if available), 66/33 weighting
["CAS", "TARGET", 1.0, 0.4, 0, 100, "", "vehiclesPlanesCAS"],
["CAS", "TARGET", 0.5, 0.3, 0, 100, "", "vehiclesPlanesCAS"],
["TANK", "TARGET", 0.5, 0.7, 0, 100, "", ""], // balanced against CAS, lowAir based
["QRFLAND", "TROOPS", 1.0, 1.4, 0, 0, "", ""],
["QRFAIR", "TROOPS", 0.5, 0.1, 0, 0, "", ""],
["CARPETBOMBS", "AREA", 0.5, 0.1, 200, 0, "u", ""], // balanced against airstrikes
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,10 @@ else
{
_text = format [localize "STR_A3A_fn_support_showIntStpCll_QRFLAND", _sideName];
};
case ("TANK"):
{
_text = format [localize "STR_A3A_fn_support_showIntStpCll_TANK", _sideName];
};
case ("AIRSTRIKE"):
{
_text = format [localize "STR_A3A_fn_support_showIntStpCll_AIRSTRIKE", _sideName];
Expand Down Expand Up @@ -109,7 +113,7 @@ private _timeStr = if(_setupTime < 60) then { "&lt;1" } else { str round (_setup

if(_reveal >= 0.8) then
{
if(toupper _supportType in ["QRFLAND", "QRFAIR", "COUNTERATTACK", "MAJORATTACK"]) then
if(toupper _supportType in ["QRFLAND", "QRFAIR", "COUNTERATTACK", "MAJORATTACK", "TANK"]) then
{
_text = [_text,format[localize "STR_A3A_fn_support_showIntStpCll_arrivalTime",_timeStr]] joinString " ";
}
Expand Down