Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Arsenal - Native baseWeapon support for CBA items #9799

Merged
merged 15 commits into from
Mar 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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.*?"}
johnb432 marked this conversation as resolved.
Show resolved Hide resolved
};

{
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;
johnb432 marked this conversation as resolved.
Show resolved Hide resolved
// 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