diff --git a/addons/arsenal/XEH_PREP.hpp b/addons/arsenal/XEH_PREP.hpp index e622ee66b52..6d50704340b 100644 --- a/addons/arsenal/XEH_PREP.hpp +++ b/addons/arsenal/XEH_PREP.hpp @@ -70,6 +70,7 @@ PREP(onSelChangedRightListnBox); PREP(open3DEN); PREP(openBox); PREP(portVALoadouts); +PREP(preventOverfilling); PREP(refresh); PREP(removeAction); PREP(removeBox); @@ -79,6 +80,7 @@ PREP(removeStat); PREP(removeVirtualItems); PREP(renameDefaultLoadout); PREP(replaceUniqueItemsLoadout); +PREP(recoverInvalidContainers); PREP(saveLoadout); PREP(scanConfig); PREP(showItem); diff --git a/addons/arsenal/functions/fnc_buttonImport.sqf b/addons/arsenal/functions/fnc_buttonImport.sqf index 494bf159daa..99a58b566a6 100644 --- a/addons/arsenal/functions/fnc_buttonImport.sqf +++ b/addons/arsenal/functions/fnc_buttonImport.sqf @@ -54,6 +54,11 @@ if (GVAR(shiftState) && {is3DEN}) then { // Check if CBA extended loadout array if ((count _extendedLoadout) == 2) then { + // Verify the loadout and attempt to recover any invalid containers + _extendedLoadout = [_extendedLoadout, true] call FUNC(verifyLoadout); + // Since verification nests the extended loadout array, undo that after container recovery + _extendedLoadout = ([GVAR(center), _extendedLoadout] call FUNC(recoverInvalidContainers)) select 0; + [GVAR(center), _extendedLoadout] call CBA_fnc_setLoadout; // Update current item list and unique items diff --git a/addons/arsenal/functions/fnc_buttonLoadoutsLoad.sqf b/addons/arsenal/functions/fnc_buttonLoadoutsLoad.sqf index 120a50ae9c7..63fbab385d0 100644 --- a/addons/arsenal/functions/fnc_buttonLoadoutsLoad.sqf +++ b/addons/arsenal/functions/fnc_buttonLoadoutsLoad.sqf @@ -37,6 +37,9 @@ private _extendedLoadout = switch (GVAR(currentLoadoutsTab)) do { // Apply loadout to unit [GVAR(center), _extendedLoadout, true] call CBA_fnc_setLoadout; +// Prevent overloading of inventory containers +GVAR(center) call FUNC(preventOverfilling); + // Update current item list and unique items [true] call FUNC(refresh); diff --git a/addons/arsenal/functions/fnc_fillLoadoutsList.sqf b/addons/arsenal/functions/fnc_fillLoadoutsList.sqf index 8dc8ef76a28..6fff05aa870 100644 --- a/addons/arsenal/functions/fnc_fillLoadoutsList.sqf +++ b/addons/arsenal/functions/fnc_fillLoadoutsList.sqf @@ -68,7 +68,9 @@ if (GVAR(currentLoadoutsTab) != IDC_buttonSharedLoadouts) then { // If not in cache, get info and cache it if (isNil "_loadoutCachedInfo") then { - _loadoutCachedInfo = [_loadoutData] call FUNC(verifyLoadout); + // Run verification in "recover" mode to salvage invalid containers, replacing them with those currently being worn + _loadoutCachedInfo = [_loadoutData, true] call FUNC(verifyLoadout); + _loadoutCachedInfo = [GVAR(center), _loadoutCachedInfo] call FUNC(recoverInvalidContainers); _contentPanelCtrl setVariable [_loadoutNameAndTab, _loadoutCachedInfo]; _loadoutCachedInfo params ["", "_nullItemsList", "_unavailableItemsList", "_missingExtendedInfo"]; diff --git a/addons/arsenal/functions/fnc_onSelChangedLeft.sqf b/addons/arsenal/functions/fnc_onSelChangedLeft.sqf index 05b86358f80..f3e0f67f70f 100644 --- a/addons/arsenal/functions/fnc_onSelChangedLeft.sqf +++ b/addons/arsenal/functions/fnc_onSelChangedLeft.sqf @@ -332,14 +332,8 @@ switch (GVAR(currentLeftPanel)) do { _loadout set [IDX_LOADOUT_UNIFORM, [_item, GVAR(currentItems) select IDX_CURR_UNIFORM_ITEMS]]; GVAR(center) setUnitLoadout _loadout; - private _uniformItems = uniformItems GVAR(center); - private _index = count _uniformItems - 1; - // Remove any items that can't fit in the container (this prevents overloading) - while {loadUniform GVAR(center) > 1 && {_index >= 0}} do { - GVAR(center) removeItemFromUniform (_uniformItems select _index); - DEC(_index); - }; + [GVAR(center), uniformContainer GVAR(center)] call FUNC(preventOverfilling); GVAR(currentItems) set [IDX_CURR_UNIFORM, _item]; @@ -373,14 +367,8 @@ switch (GVAR(currentLeftPanel)) do { _loadout set [IDX_LOADOUT_VEST, [_item, GVAR(currentItems) select IDX_CURR_VEST_ITEMS]]; GVAR(center) setUnitLoadout _loadout; - private _vestItems = vestItems GVAR(center); - private _index = count _vestItems - 1; - // Remove any items that can't fit in the container (this prevents overloading) - while {loadVest GVAR(center) > 1 && {_index >= 0}} do { - GVAR(center) removeItemFromVest (_vestItems select _index); - DEC(_index); - }; + [GVAR(center), vestContainer GVAR(center)] call FUNC(preventOverfilling); GVAR(currentItems) set [IDX_CURR_VEST, _item]; @@ -414,14 +402,8 @@ switch (GVAR(currentLeftPanel)) do { _loadout set [IDX_LOADOUT_BACKPACK, [_item, GVAR(currentItems) select IDX_CURR_BACKPACK_ITEMS]]; GVAR(center) setUnitLoadout _loadout; - private _backpackItems = backpackItems GVAR(center); - private _index = count _backpackItems - 1; - // Remove any items that can't fit in the container (this prevents overloading) - while {loadBackpack GVAR(center) > 1 && {_index >= 0}} do { - GVAR(center) removeItemFromBackpack (_backpackItems select _index); - DEC(_index); - }; + [GVAR(center), backpackContainer GVAR(center)] call FUNC(preventOverfilling); GVAR(currentItems) set [IDX_CURR_BACKPACK, _item]; diff --git a/addons/arsenal/functions/fnc_preventOverfilling.sqf b/addons/arsenal/functions/fnc_preventOverfilling.sqf new file mode 100644 index 00000000000..ac628df931e --- /dev/null +++ b/addons/arsenal/functions/fnc_preventOverfilling.sqf @@ -0,0 +1,34 @@ +#include "..\script_component.hpp" +#include "..\defines.hpp" +/* + * Author: Alganthe, johnb43, mrschick + * Checks the current loadout of the given unit for inventory containers (uniform/vest/backpack) filled beyond their max load, removing excess items if present. + * + * Arguments: + * 0: Unit to check for overfill + * 1: Which container to check. If unit, will go through all containers starting from uniform + * + * Return Value: + * None + * + * Public: No +*/ + +params ["_unit", ["_container", objNull]]; + +if (isNull _container || _container isEqualTo _unit) then { + _container = [uniformContainer _unit, vestContainer _unit, backpackContainer _unit]; +} else { + _container = [_container]; +}; + +{ + private _currentContainer = _x; + { + _currentContainer addItemCargoGlobal [_x, -1]; + + if (load _currentContainer <= 1) then { + break; + }; + } forEachReversed (itemCargo _currentContainer); +} forEach (_container select {load _x > 1}); diff --git a/addons/arsenal/functions/fnc_recoverInvalidContainers.sqf b/addons/arsenal/functions/fnc_recoverInvalidContainers.sqf new file mode 100644 index 00000000000..33df241190f --- /dev/null +++ b/addons/arsenal/functions/fnc_recoverInvalidContainers.sqf @@ -0,0 +1,44 @@ +#include "..\script_component.hpp" +#include "..\defines.hpp" +/* + * Author: mrschick + * Attempts to recover a loadout with invalid containers by substituting them for the currently worn containers. + * It is meant to be passed a loadout modified by `[loadout, true] call ace_arsenal_fnc_verifyLoadout`, nested in the format: `[[_loadout, _extendedInfo], _nullItemsList, _unavailableItemsList, _missingExtendedInfo]` + * + * Arguments: + * 0: Unit from which to get valid (worn) containers + * 1: Verified loadout to insert valid containers into + * + * Return Value: + * Copy of the passed loadout, with recovered containers + * + * Public: No +*/ + +params ["_unit", "_loadout"]; + +// Work on a copy of the original array +private _loadoutData = +_loadout; + +{ + _x params ["_containerIdx", "_wornContainer"]; + + // Only modify the loadout if it has a filled invalid container to be recovered + if ( + (_loadoutData#0#0#_containerIdx isNotEqualTo []) && + {_loadoutData#0#0#_containerIdx#0 == ""} + ) then { + // Replace loadout container with worn one, if present + if (_wornContainer == "") then { + (_loadoutData#0#0) set [_containerIdx, []]; + } else { + (_loadoutData#0#0#_containerIdx) set [0, _wornContainer]; + }; + }; +} forEach [ + [3, uniform _unit], + [4, vest _unit], + [5, backpack _unit] +]; + +_loadoutData diff --git a/addons/arsenal/functions/fnc_verifyLoadout.sqf b/addons/arsenal/functions/fnc_verifyLoadout.sqf index 10cd9a25539..259ff3d747d 100644 --- a/addons/arsenal/functions/fnc_verifyLoadout.sqf +++ b/addons/arsenal/functions/fnc_verifyLoadout.sqf @@ -6,6 +6,7 @@ * * Arguments: * 0: Loadout (CBA Extended Loadout or getUnitLoadout format) + * 1: Whether to attempt to recover invalid containers * * Return Value: * Verified loadout and missing / unavailable items list and count @@ -15,7 +16,7 @@ #define NOT_IN_ARSENAL !(_name in GVAR(virtualItemsFlat)) -params ["_loadout"]; +params ["_loadout", ["_recoverInvalidContainers", false]]; private _extendedInfo = createHashMap; @@ -37,7 +38,8 @@ private _missingExtendedInfo = []; // Search for all items and check their availability private _fnc_filterLoadout = { - _this apply { + params ["_loadout", ["_recoverInvalidContainers", false]]; + _loadout apply { if (_x isEqualType "" && {_x != ""}) then { _name = _x call EFUNC(common,getConfigName); @@ -70,11 +72,13 @@ private _fnc_filterLoadout = { } else { // Handle arrays if (_x isEqualType []) then { - _itemArray = _x call _fnc_filterLoadout; + _itemArray = [_x, true] call _fnc_filterLoadout; + // If "" is given as a container, an error is thrown, therefore, filter out all unavailable/null containers - if (count _itemArray == 2 && {(_itemArray select 0) isEqualTo ""} && {(_itemArray select 1) isEqualType []}) then { + if (!_recoverInvalidContainers && {count _itemArray == 2} && {(_itemArray select 0) isEqualTo ""} && {(_itemArray select 1) isEqualType []}) then { _itemArray = []; }; + _itemArray } else { // All other types and empty strings @@ -86,7 +90,7 @@ private _fnc_filterLoadout = { // Convert loadout to config case and replace null/unavailable items // Loadout might come from a different modpack, which might have different config naming -_loadout = _loadout call _fnc_filterLoadout; +_loadout = [_loadout, _recoverInvalidContainers] call _fnc_filterLoadout; { private _class = _extendedInfo getOrDefault [_x, ""]; diff --git a/docs/wiki/feature/arsenal.md b/docs/wiki/feature/arsenal.md index 3dd86bed236..6c9c2df9c7e 100644 --- a/docs/wiki/feature/arsenal.md +++ b/docs/wiki/feature/arsenal.md @@ -53,6 +53,8 @@ Saving loadouts from the default and public tabs will save them in your profile, All loadouts can be loaded, however items not available or missing, will NOT be added. This limitation applies to all tabs as well as imported loadouts. +In the case of a stored loadout's uniform, vest or backpack not being available or missing, loading it will retain the currently equipped uniform/vest/backpack and attempt to fill it with the stored one's content that is available in the arsenal. + The color coding for loadouts is as follows: - White: All items are available and will be loaded. - Grey: Some items in that loadout are not available in that box.