Arsenal - Native baseWeapon support for CBA items (#9799)

Co-authored-by: johnb432 <58661205+johnb432@users.noreply.github.com>
This commit is contained in:
Grim 2024-03-02 14:29:20 -03:00 committed by GitHub
parent 2036c83dc8
commit 64538f2ad0
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
11 changed files with 203 additions and 20 deletions

View File

@ -16,6 +16,8 @@ PREP(attributeKeyDown);
PREP(attributeLoad);
PREP(attributeMode);
PREP(attributeSelect);
PREP(baseAttachment);
PREP(baseOptic);
PREP(baseWeapon);
PREP(buttonActionsPage);
PREP(buttonCargo);

View File

@ -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

View File

@ -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

View File

@ -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;

View File

@ -25,7 +25,6 @@ if (count _loadout == 2) then {
if (count _loadout != 10) exitWith {[]};
private _weapon = "";
private _weaponsInfo = [];
private _uniqueBaseCfgText = "";
private _cfgWeapons = configFile >> "CfgWeapons";
@ -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"];
@ -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];
@ -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
{

View File

@ -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);

View File

@ -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: {

View File

@ -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;
};

View File

@ -13,6 +13,8 @@
* Public: No
*/
#define NOT_IN_ARSENAL !(_name in GVAR(virtualItemsFlat))
params ["_loadout"];
private _extendedInfo = createHashMap;
@ -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 = "";
};
};
};
};
};

View File

@ -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]];
};

View File

@ -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