Skip to content

Commit

Permalink
Arsenal - Native baseWeapon support for CBA items (#9799)
Browse files Browse the repository at this point in the history
Co-authored-by: johnb432 <[email protected]>
  • Loading branch information
LinkIsGrim and johnb432 authored Mar 2, 2024
1 parent 2036c83 commit 64538f2
Show file tree
Hide file tree
Showing 11 changed files with 203 additions and 20 deletions.
2 changes: 2 additions & 0 deletions addons/arsenal/XEH_PREP.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ PREP(attributeKeyDown);
PREP(attributeLoad);
PREP(attributeMode);
PREP(attributeSelect);
PREP(baseAttachment);
PREP(baseOptic);
PREP(baseWeapon);
PREP(buttonActionsPage);
PREP(buttonCargo);
Expand Down
51 changes: 51 additions & 0 deletions addons/arsenal/functions/fnc_baseAttachment.sqf
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
#include "..\script_component.hpp"
/*
* Author: Jonpas, LinkIsGrim
* Returns base attachment for CBA scripted attachment
* Adapted from CBA_fnc_switchableAttachments
*
* Arguments:
* 0: Attachment <STRING>
*
* Return Value:
* Base attachment <STRING>
*
* Example:
* "ACE_acc_pointer_green_IR" call ace_arsenal_fnc_baseAttachment
*
* Public: Yes
*/

params [["_item", "", [""]]];

TRACE_1("looking up base attachment",_item);

private _switchableClasses = [];

private _cfgWeapons = configfile >> "CfgWeapons";
private _config = _cfgWeapons >> _item;
_item = configName _config;

while {
_config = _cfgWeapons >> getText (_config >> "MRT_SwitchItemNextClass");
isClass _config && {_switchableClasses pushBackUnique configName _config != -1}
} do {};

_config = _cfgWeapons >> _item;
private _backward = [];
while {
_config = _cfgWeapons >> getText (_config >> "MRT_SwitchItemPrevClass");
isClass _config && {_backward pushBackUnique configName _config != -1}
} do {};

_switchableClasses append _backward;
_switchableClasses = _switchableClasses arrayIntersect _switchableClasses;

{
if (getNumber (_cfgWeapons >> _x >> "scope") == 2) exitWith {
TRACE_2("found class",_item,_x);
_item = _x;
};
} forEach _switchableClasses;

_item
32 changes: 32 additions & 0 deletions addons/arsenal/functions/fnc_baseOptic.sqf
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
#include "..\script_component.hpp"
/*
* Author: Jonpas, LinkIsGrim
* Returns base optic for CBA scripted optics (PIP and 2D)
*
* Arguments:
* 0: Optic <STRING>
*
* Return Value:
* Base optic <STRING>
*
* Example:
* "CUP_optic_Elcan_SpecterDR_black_PIP" call ace_arsenal_fnc_baseOptic
*
* Public: Yes
*/

params [["_optic", "", [""]]];

// PIP
private _baseClasses = configProperties [configFile >> "CBA_PIPItems", "getText _x == _optic"];

// Carry Handle
{
_baseClasses append (configProperties [_x, "getText _x == _optic"]);
} forEach configProperties [configFile >> "CBA_CarryHandleTypes"];

if (_baseClasses isNotEqualTo []) then {
_optic = configName (_baseClasses select 0);
};

_optic
2 changes: 1 addition & 1 deletion addons/arsenal/functions/fnc_baseWeapon.sqf
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
params [["_weapon", "", [""]]];

// Check if item is cached
(uiNamespace getVariable QGVAR(baseWeaponNameCache)) getOrDefaultCall [toLower _weapon, {
(uiNamespace getVariable QGVAR(baseWeaponNameCache)) getOrDefaultCall [toLowerANSI _weapon, {
private _cfgWeapons = configfile >> "CfgWeapons";
private _config = _cfgWeapons >> _weapon;

Expand Down
63 changes: 54 additions & 9 deletions addons/arsenal/functions/fnc_replaceUniqueItemsLoadout.sqf
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ if (count _loadout == 2) then {

if (count _loadout != 10) exitWith {[]};

private _weapon = "";
private _weaponsInfo = [];
private _uniqueBaseCfgText = "";
private _cfgWeapons = configFile >> "CfgWeapons";
Expand All @@ -43,7 +42,7 @@ private _cfgVehicles = configFile >> "CfgVehicles";

// Check weapon & weapon attachments
{
// Magazines
// Magazines in weapons have 2 entries: Name and ammo count
if (_forEachIndex in [4, 5]) then {
_x params [["_magazine", ""], "_count"];

Expand All @@ -69,23 +68,69 @@ private _cfgVehicles = configFile >> "CfgVehicles";
_x params [["_containerClass", ""], ["_items", []]];

if (_containerClass != "") then {
_uniqueBaseCfgText = (getText ([_cfgWeapons, _cfgVehicles] select (_forEachIndex == IDX_LOADOUT_BACKPACK) >> _containerClass >> QGVAR(uniqueBase))) call EFUNC(common,getConfigName);
if (_forEachIndex == IDX_LOADOUT_BACKPACK) then {
// Check for non-preset first
_uniqueBaseCfgText = [_containerClass, "CfgVehicles"] call CBA_fnc_getNonPresetClass;

if (_uniqueBaseCfgText != "") then {
(_x select 0) set [0, _uniqueBaseCfgText];
if (_uniqueBaseCfgText != "") then {
_containerClass = _uniqueBaseCfgText;
};

// Check if non-preset backpack has a unique base
_uniqueBaseCfgText = (getText (_cfgVehicles >> _containerClass >> QGVAR(uniqueBase))) call EFUNC(common,getConfigName);

if (_uniqueBaseCfgText != "") then {
_containerClass = _uniqueBaseCfgText;
};

_x set [0, _containerClass];
} else {
_uniqueBaseCfgText = (getText (_cfgWeapons >> _containerClass >> QGVAR(uniqueBase))) call EFUNC(common,getConfigName);

if (_uniqueBaseCfgText != "") then {
_x set [0, _uniqueBaseCfgText];
};
};

// Check if container has items that need replacing with a defined base
{
switch (true) do {
// Containers have 2 entries: Name and isBackpack
case (_x isEqualTypeArray ["", false]);
case (_x isEqualTypeArray ["", false]): {
_x params ["_containerClass", "_isBackpack"];

if (_containerClass != "") then {
if (_isBackpack) then {
// Check for non-preset first
_uniqueBaseCfgText = [_containerClass, "CfgVehicles"] call CBA_fnc_getNonPresetClass;

if (_uniqueBaseCfgText != "") then {
_containerClass = _uniqueBaseCfgText;
};

// Check if non-preset backpack has a unique base
_uniqueBaseCfgText = (getText (_cfgVehicles >> _containerClass >> QGVAR(uniqueBase))) call EFUNC(common,getConfigName);

if (_uniqueBaseCfgText != "") then {
_containerClass = _uniqueBaseCfgText;
};

_x set [0, _containerClass];
} else {
_uniqueBaseCfgText = (getText (_cfgWeapons >> _containerClass >> QGVAR(uniqueBase))) call EFUNC(common,getConfigName);

if (_uniqueBaseCfgText != "") then {
_x set [0, _uniqueBaseCfgText];
};
};
};
};
// Misc. items have 2 entries: Name and amount
case (_x isEqualTypeArray ["", 0]): {
_x params ["_item", "_arg"];
_x params ["_item"];

if (_item != "") then {
_uniqueBaseCfgText = (getText ([_cfgWeapons, _cfgVehicles] select ((_arg isEqualType false) && {_arg}) >> _item >> QGVAR(uniqueBase))) call EFUNC(common,getConfigName);
_uniqueBaseCfgText = (getText (_cfgWeapons >> _item >> QGVAR(uniqueBase))) call EFUNC(common,getConfigName);

if (_uniqueBaseCfgText != "") then {
_x set [0, _uniqueBaseCfgText];
Expand All @@ -94,7 +139,7 @@ private _cfgVehicles = configFile >> "CfgVehicles";
};
// Weapons have 2 entries: Weapon info array and amount
case (_x isEqualTypeArray [[], 0]): {
_weaponsInfo = _x select 0;
_x params ["_weaponsInfo"];

// Check weapon & weapon attachments
{
Expand Down
35 changes: 33 additions & 2 deletions addons/arsenal/functions/fnc_scanConfig.sqf
Original file line number Diff line number Diff line change
Expand Up @@ -282,11 +282,42 @@ uiNamespace setVariable [QGVAR(CBAdisposableLaunchers), compileFinal _launchers]
uiNamespace setVariable [QGVAR(configItemsTools), compileFinal _toolList];

// Compatibility: Override baseWeapon for RHS optics
// No good way to do this via script for other attachments, needs manual compat
// No good way to do this via script for other RHS attachments, needs manual compat
private _baseWeaponCache = uiNamespace getVariable QGVAR(baseWeaponNameCache);
{
private _baseAttachment = configName (_cfgWeapons >> getText (_x >> "rhs_optic_base"));
if (_baseAttachment != "") then {
_baseWeaponCache set [toLower configName _x, _baseAttachment];
_baseWeaponCache set [toLowerANSI configName _x, _baseAttachment];
};
} forEach ("getText (_x >> 'rhs_optic_base') != ''" configClasses _cfgWeapons);

// Compatibility: Override baseWeapon for CBA Scripted Optics
// Adapted from https://github.com/Theseus-Aegis/Mods/blob/master/addons/armory/functions/fnc_getBaseVariant.sqf
private _isScriptedOptic = toString {
isClass (_x >> "CBA_ScriptedOptic") ||
{(getText (_x >> "weaponInfoType")) regexMatch "CBA_scriptedOptic.*?"}
};

{
private _xClass = toLowerANSI configName _x;
private _baseOptic = _xClass call FUNC(baseOptic);
if (_baseOptic != "" && {_baseOptic != _xClass}) then {
TRACE_2("updating baseOptic",_xClass,_baseOptic);
_baseWeaponCache set [_xClass, _baseOptic];
};
} forEach (_isScriptedOptic configClasses _cfgWeapons);

// Compatibility: Override baseWeapon for CBA Scripted Attachments
private _isScriptedAttachment = toString {
getText (_x >> "MRT_SwitchItemNextClass") != "" ||
{getText (_x >> "MRT_SwitchItemPrevClass") != ""}
};

{
private _xClass = toLowerANSI configName _x;
private _baseAttachment = _xClass call FUNC(baseAttachment);
if (_baseAttachment != "" && {_baseAttachment != _xClass}) then {
TRACE_2("updating baseAttachment",_xClass,_baseAttachment);
_baseWeaponCache set [_xClass, _baseAttachment];
};
} forEach (_isScriptedAttachment configClasses _cfgWeapons);
8 changes: 6 additions & 2 deletions addons/arsenal/functions/fnc_updateCurrentItemsList.sqf
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,12 @@ private _indexCurrentItems = -1;
};
// Backpack
case IDX_LOADOUT_BACKPACK: {
GVAR(currentItems) set [IDX_CURR_BACKPACK, _x param [0, ""]];
GVAR(currentItems) set [IDX_CURR_BACKPACK_ITEMS, _x param [1, []]];
_x params [["_backpack", ""], ["_items", []]];
if (_backpack != "") then {
_backpack = [_backpack, "CfgVehicles"] call CBA_fnc_getNonPresetClass;
};
GVAR(currentItems) set [IDX_CURR_BACKPACK, _backpack];
GVAR(currentItems) set [IDX_CURR_BACKPACK_ITEMS, _items];
};
// Helmet
case IDX_LOADOUT_HEADGEAR: {
Expand Down
5 changes: 5 additions & 0 deletions addons/arsenal/functions/fnc_updateUniqueItemsList.sqf
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,11 @@ private _fnc_uniqueEquipment = {
case IDX_LOADOUT_BACKPACK: {
_x params [["_containerClass", ""]];

// Handle preset (loaded/AI) backpacks
if (_containerClass != "" && _forEachIndex == IDX_LOADOUT_BACKPACK) then {
_containerClass = [_containerClass, "CfgVehicles"] call CBA_fnc_getNonPresetClass;
};

// Remove all unique equipment in tab; Add container as a unique equipment
[GVAR(virtualItems) get (_forEachIndex + 1), _containerClass] call _fnc_uniqueEquipment;
};
Expand Down
21 changes: 17 additions & 4 deletions addons/arsenal/functions/fnc_verifyLoadout.sqf
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
* Public: No
*/

#define NOT_IN_ARSENAL !(_name in GVAR(virtualItemsFlat))

params ["_loadout"];

private _extendedInfo = createHashMap;
Expand Down Expand Up @@ -40,11 +42,22 @@ private _fnc_filterLoadout = {
_nullItemsList pushBack _x;
} else {
// Check if item or its base weapon exist in the arsenal
if !(_name in GVAR(virtualItemsFlat)) then {
if NOT_IN_ARSENAL then {
_name = _name call FUNC(baseWeapon);
if !(_name in GVAR(virtualItemsFlat)) then {
_unavailableItemsList pushBack _name;
_name = "";
if NOT_IN_ARSENAL then {
// This could be a backpack
private _temp = [_name, "CfgVehicles"] call CBA_fnc_getNonPresetClass;
if (_temp == "") then { // It's not
_unavailableItemsList pushBack _name;
_name = "";
} else { // It is
_name = _temp;
// Check if it's available again
if NOT_IN_ARSENAL then {
_unavailableItemsList pushBack _name;
_name = "";
};
};
};
};
};
Expand Down
2 changes: 1 addition & 1 deletion addons/gunbag/XEH_preInit.sqf
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ PREP_RECOMPILE_END;
private _magazines = _gunbagInfo select 2;
{
private _class = _x param [0, ""];
if !(_class != "" && {_class in EGVAR(arsenal,virtualItemsFlat)}) then {
if (_class != "" && {!(_class in EGVAR(arsenal,virtualItemsFlat))}) then {
_missingItems pushBack _class;
_magazines set [_forEachIndex, ["", 0]];
};
Expand Down
2 changes: 1 addition & 1 deletion docs/wiki/framework/arsenal-framework.md
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ Examples:

ACE Arsenal uses 2 existing config entries to sort and display items.

- `baseWeapon`: Class name that is used to display an item in the arsenal. This property can be applied to any weapon or weapon attachment in `CfgWeapons`.
- `baseWeapon`: Class name that is used to display an item in the arsenal, used for weapon/attachment variants that are not normally shown to the player (AI variants, PIP optics, and so on). This property can be applied to any weapon or weapon attachment in `CfgWeapons`. Items using CBA or RHS' Scripted Optics systems, or CBA Switchable Attachments do not need this property explictly set, and will automatically use their player-accessible class.
- `ACE_isUnique`: Classes in `CfgMagazines` with this property set to `1` will be treated and shown by the Arsenal as Misc. Items. Used for items with attached data that needs to be kept track of, such as Notepads or Spare Barrels.

### 3.2 New config entries
Expand Down

0 comments on commit 64538f2

Please sign in to comment.