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(getIn);
PREP(compatibleMagazines);
PREP(getCarryMagazine);
PREP(getNearbySources);
PREP(getSourceCompatibleMagazines);
PREP(proxyWeapon);
PREP(reload_actionsLoad);

View File

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

View File

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

View File

@ -16,67 +16,29 @@
params ["_staticWeapon", "_gunner", "_weapon"];
TRACE_3("AI reload",_staticWeapon,_gunner,_weapon);
private _turretPath = [_gunner] call EFUNC(common,getTurretIndex);
private _reloadSource = objNull;
private _reloadMag = "";
private _reloadNeededAmmo = -1;
private _loadableMagazines = [_staticWeapon, _gunner, true] call FUNC(reload_getLoadableMagazines);
if (_loadableMagazines isEqualTo []) exitWith {TRACE_1("could not find reloadable mag",_staticWeapon)};
private _cfgMagGroups = configFile >> QGVAR(groups);
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
private _bestAmmo = 0;
private _magazineInfo = [];
{
scopeName "findSource";
private _xSource = _x;
_x params ["", "", "", "", "", "_ammo"];
if (_ammo > _bestAmmo) then {
_bestAmmo = _ammo;
_magazineInfo = _x;
};
} forEach _loadableMagazines;
private _cswMagazines = (magazineCargo _xSource) select {isClass (_cfgMagGroups >> _x)};
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");};
_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);
// see fnc_reload_loadMagazine #L54
// 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;
if !(isNull (configOf _staticWeapon >> QUOTE(ADDON) >> "ammoLoadTime")) then {
_timeToLoad = getNumber (configOf _staticWeapon >> QUOTE(ADDON) >> "ammoLoadTime");
};
private _timeToLoad = GET_NUMBER(configOf _staticWeapon >> QUOTE(ADDON) >> "ammoLoadTime", 1);
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);};
// 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;
}, _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:
* "1Rnd_GAT_missiles" call ace_csw_fnc_getCarryMagazine
*
* Public: No
* Public: Yes
*/
params ["_vehicleMag"];
params [["_vehicleMag", "", [""]]];
private _carryMag = GVAR(vehicleMagCache) get _vehicleMag;
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); };
// 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);
_staticWeapon removeWeaponTurret [_currentWeapon, _turret];
_staticWeapon addWeaponTurret [_proxyWeapon, _turret];

View File

