-
Notifications
You must be signed in to change notification settings - Fork 739
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
CSW - Fix and Improve reloading #9234
base: master
Are you sure you want to change the base?
Changes from 49 commits
39f200b
78800be
01dffca
aca90fb
f3c393f
76a2076
5d62ab4
3b42998
d00c9ca
c96a9da
c46dc33
6c2a8a2
ed44c0d
aa8fff3
4b92ef2
e5a9fad
17156d5
078857b
73bc331
cafe1f4
7647123
4e8c69e
8758645
ef93a61
bb9ac71
1818762
22d45be
b7abfea
fac2e61
2b52fee
1cf254a
3c767c6
b51efb1
f5f14b7
1a876af
5e2ffb9
a5b0490
301489b
da21089
a4661f3
c94d29c
ee6a953
179d713
757710b
7fc4c42
a5d4a51
76628c1
3c3790e
1388f44
b0504d7
89491c1
66e417b
18948e4
46c484e
dc52f7a
6656aa6
71dcfb5
9a52511
cf89aad
aae708a
040709e
e877c44
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -6,91 +6,68 @@ | |
* Arguments: | ||
* 0: CSW <OBJECT> | ||
* 1: Gunner <OBJECT> | ||
* 2: Weapon <STRING> | ||
* 3: Magazine <STRING> (default: "") | ||
* 2: Skip reload time <BOOL> (default: false) | ||
* 3: Clear forced magazine after reloading (default: false) | ||
* | ||
* Return Value: | ||
* None | ||
* | ||
* Public: No | ||
*/ | ||
|
||
params ["_vehicle", "_gunner", "_weapon", ["_magazine", ""]]; | ||
params ["_vehicle", "_gunner", ["_instantReload", false], ["_clearForcedMag", false]]; | ||
TRACE_3("AI reload",_vehicle,_gunner,_instantReload); | ||
|
||
private _turretPath = [_gunner] call EFUNC(common,getTurretIndex); | ||
private _reloadSource = objNull; | ||
private _reloadMag = ""; | ||
private _reloadNeededAmmo = -1; | ||
// API, used for ai_switchMagazine | ||
private _forcedMag = _vehicle getVariable [QGVAR(forcedMag), ""]; | ||
private _turretPath = _vehicle unitTurret _gunner; | ||
if (_turretPath isEqualTo []) then { | ||
_turretPath = [0]; | ||
}; | ||
|
||
private _cfgMagGroups = configFile >> QGVAR(groups); | ||
// If this is called while CSW has ammo, unload mags in gunner's turret | ||
if (someAmmo _vehicle) then {[_vehicle, _turretPath] call FUNC(unloadMagazines)}; | ||
johnb432 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
private _nearSupplies = [_gunner] + ((_vehicle nearSupplies 10) select { | ||
isNull (group _x) || | ||
{!([_x] call EFUNC(common,isPlayer)) && {[side group _gunner, side group _x] call BIS_fnc_sideIsFriendly}} | ||
}); | ||
private _loadableMagazines = [_vehicle, _gunner, true] call FUNC(reload_getLoadableMagazines); | ||
if (_loadableMagazines isEqualTo []) exitWith {TRACE_1("could not find reloadable mag",_vehicle)}; | ||
|
||
// Find if there is anything we can reload with | ||
private _bestAmmo = 0; | ||
private _magazineInfo = []; | ||
{ | ||
scopeName "findSource"; | ||
private _xSource = _x; | ||
|
||
private _cswMagazines = []; | ||
{ | ||
_cswMagazines pushBackUnique _x; | ||
} forEach ((magazineCargo _xSource) select {isClass (_cfgMagGroups >> _x)}); | ||
TRACE_2("",_xSource,_cswMagazines); | ||
|
||
private _compatibleMags = compatibleMagazines _weapon; | ||
if (_magazine != "") then { | ||
_compatibleMags insert [0, [_magazine]]; | ||
_x params ["_xMag", "", "", "", "", "_ammo"]; | ||
if (_forcedMag != "" && {_xMag != _forcedMag}) then {continue}; | ||
if (_ammo > _bestAmmo) then { | ||
_bestAmmo = _ammo; | ||
_magazineInfo = _x; | ||
}; | ||
} forEach _loadableMagazines; | ||
|
||
{ | ||
private _xWeaponMag = _x; | ||
{ | ||
if ((getNumber (_cfgMagGroups >> _x >> _xWeaponMag)) == 1) then { | ||
private _loadInfo = [_vehicle, _turretPath, _x, _xSource] call FUNC(reload_canLoadMagazine); | ||
if (_loadInfo select 0) then { | ||
_reloadMag = _x; | ||
_reloadSource = _xSource; | ||
_reloadNeededAmmo = _loadInfo select 2; | ||
TRACE_3("found mag",_reloadMag,_reloadSource,_x); | ||
breakOut "findSource"; | ||
}; | ||
}; | ||
} forEach _cswMagazines; | ||
} forEach _compatibleMags; | ||
} forEach _nearSupplies; | ||
if (_reloadMag == "") exitWith {TRACE_1("could not find mag",_reloadMag);}; | ||
if (_clearForcedMag) then { | ||
_vehicle setVariable [QGVAR(forcedMag), nil, true]; | ||
}; | ||
Comment on lines
+42
to
+44
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Description of |
||
|
||
// Figure out what we can add from the magazines we have | ||
private _bestAmmoToSend = -1; | ||
{ | ||
_x params ["_xMag", "_xAmmo"]; | ||
TRACE_2("",_xMag,_xAmmo); | ||
if (_xMag == _reloadMag) then { | ||
if ((_bestAmmoToSend == -1) || {(_xAmmo > _bestAmmoToSend) && {_xAmmo <= _reloadNeededAmmo}}) then { | ||
_bestAmmoToSend = _xAmmo; | ||
}; | ||
}; | ||
} forEach (if (_reloadSource isKindOf "CAManBase") then {magazinesAmmo _reloadSource} else {magazinesAmmoCargo _reloadSource}); | ||
TRACE_4("",_reloadSource,_reloadMag,_reloadNeededAmmo,_bestAmmoToSend); | ||
if (_bestAmmoToSend == -1) exitWith {ERROR("No ammo");}; | ||
if (_magazineInfo isEqualTo []) exitWith {}; | ||
_magazineInfo params ["_carryMag", "_turretPath", "_loadInfo", "_magSource", "", "_ammo"]; | ||
|
||
// Remove the mag from the source | ||
[_reloadSource, _reloadMag, _bestAmmoToSend] call EFUNC(common,removeSpecificMagazine); | ||
[_magSource, _carryMag, _ammo] call EFUNC(common,removeSpecificMagazine); | ||
|
||
private _timeToLoad = 1; | ||
if (!isNull(configOf _vehicle >> QUOTE(ADDON) >> "ammoLoadTime")) then { | ||
_timeToLoad = getNumber(configOf _vehicle >> QUOTE(ADDON) >> "ammoLoadTime"); | ||
// AI never returns ammo and removes the magazine before reloading, so we can skip distance and weaponHolder checks | ||
private _eventParams = [_vehicle, _turretPath, objNull, _carryMag, _ammo, _gunner]; | ||
|
||
if (_instantReload) exitWith { | ||
TRACE_1("calling addTurretMag event: instant AI reload",_this); | ||
[QGVAR(addTurretMag), _eventParams] call CBA_fnc_globalEvent; | ||
}; | ||
|
||
private _timeToLoad = GET_NUMBER(configOf _vehicle >> QUOTE(ADDON) >> "ammoLoadTime",1); | ||
|
||
TRACE_1("Reloading in progress",_timeToLoad); | ||
[{ | ||
params ["_vehicle", "_turretPath", "_gunner", "_reloadMag", "_bestAmmoToSend"]; | ||
if ((!alive _vehicle) || {!alive _gunner} || {(_vehicle distance _gunner) > 10}) exitWith {TRACE_1("invalid state",_this);}; | ||
params ["_vehicle", "", "", "", "", "_gunner"]; | ||
if !(alive _vehicle && {alive _gunner}) exitWith {TRACE_2("invalid state",alive _vehicle,alive _gunner);}; | ||
|
||
// Reload the static weapon | ||
TRACE_5("calling addTurretMag event",_vehicle,_turretPath,_gunner,_reloadMag,_bestAmmoToSend); | ||
TRACE_1("calling addTurretMag event: AI reload",_this); | ||
[QGVAR(addTurretMag), _this] call CBA_fnc_globalEvent; | ||
johnb432 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
}, [_vehicle, _turretPath, _gunner, _reloadMag, _bestAmmoToSend], _timeToLoad] call CBA_fnc_waitAndExecute; | ||
}, _eventParams, _timeToLoad] call CBA_fnc_waitAndExecute; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
#include "..\script_component.hpp" | ||
/* | ||
* Author: LinkIsGrim | ||
* Handles AI magazine switching. | ||
* Magazine must be compatible and available, use ace_csw_fnc_getAvailableAmmo. | ||
* | ||
* Arguments: | ||
* 0: CSW <OBJECT> | ||
* 1: Carry Magazine <STRING> | ||
* 2: Turret Path <ARRAY> (default: [0]) | ||
* 3: Skip reload time <BOOL> (default: false) | ||
* 4: Clear forced magazine after reloading <BOOL> (default: true) | ||
* | ||
* Return Value: | ||
* Successful <BOOL> | ||
* | ||
* Example: | ||
* [cursorTarget, "ACE_csw_100Rnd_127x99_mag_red", [0]] call ace_csw_fnc_ai_switchMagazine | ||
* | ||
* Public: Yes | ||
*/ | ||
|
||
params [["_vehicle", objNull, [objNull]], ["_carryMag", "", [""]], ["_turretPath", [0], [[0]]], ["_instantReload", false, [false]], ["_clearForcedMag", true, [true]]]; | ||
|
||
if !(alive _vehicle && {!isNull (_vehicle turretUnit _turretPath)} && {!(isNull _vehicle)}) exitWith {false}; | ||
LinkIsGrim marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
// must be config case | ||
_carryMag = configName (configFile >> "CfgMagazines" >> _carryMag); | ||
if (_carryMag isEqualTo "") exitWith {false}; | ||
|
||
private _availableMags = [_vehicle] call FUNC(getAvailableAmmo); | ||
if !(_carryMag in _availableMags) exitWith {false}; | ||
|
||
_vehicle setVariable [QGVAR(forcedMag), _carryMag, true]; | ||
|
||
private _gunner = _vehicle turretUnit _turretPath; | ||
|
||
[QGVAR(ai_reload), [_vehicle, _gunner, _instantReload, _clearForcedMag], _gunner] call CBA_fnc_targetEvent; | ||
|
||
true |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
#include "..\script_component.hpp" | ||
/* | ||
* Author: LinkIsGrim | ||
* Gets all carry magazines that can be loaded into a CSW, includes weapons added by script. | ||
* | ||
* Arguments: | ||
* 0: CSW <OBJECT> | ||
* | ||
* Return Value: | ||
* Compatible Magazines <HASHMAP> | ||
* Magazine classname <STRING> | ||
* Nothing | ||
* | ||
* Example: | ||
* [cursorObject] call ace_csw_fnc_compatibleMagazines | ||
* | ||
* Public: Yes | ||
*/ | ||
|
||
params [["_csw", objNull, [objNull]]]; | ||
|
||
if !((typeOf _csw) in GVAR(initializedStaticTypes)) exitWith {createHashMap}; | ||
|
||
// fast exit for csw with single weapon, most common scenario | ||
if (count allTurrets _csw isEqualTo 1 && {count weapons _csw isEqualTo 1}) exitWith { | ||
+(GVAR(compatibleMagsCache) getOrDefault [(weapons _csw) select 0, createHashMap]) // return | ||
}; | ||
|
||
private _weapons = []; | ||
|
||
{ | ||
private _turret = _x; | ||
{ | ||
_weapons pushBackUnique _x; | ||
} forEach (_csw weaponsTurret _turret); | ||
} forEach (allTurrets _csw); | ||
|
||
if (_weapons isEqualTo []) exitWith {[]}; | ||
|
||
private _carryMagazines = createHashMap; // hashmap for constant lookup | ||
{ | ||
private _weapon = _x; | ||
if !(_weapon in GVAR(compatibleMagsCache)) then {continue}; | ||
_carryMagazines merge [GVAR(compatibleMagsCache) get _weapon, true]; | ||
} forEach _weapons; | ||
Comment on lines
+40
to
+45
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
|
||
+_carryMagazines // return |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
#include "..\script_component.hpp" | ||
/* | ||
* Author: LinkIsGrim | ||
* Gets available ammo for a CSW. | ||
* | ||
* Arguments: | ||
* 0: CSW <OBJECT> | ||
* 1: Only loaded magazines <BOOL> (default: false) | ||
* 2: Skip ammo from vehicles <BOOL> (default: true) | ||
* 3: Include CSW crew <BOOL> (default: true) | ||
* | ||
* Return Value: | ||
* Available Ammo <HASHMAP> | ||
* Magazine classname <STRING> | ||
* Total Ammo <NUMBER> | ||
* | ||
* Example: | ||
* [cursorObject] call ace_csw_fnc_getAvailableAmmo | ||
* | ||
* Public: Yes | ||
*/ | ||
|
||
params [["_vehicle", objNull, [objNull]], ["_onlyLoaded", false, [false]], ["_skipVehicles", true, [true]], ["_includeCrew", true, [true]]]; | ||
|
||
if (isNull _vehicle) exitWith {createHashMap}; | ||
LinkIsGrim marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
private _availableMagazines = createHashMap; | ||
|
||
private _fnc_addAmmo = { | ||
params ["_magazine", "_ammo"]; | ||
if !(_magazine in _availableMagazines) then { | ||
_availableMagazines set [_magazine, _ammo]; | ||
} else { | ||
_availableMagazines set [_magazine, (_availableMagazines get _magazine) + _ammo]; | ||
}; | ||
johnb432 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
}; | ||
|
||
{ | ||
_x params ["_xMag", "", "_xAmmo"]; | ||
|
||
if (_xAmmo <= 0) then {continue}; | ||
|
||
private _carryMag = _xMag call FUNC(getCarryMagazine); | ||
if (_carryMag isEqualTo "") then {continue}; | ||
|
||
[_carryMag, _xAmmo] call _fnc_addAmmo | ||
} forEach (magazinesAllTurrets _vehicle); | ||
|
||
if (_onlyLoaded) exitWith {_availableMagazines}; | ||
|
||
[QGVAR(clearNearbySourcesCache), []] call CBA_fnc_localEvent; | ||
private _sources = [_vehicle, _skipVehicles, _includeCrew] call FUNC(getNearbySources); | ||
if (_sources isEqualTo []) exitWith {_availableMagazines}; | ||
|
||
{ | ||
private _source = _x; | ||
{ | ||
_x call _fnc_addAmmo | ||
} forEach ([_source, _vehicle] call FUNC(getSourceCompatibleMagazines)); | ||
} forEach _sources; | ||
|
||
_availableMagazines // return |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why?
FUNC(reload_getLoadableMagazines)
doesn't follow the same logic, which could lead to a desync of information.