all the things

This commit is contained in:
Salluci 2023-07-13 10:42:30 +03:00
parent 3b42998f7b
commit d00c9ca2a0
13 changed files with 148 additions and 119 deletions

View File

@ -19,8 +19,10 @@ PREP(assemble_pickupWeapon);
PREP(canGetIn); PREP(canGetIn);
PREP(getIn); PREP(getIn);
PREP(compatibleMagazines);
PREP(getCarryMagazine); PREP(getCarryMagazine);
PREP(getNearbySources); PREP(getNearbySources);
PREP(getSourceCompatibleMagazines);
PREP(proxyWeapon); PREP(proxyWeapon);
PREP(reload_actionsLoad); PREP(reload_actionsLoad);

View File

@ -1,7 +1,5 @@
#include "script_component.hpp" #include "script_component.hpp"
GVAR(vehicleMagCache) = createHashMap;
["CBA_settingsInitialized", { ["CBA_settingsInitialized", {
TRACE_3("settingsInit",GVAR(defaultAssemblyMode),GVAR(handleExtraMagazines),GVAR(ammoHandling)); TRACE_3("settingsInit",GVAR(defaultAssemblyMode),GVAR(handleExtraMagazines),GVAR(ammoHandling));
["StaticWeapon", "init", LINKFUNC(staticWeaponInit), true, [], true] call CBA_fnc_addClassEventHandler; ["StaticWeapon", "init", LINKFUNC(staticWeaponInit), true, [], true] call CBA_fnc_addClassEventHandler;

View File

@ -9,6 +9,8 @@ PREP_RECOMPILE_END;
#include "initSettings.sqf" #include "initSettings.sqf"
GVAR(initializedStaticTypes) = []; GVAR(initializedStaticTypes) = [];
GVAR(vehicleMagCache) = createHashMap;
GVAR(compatibleMagsCache) = createHashMap;
GVAR(compatibleVehicleMagsCache) = createHashMap;
ADDON = true; ADDON = true;

View File

@ -16,67 +16,29 @@
params ["_staticWeapon", "_gunner", "_weapon"]; params ["_staticWeapon", "_gunner", "_weapon"];
TRACE_3("AI reload",_staticWeapon,_gunner,_weapon); TRACE_3("AI reload",_staticWeapon,_gunner,_weapon);
private _turretPath = [_gunner] call EFUNC(common,getTurretIndex); private _loadableMagazines = [_staticWeapon, _gunner, true] call FUNC(reload_getLoadableMagazines);
private _reloadSource = objNull; if (_loadableMagazines isEqualTo []) exitWith {TRACE_1("could not find reloadable mag",_staticWeapon)};
private _reloadMag = "";
private _reloadNeededAmmo = -1;
private _cfgMagGroups = configFile >> QGVAR(groups); private _bestAmmo = 0;
private _magazineInfo = [];
private _sources = [_gunner] call FUNC(getNearbySources);
// Find if there is anything we can reload with
// see fnc_reload_getLoadableMagazines, though we don't care about AI pulling from the best ammo possible
{ {
scopeName "findSource"; _x params ["", "", "", "", "", "_ammo"];
private _xSource = _x; if (_ammo > _bestAmmo) then {
_bestAmmo = _ammo;
_magazineInfo = _x;
};
} forEach _loadableMagazines;
private _cswMagazines = (magazineCargo _xSource) select {isClass (_cfgMagGroups >> _x)}; _magazineInfo params ["_carryMag", "_turretPath", "_loadInfo", "_magSource", "", "_ammo"];
TRACE_2("",_xSource,_cswMagazines);
{
private _xWeaponMag = _x;
{
if ((getNumber (_cfgMagGroups >> _x >> _xWeaponMag)) == 1) then {
private _loadInfo = [_staticWeapon, _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 (compatibleMagazines _weapon);
} forEach _sources;
if (_reloadMag == "") exitWith {TRACE_1("could not find mag",_reloadMag);};
// 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");};
// Remove the mag from the source // Remove the mag from the source
[_reloadSource, _reloadMag, _bestAmmoToSend] call EFUNC(common,removeSpecificMagazine); [_magSource, _carryMag, _ammo] call EFUNC(common,removeSpecificMagazine);
// see fnc_reload_loadMagazine #L54 // see fnc_reload_loadMagazine #L54
// AI never returns ammo and removes the magazine before reloading, so we can skip distance and weaponHolder checks // AI never returns ammo and removes the magazine before reloading, so we can skip distance and weaponHolder checks
private _eventParams = [_staticWeapon, _turretPath, objNull, _reloadMag, _bestAmmoToSend, _gunner]; private _eventParams = [_staticWeapon, _turretPath, objNull, _carryMag, _ammo, _gunner];
private _timeToLoad = 1; private _timeToLoad = GET_NUMBER(configOf _staticWeapon >> QUOTE(ADDON) >> "ammoLoadTime", 1);
if !(isNull (configOf _staticWeapon >> QUOTE(ADDON) >> "ammoLoadTime")) then {
_timeToLoad = getNumber (configOf _staticWeapon >> QUOTE(ADDON) >> "ammoLoadTime");
};
TRACE_1("Reloading in progress",_timeToLoad); TRACE_1("Reloading in progress",_timeToLoad);
[{ [{
@ -84,6 +46,6 @@ TRACE_1("Reloading in progress",_timeToLoad);
if !(alive _staticWeapon && {alive _gunner}) exitWith {TRACE_2("invalid state",alive _staticWeapon,alive _gunner);}; if !(alive _staticWeapon && {alive _gunner}) exitWith {TRACE_2("invalid state",alive _staticWeapon,alive _gunner);};
// Reload the static weapon // Reload the static weapon
TRACE_5("calling addTurretMag event: AI reload",_staticWeapon,_turretPath,_gunner,_reloadMag,_bestAmmoToSend); TRACE_1("calling addTurretMag event: AI reload",_this);
[QGVAR(addTurretMag), _this] call CBA_fnc_globalEvent; [QGVAR(addTurretMag), _this] call CBA_fnc_globalEvent;
}, _eventParams, _timeToLoad] call CBA_fnc_waitAndExecute; }, _eventParams, _timeToLoad] call CBA_fnc_waitAndExecute;

View File

@ -0,0 +1,39 @@
#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]]];
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(compatibleVehicleMagsCache)) then {continue};
_carryMagazines merge [GVAR(compatibleMagsCache) get _weapon, true];
} forEach _weapons;
_carryMagazines // return

View File

@ -12,10 +12,10 @@
* Example: * Example:
* "1Rnd_GAT_missiles" call ace_csw_fnc_getCarryMagazine * "1Rnd_GAT_missiles" call ace_csw_fnc_getCarryMagazine
* *
* Public: No * Public: Yes
*/ */
params ["_vehicleMag"]; params [["_vehicleMag", "", [""]]];
private _carryMag = GVAR(vehicleMagCache) get _vehicleMag; private _carryMag = GVAR(vehicleMagCache) get _vehicleMag;
if (isNil "_carryMag") then { if (isNil "_carryMag") then {

View File

@ -0,0 +1,35 @@
#include "script_component.hpp"
/*
* Author: LinkIsGrim
* Gets compatible magazines to load a CSW from a magazine source
*
* Arguments:
* 0: Magazine Source <OBJECT>
* 1: CSW <OBJECT> (default: objNull)
*
* Return Value:
* Magazines <ARRAY>
* Magazine classname <STRING>
* Magazine ammo <NUMBER>
*
* Example:
* [player, cursorObject] call ace_csw_fnc_getSourceCompatibleMagazines
*
* Public: Yes
*/
params [["_source", objNull, [objNull]], ["_csw", objNull, [objNull]]];
if (isNull _source || {isNull _csw}) exitWith {[]};
private _magazines = magazinesAmmoCargo _source;
if (_magazines isEqualTo []) exitWith {[]};
private _compatibleMagazines = [_csw] call FUNC(compatibleMagazines);
private _return = _magazines select {(_x select 0) in _compatibleMagazines};
// sort by ammo count, highest to lowest
_return sort false;
_return

View File

@ -37,6 +37,15 @@ if ((missionNamespace getVariable [_proxyWeapon, objNull]) isEqualType {}) then
}; };
if (!_needed) exitWith { TRACE_2("not needed",_needed,_proxyWeapon); }; if (!_needed) exitWith { TRACE_2("not needed",_needed,_proxyWeapon); };
// Cache compatible magazines
if !(_proxyWeapon in GVAR(compatibleVehicleMagsCache)) then {
private _compatibleMagazines = compatibleMagazines _proxyWeapon;
GVAR(compatibleVehicleMagsCache) set [_proxyWeapon, _compatibleMagazines];
GVAR(compatibleCarryMagsCache) set [_proxyWeapon,
_compatibleMagazines apply {_x call FUNC(getCarryMagazine)} createHashMapFromArray []
];
};
TRACE_2("swapping to proxy weapon",_currentWeapon,_proxyWeapon); TRACE_2("swapping to proxy weapon",_currentWeapon,_proxyWeapon);
_staticWeapon removeWeaponTurret [_currentWeapon, _turret]; _staticWeapon removeWeaponTurret [_currentWeapon, _turret];
_staticWeapon addWeaponTurret [_proxyWeapon, _turret]; _staticWeapon addWeaponTurret [_proxyWeapon, _turret];

View File

@ -23,9 +23,9 @@ private _loadableMagazines = [_vehicle, _player] call FUNC(reload_getLoadableMag
private _statement = { private _statement = {
params ["_target", "_player", "_params"]; params ["_target", "_player", "_params"];
_params params ["_carryMag", "_turretPath", "", "_magSource"]; _params params ["_carryMag", "_turretPath", "", "_magSource", "", "_ammo"];
[_target, _turretPath, _carryMag, _magSource, _player] call FUNC(reload_loadMagazine); [_target, _turretPath, _carryMag, _magSource, _player, _ammo] call FUNC(reload_loadMagazine);
}; };
private _condition = { private _condition = {

View File

@ -5,7 +5,8 @@
* *
* Arguments: * Arguments:
* 0: Vehicle <OBJECT> * 0: Vehicle <OBJECT>
* 1: Player <OBJECT> * 1: Unit <OBJECT>
* 2: AI reloading, skip turret checks <BOOL> (default: false)
* *
* Return Value: * Return Value:
* Mags <ARRAY> * Mags <ARRAY>
@ -17,55 +18,48 @@
* Public: No * Public: No
*/ */
params ["_vehicle", "_player"]; params ["_vehicle", "_unit", ["_aiReload", false]];
private _magGroupsConfig = configFile >> QGVAR(groups); // so we don't solve in loop every time
private _availableMagazines = createHashMap; // slower than array, still needed for setting source of magazine private _availableMagazines = createHashMap; // slower than array, still needed for setting source of magazine
// filter enemy & player units while allowing pulling from friendly AI, crates, etc // filter enemy & player units while allowing pulling from friendly AI, crates, etc
private _sources = [_player] call FUNC(getNearbySources); private _sources = [_unit] call FUNC(getNearbySources);
// send the mag source with the highest ammo
private _bestMagAmmo = createHashMap;
{ {
// minor optimization: since mags are sorted by ammo count in FUNC(getSourceCompatibleMagazines), we only need to check the first mag of this type in this source
private _handledSourceMags = [];
private _xSource = _x; private _xSource = _x;
private _cswMags = (magazinesAmmoCargo _xSource) select {isClass (_magGroupsConfig >> _x select 0)};
{ {
_x params ["_classname", "_ammo"]; _x params ["_classname", "_ammo"];
if (_ammo > (_bestMagAmmo getOrDefault [_classname, 0])) then { if (_classname in _handledSourceMags) then {continue};
_bestMagAmmo set [_classname, _ammo]; _handledSourceMags pushBack _classname;
_availableMagazines set [_classname, _xSource];
// select mag source with the highest ammo
if (_ammo > (_availableMagazines getOrDefault [_classname, [objNull, 0]]) select 1) then {
_availableMagazines set [_classname, [_xSource, _ammo]];
}; };
} forEach _cswMags; } forEach ([_x, _vehicle] call FUNC(getSourceCompatibleMagazines));
} forEach _sources; } forEach _sources;
if (_availableMagazines isEqualTo createHashMap) exitWith { [] }; // fast exit if no available mags if (_availableMagazines isEqualTo createHashMap) exitWith {[]}; // fast exit if no available mags
private _loadInfo = []; private _loadInfo = [];
private _return = []; private _return = [];
private _turretPath = [_unit] call EFUNC(common,getTurretIndex);
// Go through turrets and find weapons that we could reload // Go through turrets and find weapons that we could reload
// We can skip checking all turrets if we're doing AI reloading
{ {
private _turretPath = _x; private _turretPath = _x;
{
private _weapon = _x;
{ {
//IGNORE_PRIVATE_WARNING ["_x", "_y"]; //IGNORE_PRIVATE_WARNING ["_x", "_y"];
private _carryMag = _x; private _carryMag = _x;
private _magSource = _y; _y params ["_magSource", "_ammo"];
private _carryGroup = _magGroupsConfig >> _carryMag; _loadInfo = [_vehicle, _turretPath, _carryMag] call FUNC(reload_canLoadMagazine);
{ if (_loadInfo select 0) then {
if ( _return pushBack [_carryMag, _turretPath, _loadInfo, _magSource, _unit, _ammo];
((getNumber (_carryGroup >> _x)) == 1) &&
{_loadInfo = [_vehicle, _turretPath, _carryMag, _magSource] call FUNC(reload_canLoadMagazine); _loadInfo select 0}
) exitWith {
_return pushBack [_carryMag, _turretPath, _loadInfo, _magSource, _player];
}; };
} forEach (compatibleMagazines _weapon);
} forEach _availableMagazines; } forEach _availableMagazines;
} forEach (_vehicle weaponsTurret _turretPath); } forEach ([(allTurrets _vehicle), [_turretPath]] select _aiReload);
} forEach (allTurrets _vehicle);
// Note: these nested forEach's looks terrible, but most only have one element
_return _return

View File

@ -24,6 +24,9 @@
params ["_vehicle", "_turret", "_magSource", "_carryMag", "_ammoReceived", "_unit"]; params ["_vehicle", "_turret", "_magSource", "_carryMag", "_ammoReceived", "_unit"];
private _returnTo = param [6, _unit]; private _returnTo = param [6, _unit];
if (isNull _returnTo) then {
_returnTo = _vehicle;
};
TRACE_7("reload_handleAddTurretMag",_vehicle,_turret,_magSource,_carryMag,_ammoReceived,_unit,_returnTo); TRACE_7("reload_handleAddTurretMag",_vehicle,_turret,_magSource,_carryMag,_ammoReceived,_unit,_returnTo);
TRACE_2("",local _vehicle, _vehicle turretLocal _turret); TRACE_2("",local _vehicle, _vehicle turretLocal _turret);

View File

@ -19,57 +19,41 @@
* Public: No * Public: No
*/ */
params ["_vehicle", "_turret", "_carryMag", "_magSource", "_unit"]; params ["_vehicle", "_turret", "_carryMag", "_magSource", "_unit", "_ammo"];
TRACE_5("loadMagazine",_vehicle,_turret,_carryMag,_magSource,_unit); TRACE_6("loadMagazine",_vehicle,_turret,_carryMag,_magSource,_unit,_ammo);
private _timeToLoad = 1; private _timeToLoad = GET_NUMBER(configOf _vehicle >> QUOTE(ADDON) >> "ammoLoadTime", 1);
if (!isNull(configOf _vehicle >> QUOTE(ADDON) >> "ammoLoadTime")) then {
_timeToLoad = getNumber(configOf _vehicle >> QUOTE(ADDON) >> "ammoLoadTime");
};
private _displayName = format [localize LSTRING(loadX), getText (configFile >> "CfgMagazines" >> _carryMag >> "displayName")]; private _displayName = format [localize LSTRING(loadX), getText (configFile >> "CfgMagazines" >> _carryMag >> "displayName")];
private _onFinish = { private _onFinish = {
(_this select 0) params ["_vehicle", "_turret", "_carryMag", "_magSource", "_unit"]; (_this select 0) params ["_vehicle", "_turret", "_carryMag", "_magSource", "_unit", "_ammo"];
TRACE_5("load progressBar finish",_vehicle,_turret,_carryMag,_magSource,_unit); TRACE_6("load progressBar finish",_vehicle,_turret,_carryMag,_magSource,_unit,_ammo);
([_vehicle, _turret, _carryMag, _magSource] call FUNC(reload_canLoadMagazine)) params ["", "", "_neededAmmo", ""]; ([_vehicle, _turret, _carryMag, _magSource] call FUNC(reload_canLoadMagazine)) params ["", "", "_neededAmmo", ""];
if (_neededAmmo <= 0) exitWith { ERROR_1("Can't load ammo - %1",_this); }; if (_neededAmmo <= 0) exitWith { ERROR_1("Can't load ammo - %1",_this); };
// Figure out what we can add from the magazines we have [_magSource, _carryMag, _ammo] call EFUNC(common,removeSpecificMagazine);
private _bestAmmoToSend = -1;
{
_x params ["_xMag", "_xAmmo"];
if (_xMag == _carryMag) then {
if ((_bestAmmoToSend == -1) || {(_xAmmo > _bestAmmoToSend) && {_xAmmo <= _neededAmmo}}) then {
_bestAmmoToSend = _xAmmo;
};
};
} forEach (if (_magSource isKindOf "CAManBase") then {magazinesAmmo _magSource} else {magazinesAmmoCargo _magSource});
if (_bestAmmoToSend == -1) exitWith {ERROR_2("No ammo [%1 - %2]?",_xMag,_bestAmmoToSend);};
[_magSource, _carryMag, _bestAmmoToSend] call EFUNC(common,removeSpecificMagazine);
private _nearUnits = _vehicle nearEntities ["CAManBase", 5]; private _nearUnits = _vehicle nearEntities ["CAManBase", 5];
[QGVAR(clearNearbySourcesCache), [], _nearUnits] call CBA_fnc_targetEvent; [QGVAR(clearNearbySourcesCache), [], _nearUnits] call CBA_fnc_targetEvent;
if (_bestAmmoToSend == 0) exitWith {};
private _returnTo = _magSource; private _returnTo = _magSource;
// if we're pulling from a weaponHolder, return the ammo to the unit doing the action // if we're pulling from a weaponHolder, return the ammo to the unit doing the action
// workaround for weaponHolders being recreated with removeSpecificMagazine, magazines will still get dropped if inventory is full // workaround for weaponHolders being recreated with removeSpecificMagazine, magazines will still get dropped if inventory is full
// TODO: remove after 2.14
if (_magSource isKindOf "WeaponHolder") then { if (_magSource isKindOf "WeaponHolder") then {
_returnTo = _unit; _returnTo = _unit;
}; };
TRACE_6("calling addTurretMag event",_vehicle,_turret,_magSource,_carryMag,_bestAmmoToSend, _unit); TRACE_6("calling addTurretMag event",_vehicle,_turret,_magSource,_carryMag,_ammo, _unit);
[QGVAR(addTurretMag), [_vehicle, _turret, _magSource, _carryMag, _bestAmmoToSend, _unit, _returnTo]] call CBA_fnc_globalEvent; [QGVAR(addTurretMag), [_vehicle, _turret, _magSource, _carryMag, _ammo, _unit, _returnTo]] call CBA_fnc_globalEvent;
}; };
[ [
TIME_PROGRESSBAR(_timeToLoad), TIME_PROGRESSBAR(_timeToLoad),
[_vehicle, _turret, _carryMag, _magSource, _unit], [_vehicle, _turret, _carryMag, _magSource, _unit, _ammo],
_onFinish, _onFinish,
{TRACE_1("load progressBar fail",_this);}, {TRACE_1("load progressBar fail",_this);},
_displayName, _displayName,

View File

@ -17,6 +17,7 @@
#include "\z\ace\addons\main\script_macros.hpp" #include "\z\ace\addons\main\script_macros.hpp"
#define GET_NUMBER(config,default) (if (isNumber (config)) then {getNumber (config)} else {default})
#define DISTANCE_FROM_GUN 1.5 #define DISTANCE_FROM_GUN 1.5
#define RELATIVE_DIRECTION(direction) [DISTANCE_FROM_GUN, direction] #define RELATIVE_DIRECTION(direction) [DISTANCE_FROM_GUN, direction]