@ -23,9 +23,9 @@ private _loadableMagazines = [_vehicle, _player] call FUNC(reload_getLoadableMag
private _statement = {
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 = {

View File

@ -5,7 +5,8 @@
*
* Arguments:
* 0: Vehicle <OBJECT>
* 1: Player <OBJECT>
* 1: Unit <OBJECT>
* 2: AI reloading, skip turret checks <BOOL> (default: false)
*
* Return Value:
* Mags <ARRAY>
@ -17,55 +18,48 @@
* 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
// filter enemy & player units while allowing pulling from friendly AI, crates, etc
private _sources = [_player] call FUNC(getNearbySources);
// send the mag source with the highest ammo
private _bestMagAmmo = createHashMap;
private _sources = [_unit] call FUNC(getNearbySources);
{
// 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 _cswMags = (magazinesAmmoCargo _xSource) select {isClass (_magGroupsConfig >> _x select 0)};
{
_x params ["_classname", "_ammo"];
if (_ammo > (_bestMagAmmo getOrDefault [_classname, 0])) then {
_bestMagAmmo set [_classname, _ammo];
_availableMagazines set [_classname, _xSource];
if (_classname in _handledSourceMags) then {continue};
_handledSourceMags pushBack _classname;
// 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;
if (_availableMagazines isEqualTo createHashMap) exitWith {[]}; // fast exit if no available mags
private _loadInfo = [];
private _return = [];
private _turretPath = [_unit] call EFUNC(common,getTurretIndex);
// 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 _weapon = _x;
{
//IGNORE_PRIVATE_WARNING ["_x", "_y"];
private _carryMag = _x;
private _magSource = _y;
private _carryGroup = _magGroupsConfig >> _carryMag;
{
if (
((getNumber (_carryGroup >> _x)) == 1) &&
{_loadInfo = [_vehicle, _turretPath, _carryMag, _magSource] call FUNC(reload_canLoadMagazine); _loadInfo select 0}
) exitWith {
_return pushBack [_carryMag, _turretPath, _loadInfo, _magSource, _player];
_y params ["_magSource", "_ammo"];
_loadInfo = [_vehicle, _turretPath, _carryMag] call FUNC(reload_canLoadMagazine);
if (_loadInfo select 0) then {
_return pushBack [_carryMag, _turretPath, _loadInfo, _magSource, _unit, _ammo];
};
} forEach (compatibleMagazines _weapon);
} forEach _availableMagazines;
} forEach (_vehicle weaponsTurret _turretPath);
} forEach (allTurrets _vehicle);
// Note: these nested forEach's looks terrible, but most only have one element
} forEach ([(allTurrets _vehicle), [_turretPath]] select _aiReload);
_return

View File

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

View File

@ -19,57 +19,41 @@
* Public: No
*/
params ["_vehicle", "_turret", "_carryMag", "_magSource", "_unit"];
TRACE_5("loadMagazine",_vehicle,_turret,_carryMag,_magSource,_unit);
params ["_vehicle", "_turret", "_carryMag", "_magSource", "_unit", "_ammo"];
TRACE_6("loadMagazine",_vehicle,_turret,_carryMag,_magSource,_unit,_ammo);
private _timeToLoad = 1;
if (!isNull(configOf _vehicle >> QUOTE(ADDON) >> "ammoLoadTime")) then {
_timeToLoad = getNumber(configOf _vehicle >> QUOTE(ADDON) >> "ammoLoadTime");
};
private _timeToLoad = GET_NUMBER(configOf _vehicle >> QUOTE(ADDON) >> "ammoLoadTime", 1);
private _displayName = format [localize LSTRING(loadX), getText (configFile >> "CfgMagazines" >> _carryMag >> "displayName")];
private _onFinish = {
(_this select 0) params ["_vehicle", "_turret", "_carryMag", "_magSource", "_unit"];
TRACE_5("load progressBar finish",_vehicle,_turret,_carryMag,_magSource,_unit);
(_this select 0) params ["_vehicle", "_turret", "_carryMag", "_magSource", "_unit", "_ammo"];
TRACE_6("load progressBar finish",_vehicle,_turret,_carryMag,_magSource,_unit,_ammo);
([_vehicle, _turret, _carryMag, _magSource] call FUNC(reload_canLoadMagazine)) params ["", "", "_neededAmmo", ""];
if (_neededAmmo <= 0) exitWith { ERROR_1("Can't load ammo - %1",_this); };
// Figure out what we can add from the magazines we have
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);
[_magSource, _carryMag, _ammo] call EFUNC(common,removeSpecificMagazine);
private _nearUnits = _vehicle nearEntities ["CAManBase", 5];
[QGVAR(clearNearbySourcesCache), [], _nearUnits] call CBA_fnc_targetEvent;
if (_bestAmmoToSend == 0) exitWith {};
private _returnTo = _magSource;
// 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
// TODO: remove after 2.14
if (_magSource isKindOf "WeaponHolder") then {
_returnTo = _unit;
};
TRACE_6("calling addTurretMag event",_vehicle,_turret,_magSource,_carryMag,_bestAmmoToSend, _unit);
[QGVAR(addTurretMag), [_vehicle, _turret, _magSource, _carryMag, _bestAmmoToSend, _unit, _returnTo]] call CBA_fnc_globalEvent;
TRACE_6("calling addTurretMag event",_vehicle,_turret,_magSource,_carryMag,_ammo, _unit);
[QGVAR(addTurretMag), [_vehicle, _turret, _magSource, _carryMag, _ammo, _unit, _returnTo]] call CBA_fnc_globalEvent;
};
[
TIME_PROGRESSBAR(_timeToLoad),
[_vehicle, _turret, _carryMag, _magSource, _unit],
[_vehicle, _turret, _carryMag, _magSource, _unit, _ammo],
_onFinish,
{TRACE_1("load progressBar fail",_this);},
_displayName,

View File

@ -17,6 +17,7 @@
#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 RELATIVE_DIRECTION(direction) [DISTANCE_FROM_GUN, direction]