ACE3/addons/arsenal/functions/fnc_fillRightPanel.sqf
johnb432 cb554a3ea7
Arsenal - Fix unique item edge cases and prevent increasing quantity of cargo weapons (#9700)
* Unique weapons fix

* Update fnc_fillRightPanel.sqf

* Update fnc_updateUniqueItemsList.sqf

* Added unique facewear support
2023-12-31 05:14:17 -08:00

449 lines
17 KiB
Plaintext

#include "..\script_component.hpp"
#include "..\defines.hpp"
/*
* Author: Alganthe, johnb43
* Fills right panel.
*
* Arguments:
* 0: Arsenal display <DISPLAY>
* 1: Tab control <CONTROL>
* 2: Animate panel refresh <BOOL> (default: true)
*
* Return Value:
* None
*
* Public: No
*/
params ["_display", "_control", ["_animate", true]];
// Fade old control background
if (!isNil QGVAR(currentRightPanel)) then {
private _previousCtrlBackground = _display displayCtrl (GVAR(currentRightPanel) - 1);
_previousCtrlBackground ctrlSetFade 1;
_previousCtrlBackground ctrlCommit ([0, FADE_DELAY] select _animate);
};
// Show new control background
private _ctrlIDC = ctrlIDC _control;
private _ctrlBackground = _display displayCtrl (_ctrlIDC - 1);
_ctrlBackground ctrlShow true;
_ctrlBackground ctrlSetFade 0;
_ctrlBackground ctrlCommit ([0, FADE_DELAY] select _animate);
private _searchbarCtrl = _display displayCtrl IDC_rightSearchbar;
// Show right search bar
if (!(ctrlShown _searchbarCtrl) || {ctrlFade _searchbarCtrl > 0}) then {
_searchbarCtrl ctrlShow true;
_searchbarCtrl ctrlSetFade 0;
_searchbarCtrl ctrlCommit 0;
};
private _cfgMagazines = configFile >> "CfgMagazines";
private _cfgWeapons = configFile >> "CfgWeapons";
private _rightPanelCache = uiNamespace getVariable QGVAR(rightPanelCache);
private _currentCargo = []; // we only need this if we're filtering for favorites
if (GVAR(favoritesOnly)) then {
_currentCargo = itemsWithMagazines GVAR(center) + backpacks GVAR(center);
_currentCargo = _currentCargo arrayIntersect _currentCargo;
};
private _fnc_fillRightContainer = {
params ["_configCategory", "_className", ["_isUnique", false, [false]], ["_unknownOrigin", false, [false]]];
if (GVAR(favoritesOnly) && {!(_className in _currentCargo)} && {!((toLower _className) in GVAR(favorites))}) exitWith {};
// If item is not in the arsenal, it must be unique
if (!_isUnique && {!(_className in GVAR(virtualItemsFlat))}) then {
_isUnique = true;
};
// If not in cache, find info and cache it for later use
(_rightPanelCache getOrDefaultCall [_configCategory + _className, {
// Get display name, picture and mass
private _configPath = configFile >> _configCategory >> _className;
// "Misc. items" magazines (e.g. spare barrels, intel, photos)
if (_className in (uiNamespace getVariable QGVAR(magazineMiscItems))) then {
_configPath = _cfgMagazines >> _className;
};
// If an item with unknown origin is in the arsenal list, try to find it
if (_unknownOrigin && {isNull _configPath}) then {
_configPath = _className call CBA_fnc_getItemConfig;
// Check if item is object (this should never happen)
if (isNull _configPath) then {
_configPath = _className call CBA_fnc_getObjectConfig;
};
};
[getText (_configPath >> "displayName"), getText (_configPath >> "picture")]
}, true]) params ["_displayName", "_picture"];
private _lbAdd = _ctrlPanel lnbAddRow ["", _displayName, "0"];
_ctrlPanel lnbSetText [[_lbAdd, 1], _displayName];
_ctrlPanel lnbSetData [[_lbAdd, 0], _className];
_ctrlPanel lnbSetPicture [[_lbAdd, 0], _picture];
_ctrlPanel lnbSetValue [[_lbAdd, 2], [0, 1] select _isUnique];
_ctrlPanel lnbSetTooltip [[_lbAdd, 0], format ["%1\n%2", _displayName, _className]];
if ((toLower _className) in GVAR(favorites)) then {
_ctrlPanel lnbSetColor [[_lbAdd, 1], FAVORITES_COLOR];
_ctrlPanel lnbSetColorRight [[_lbAdd, 1], FAVORITES_COLOR];
};
};
private _ctrlPanel = _display displayCtrl IDC_rightTabContent;
private _listnBox = _display displayCtrl IDC_rightTabContentListnBox;
// Retrieve compatible items
private _isContainer = false;
private _selectedItem = "";
private _compatibleItems = [];
private _compatibleMagsMuzzle = [];
private _compatibleMagsAll = createHashMap;
switch (GVAR(currentLeftPanel)) do {
// If weapons or binoculars are chosen, get their compatible magazines & items
// Weapons and binoculars
case IDC_buttonPrimaryWeapon;
case IDC_buttonHandgun;
case IDC_buttonSecondaryWeapon;
case IDC_buttonBinoculars: {
(switch (GVAR(currentLeftPanel)) do {
case IDC_buttonPrimaryWeapon: {
[IDX_CURR_PRIMARY_WEAPON, IDX_CURR_PRIMARY_WEAPON_ITEMS]
};
case IDC_buttonHandgun: {
[IDX_CURR_HANDGUN_WEAPON, IDX_CURR_HANDGUN_WEAPON_ITEMS]
};
case IDC_buttonSecondaryWeapon: {
[IDX_CURR_SECONDARY_WEAPON, IDX_CURR_SECONDARY_WEAPON_ITEMS]
};
case IDC_buttonBinoculars: {
[IDX_CURR_BINO, IDX_CURR_BINO_ITEMS]
};
}) params ["_currentWeaponIndex", "_currentWeaponItemsIndex"];
private _index = [IDC_buttonMuzzle, IDC_buttonItemAcc, IDC_buttonOptic, IDC_buttonBipod, IDC_buttonCurrentMag, IDC_buttonCurrentMag2] find _ctrlIDC;
private _weapon = GVAR(currentItems) select _currentWeaponIndex;
// Check if weapon attachement or magazine
if (_index != -1) then {
_selectedItem = (GVAR(currentItems) select _currentWeaponItemsIndex) select _index;
// If weapon attachment, get base weapon; Get compatible items
if (_index <= 3) then {
_compatibleItems = compatibleItems _weapon;
_selectedItem = _selectedItem call FUNC(baseWeapon);
} else {
// Get compatible magazines for primary & secondary muzzle (secondary muzzle is not guaranteed to exist)
// Assumption: One weapon can have two muzzles maximum
_compatibleMagsMuzzle = compatibleMagazines [_weapon, (_weapon call CBA_fnc_getMuzzles) param [_index - 4, ""]];
};
};
};
// Uniform, vest or backpack
case IDC_buttonUniform;
case IDC_buttonVest;
case IDC_buttonBackpack: {
_isContainer = true;
// Get the currently selected item in panel
private _selectedItemIndex = lnbCurSelRow _listnBox;
// If something is selected, save it
if (_selectedItemIndex != -1) then {
_selectedItem = _listnBox lnbData [_selectedItemIndex, 0];
};
// This is for the "compatible magazines" tab when a container is open
if (_ctrlIDC == IDC_buttonMag) then {
// Get all compatibles magazines with unit's weapons (including compatible magazines that aren't in configItems)
{
_compatibleMagsAll insert [true, compatibleMagazines _x, []];
} forEach [GVAR(currentItems) select IDX_CURR_PRIMARY_WEAPON, GVAR(currentItems) select IDX_CURR_HANDGUN_WEAPON, GVAR(currentItems) select IDX_CURR_SECONDARY_WEAPON, GVAR(currentItems) select IDX_CURR_BINO];
};
};
};
// Reset right panel content
lbClear _ctrlPanel;
lnbClear _listnBox;
_ctrlPanel lbSetCurSel -1;
_listnBox lnbSetCurSelRow -1;
if (_isContainer) then {
_ctrlPanel = _listnBox;
};
// Force a "refresh" animation of the panel
if (_animate) then {
_ctrlPanel ctrlSetFade 1;
_ctrlPanel ctrlCommit 0;
_ctrlPanel ctrlSetFade 0;
_ctrlPanel ctrlCommit FADE_DELAY;
};
// Check if the left panel is a weapon. If so, right panel will be compatible items with weapon only
private _leftPanelState = GVAR(currentLeftPanel) in [IDC_buttonPrimaryWeapon, IDC_buttonHandgun, IDC_buttonSecondaryWeapon, IDC_buttonBinoculars];
// Add an empty entry if left panel is a weapon or bino
if (_leftPanelState && {_ctrlIDC in [RIGHT_PANEL_ACC_IDCS, IDC_buttonCurrentMag, IDC_buttonCurrentMag2]}) then {
private _addEmpty = _ctrlPanel lbAdd format [" <%1>", localize "str_empty"];
_ctrlPanel lbSetValue [_addEmpty, -1];
};
// Fill right panel according to category choice
switch (_ctrlIDC) do {
// Optics, flashlights, muzzle attachments, bipods
case IDC_buttonOptic;
case IDC_buttonItemAcc;
case IDC_buttonMuzzle;
case IDC_buttonBipod: {
private _index = [IDX_VIRT_OPTICS_ATTACHMENTS, IDX_VIRT_FLASHLIGHT_ATTACHMENTS, IDX_VIRT_MUZZLE_ATTACHMENTS, IDX_VIRT_BIPOD_ATTACHMENTS] select ([RIGHT_PANEL_ACC_IDCS] find _ctrlIDC);
if (_leftPanelState) then {
{
if (_x in ((GVAR(virtualItems) get IDX_VIRT_ATTACHMENTS) get _index)) then {
["CfgWeapons", _x, _ctrlPanel] call FUNC(addListBoxItem);
};
} forEach _compatibleItems;
} else {
{
["CfgWeapons", _x] call _fnc_fillRightContainer;
} forEach (keys ((GVAR(virtualItems) get IDX_VIRT_ATTACHMENTS) get _index));
{
["CfgWeapons", _x, true] call _fnc_fillRightContainer;
} forEach (keys ((GVAR(virtualItems) get IDX_VIRT_UNIQUE_ATTACHMENTS) get _index));
};
};
// Current primary & secondary muzzle compatible magazines
case IDC_buttonCurrentMag;
case IDC_buttonCurrentMag2: {
if (_leftPanelState) then {
{
if (_x in (GVAR(virtualItems) get IDX_VIRT_ITEMS_ALL)) then {
["CfgMagazines", _x, _ctrlPanel] call FUNC(addListBoxItem);
};
} forEach _compatibleMagsMuzzle;
};
};
// All compatible magazines
case IDC_buttonMag: {
{
if (_x in (GVAR(virtualItems) get IDX_VIRT_ITEMS_ALL)) then {
["CfgMagazines", _x] call _fnc_fillRightContainer;
continue;
};
if (_x in (GVAR(virtualItems) get IDX_VIRT_UNIQUE_VIRT_ITEMS_ALL)) then {
["CfgMagazines", _x, true] call _fnc_fillRightContainer;
};
} forEach (keys _compatibleMagsAll);
};
// All magazines
case IDC_buttonMagALL: {
{
["CfgMagazines", _x] call _fnc_fillRightContainer;
} forEach (keys (GVAR(virtualItems) get IDX_VIRT_ITEMS_ALL));
{
["CfgMagazines", _x, true] call _fnc_fillRightContainer;
} forEach (keys (GVAR(virtualItems) get IDX_VIRT_UNIQUE_VIRT_ITEMS_ALL));
};
// Grenades
case IDC_buttonThrow: {
{
["CfgMagazines", _x] call _fnc_fillRightContainer;
} forEach (keys (GVAR(virtualItems) get IDX_VIRT_GRENADES));
{
["CfgMagazines", _x, true] call _fnc_fillRightContainer;
} forEach (keys (GVAR(virtualItems) get IDX_VIRT_UNIQUE_GRENADES));
};
// Explosives
case IDC_buttonPut: {
{
["CfgMagazines", _x] call _fnc_fillRightContainer;
} forEach (keys (GVAR(virtualItems) get IDX_VIRT_EXPLOSIVES));
{
["CfgMagazines", _x, true] call _fnc_fillRightContainer;
} forEach (keys (GVAR(virtualItems) get IDX_VIRT_UNIQUE_EXPLOSIVES));
};
// Misc. items
case IDC_buttonMisc: {
// Don't add items that will be in a custom right panel button
private _items = createHashMap;
if (!isNil QGVAR(customRightPanelButtons)) then {
{
if (!isNil "_x") then {
_items insert [true, _x select 0, []];
};
} forEach GVAR(customRightPanelButtons);
};
// "Regular" misc. items
{
if !(_x in _items) then {
["CfgWeapons", _x] call _fnc_fillRightContainer;
};
} forEach (keys (GVAR(virtualItems) get IDX_VIRT_MISC_ITEMS));
// Unique items
{
if !(_x in _items) then {
["CfgWeapons", _x, true] call _fnc_fillRightContainer;
};
} forEach (keys (GVAR(virtualItems) get IDX_VIRT_UNIQUE_MISC_ITEMS));
// Unique backpacks
{
if !(_x in _items) then {
["CfgVehicles", _x, true] call _fnc_fillRightContainer;
};
} forEach (keys (GVAR(virtualItems) get IDX_VIRT_UNIQUE_BACKPACKS));
// Unique goggles
{
if !(_x in _items) then {
// _y indicates if an item is truly unique or if it's a non-inventory item in a container (e.g. goggles in backpack)
["CfgGlasses", _x, _y] call _fnc_fillRightContainer;
};
} forEach (GVAR(virtualItems) get IDX_VIRT_UNIQUE_GOGGLES);
// Unknown items
{
if !(_x in _items) then {
// _y indicates if an item is truly unique or if it's a non-inventory item in a container (e.g. helmet in backpack)
["CfgWeapons", _x, _y, true] call _fnc_fillRightContainer;
};
} forEach (GVAR(virtualItems) get IDX_VIRT_UNIQUE_UNKNOWN_ITEMS); // if an item is here but in virtual items, it's just in the wrong place
};
// Custom buttons
default {
private _items = (GVAR(customRightPanelButtons) param [[RIGHT_PANEL_CUSTOM_BUTTONS] find _ctrlIDC, []]) param [0, []];
if (_items isNotEqualTo []) then {
{
switch (true) do {
// "Regular" misc. items
case (_x in (GVAR(virtualItems) get IDX_VIRT_MISC_ITEMS)): {
["CfgWeapons", _x] call _fnc_fillRightContainer;
};
// Unique items
case (_x in (GVAR(virtualItems) get IDX_VIRT_UNIQUE_MISC_ITEMS)): {
["CfgWeapons", _x, true] call _fnc_fillRightContainer;
};
// Unique backpacks
case (_x in (GVAR(virtualItems) get IDX_VIRT_UNIQUE_BACKPACKS)): {
["CfgVehicles", _x, true] call _fnc_fillRightContainer;
};
// Unique goggles
case (_x in (GVAR(virtualItems) get IDX_VIRT_UNIQUE_GOGGLES)): {
["CfgGlasses", _x, GVAR(virtualItems) get IDX_VIRT_UNIQUE_GOGGLES get _x] call _fnc_fillRightContainer;
};
// Unknown items
case (_x in (GVAR(virtualItems) get IDX_VIRT_UNIQUE_UNKNOWN_ITEMS)): {
["CfgWeapons", _x, GVAR(virtualItems) get IDX_VIRT_UNIQUE_UNKNOWN_ITEMS get _x, true] call _fnc_fillRightContainer;
};
};
} forEach _items;
};
};
};
// When switching tabs, clear searchbox
if (GVAR(currentRightPanel) != _ctrlIDC) then {
(_display displayCtrl IDC_rightSearchbar) ctrlSetText "";
};
// Trigger event
GVAR(currentRightPanel) = _ctrlIDC;
[QGVAR(rightPanelFilled), [_display, GVAR(currentLeftPanel), _ctrlIDC]] call CBA_fnc_localEvent;
// Add current items, change progress bar of container load and get relevant container
if (_isContainer) then {
private _containerItems = [];
private _container = switch (GVAR(currentLeftPanel)) do {
// Uniform
case IDC_buttonUniform: {
// Update load bar
(_display displayCtrl IDC_loadIndicatorBar) progressSetPosition (loadUniform GVAR(center));
// Get all items from container
_containerItems = uniformItems GVAR(center);
uniformContainer GVAR(center)
};
// Vest
case IDC_buttonVest: {
// Update load bar
(_display displayCtrl IDC_loadIndicatorBar) progressSetPosition (loadVest GVAR(center));
// Get all items from container
_containerItems = vestItems GVAR(center);
vestContainer GVAR(center)
};
// Backpack
case IDC_buttonBackpack: {
// Update load bar
(_display displayCtrl IDC_loadIndicatorBar) progressSetPosition (loadBackpack GVAR(center));
// Get all items from container
_containerItems = backpackItems GVAR(center);
backpackContainer GVAR(center)
};
};
// Find out how many items of a type there are and update the number displayed
for "_lbIndex" from 0 to (lnbSize _ctrlPanel select 0) - 1 do {
private _xItem = _ctrlPanel lnbData [_lbIndex, 0];
_ctrlPanel lnbSetText [[_lbIndex, 2], str ({_xItem == _x} count _containerItems)];
};
// Refresh availibility of items based on space remaining in container
[_ctrlPanel, _container, _containerItems isNotEqualTo []] call FUNC(updateRightPanel);
};
// Sorting
[_display, _control, _display displayCtrl IDC_sortRightTab, _display displayCtrl IDC_sortRightTabDirection] call FUNC(fillSort);
if (_selectedItem != "") then {
if (_isContainer) then {
// Try to select previously selected item again, otherwise select nothing
private _index = -1;
for "_lbIndex" from 0 to (lnbSize _ctrlPanel select 0) - 1 do {
if ((_ctrlPanel lnbData [_lbIndex, 0]) == _selectedItem) exitWith {
_index = _lbIndex;
};
};
_ctrlPanel lnbSetCurSelRow _index;
} else {
// Try to select previously selected item again, otherwise select first item ("Empty")
private _index = 0;
for "_lbIndex" from 0 to (lbSize _ctrlPanel) - 1 do {
if ((_ctrlPanel lbData _lbIndex) == _selectedItem) exitWith {
_index = _lbIndex;
};
};
_ctrlPanel lbSetCurSel _index;
};
} else {
if (_isContainer) then {
_ctrlPanel lnbSetCurSelRow -1; // select nothing
} else {
_ctrlPanel lbSetCurSel 0; // select "Empty"
};
};