Skip to content

Commit

Permalink
[Feature] - Add Gearscript ACE gun-bag support. (#102)
Browse files Browse the repository at this point in the history
* Part 1 - added "SET_GUNBAG_CONTENTS" macro and underlying variable setter.

* Full gunbag support including forcing gunbag state onto regular backpacks.
Examples placed into default gearscripts.
Fixed globals ordering bug (was after preinit config group).
  • Loading branch information
Bubbus authored Apr 12, 2022
1 parent a18c11b commit 397d374
Show file tree
Hide file tree
Showing 19 changed files with 217 additions and 4 deletions.
9 changes: 9 additions & 0 deletions components/functions.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,3 +47,12 @@ class ace_medical_feedback
class effectUnconscious{};
};
};

class ace_gunbag
{
class overrides
{
file = "components\gearscript\gunbag";
class hasGunbag{};
};
};
49 changes: 49 additions & 0 deletions components/gearScript/fn_applyGunbag.sqf
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
#include "macros.hpp"

params ["_unit", "_typeofUnit", "_gearVariant"];

_gearVariant = toLower _gearVariant;
_typeofUnit = toLower _typeofUnit;

private _gunbagContents = GUNBAG_ITEM_DYNAMIC(_gearVariant,_typeofUnit);
private _gunbagVariableValue = [];

if !(_gunbagContents isEqualTo []) then
{
_gunbagContents params ["_attachments", "_muzzles", "_magazines", "_ammo", "_baseWeapon"];

private _gunbagMags = [];
{
_gunbagMags pushBack [_x, _ammo # _forEachIndex];

} forEach _magazines;

_gunbagVariableValue =
[
_baseWeapon,
_attachments,
_gunbagMags
];
};

// Wait a short while and apply gunbag contents. Avoids issue on spawn where ACE can potentially override intended value.
[
// Script
{
params ["_unit", "_contents"];

if (_contents isEqualTo []) then
{
_contents = nil;
};

(backpackContainer _unit) setVariable ["ace_gunbag_gunbagWeapon", _contents, true];
},

// Arguments
[_unit, _gunbagVariableValue],

// Delay
0.5

] call CBA_fnc_waitAndExecute;
1 change: 1 addition & 0 deletions components/gearScript/fn_assignGear.sqf
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ if (_gearVariant == "") exitWith
};

[_unit, _typeOfUnit, _gearVariant] call f_fnc_applyLoadout;
[_unit, _typeOfUnit, _gearVariant] call f_fnc_applyGunbag;


// ====================================================================================
Expand Down
9 changes: 9 additions & 0 deletions components/gearScript/functions.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ class gearScript
class addItemToLoadoutContainer{};
class addLinkedItemToLoadout{};
class applyLoadout{};
class applyGunbag{};
class applyLoadoutModifications{};
class assignGear{};
class createLoadoutLocker{};
Expand Down Expand Up @@ -45,3 +46,11 @@ class gearScript_zen
class zen_createSupplyCrate_followUpDialog{};
class zen_createSupplyCrate_performAction{};
};

class gearScript_gunbag
{
file = "components\gearScript\gunbag";
class getWeaponStateFromClassName{};
class setGunbagVariableFromArsenalExport{};
class setGunbagVariableState{};
};
9 changes: 9 additions & 0 deletions components/gearScript/globals.sqf
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
private _keyValues =
[
["LinkedItemsMuzzle", 0],
["LinkedItemsAcc", 1],
["LinkedItemsOptic", 2],
["LinkedItemsUnder", 3]
];

f_arr_gunbagAttachmentsMap = createHashMapFromArray _keyValues;
32 changes: 32 additions & 0 deletions components/gearScript/gunbag/fn_getWeaponStateFromClassName.sqf
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// Derived from ace_common_fnc_getWeaponState. Used to get a 'getWeaponState' array from a weapon config string.
// Augments the standard 'getWeaponState' array by returning the base weapon name as a 5th field.
// Currently ignores configured default magazines. Arrays returned from this function will have no ammo.

params [["_weapon", nil, [""]]];
if (isNil "_weapon") throw "_weapon must not be nil.";

private _weaponClass = configFile >> "CfgWeapons" >> _weapon;
if (isNil "_weapon") then {throw format ["_weapon (%1) must be a subclass of CfgWeapons.", _weapon]};

private _baseWeapon = getText (_weaponClass >> "baseWeapon");

private _attachments = ["","","",""];
private _linkedItems = _weaponClass >> "LinkedItems";
private _linkedItemsSubclasses = _linkedItems call BIS_fnc_getCfgSubClasses;

{
private _entry = _linkedItems >> _x;
private _index = f_arr_gunbagAttachmentsMap get _x;

if !(isNil "_index") then
{
private _attachmentName = getText (_entry >> "item");
_attachments set [_index, _attachmentName];
};
} foreach _linkedItemsSubclasses;

private _muzzles = _weapon call ace_common_fnc_getWeaponMuzzles;
private _magazines = _muzzles apply {""};
private _ammo = _muzzles apply {0};

[_attachments, _muzzles, _magazines, _ammo, _baseWeapon];
8 changes: 8 additions & 0 deletions components/gearScript/gunbag/fn_hasGunbag.sqf
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
// Override of ace_gunbag_fnc_hasGunbag, to allow any backpack to be a gunbag if it has the gunbag variable set.

params ["_unit"];

(getNumber (configFile >> "CfgVehicles" >> (backpack _unit) >> "ace_gunbag") == 1) or
{
((backpackContainer _unit) getVariable ["ace_gunbag_gunbagWeapon", []]) isNotEqualTo []
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
#include "macros.hpp"

// Used by gearscript to set the state of a unit's gunbag global variable.
// Provide an ACE Arsenal export array ("Unit Loadout Array"), or a string representing the weapon's CfgWeapons classname.

params ["_faction", "_unitName", ["_contents", nil, [[], ""]]];

if (isNil "_contents") then {throw format ["_contents for gunbag contents must not be nil. (unit %1, side %2).", _unitName, _faction]};

if (typeName _contents isEqualTo "STRING") exitWith
{
[_faction, _unitName, _contents] call f_fnc_setGunbagVariableState;
};

if (count _contents < 1) then {throw format ["_contents for gunbag contents is empty. (unit %1, side %2).", _unitName, _faction]};

private _rifle = _contents # 0;

private _isRifleWellFormed = _rifle params
[
["_rifleClass", nil, [""]],
["_muzzleDevice", nil, [""]],
["_sideRailDevice", nil, [""]],
["_optic", nil, [""]],
["_muzzle1Mag", nil, [[]]],
["_muzzle2Mag", nil, [[]]],
["_bipod", nil, [""]]
];

if !(_isRifleWellFormed) then {throw format ["_contents for gunbag contents contained an invalid rifle. Please re-export the loadout. (unit %1, side %2).", _unitName, _faction]};

private _magsArray = [_muzzle1Mag, _muzzle2Mag] select {_x isNotEqualTo []};

private _contents =
[
[_muzzleDevice, _sideRailDevice, _optic, _bipod],
_rifleClass call ace_common_fnc_getWeaponMuzzles,
_magsArray apply {_x # 0},
_magsArray apply {_x # 1},
_rifleClass
];

SET_GUNBAG_CONTENTS(_faction,_unitName,_contents);
12 changes: 12 additions & 0 deletions components/gearScript/gunbag/fn_setGunbagVariableState.sqf
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#include "macros.hpp"

// Used by gearscript to set the state of a unit's gunbag global variable.
// Should a string representing the weapon's CfgWeapons classname.

params ["_faction", "_unitName", ["_contents", nil, [""]]];

if (isNil "_contents") throw "_contents must not be nil.";

private _weaponState = [_contents] call f_fnc_getWeaponStateFromClassName;

SET_GUNBAG_CONTENTS(_faction,_unitName,_weaponState);
1 change: 1 addition & 0 deletions components/gearScript/gunbag/macros.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
#include "../macros.hpp"
11 changes: 11 additions & 0 deletions configuration/loadouts/gear_blufor.sqf
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,17 @@ CREATE_LOADOUT(mk,_baseLoadout);
COPY_ADDONS(mk,rif);


// Sniper Loadout

_baseLoadout = [["srifle_LRR_F","","","optic_LRPS",["7Rnd_408_Mag",7],[],""],[],["hgun_P07_F","","","",["16Rnd_9x21_Mag",17],[],""],["U_B_CombatUniform_mcam",[["ACE_elasticBandage",3],["ACE_morphine",2],["ACE_epinephrine",1],["ACE_packingBandage",3],["ACE_tourniquet",2],["ACE_RangeCard",1],["ACRE_PRC343_ID_3",1],["ACE_Flashlight_XL50",1],["ACE_MapTools",1],["ACE_splint",2],["ACE_Kestrel4500",1],["ACE_microDAGR",1],["16Rnd_9x21_Mag",1,17]]],["V_TacChestrig_oli_F",[["optic_NVS",1],["HandGrenade",2,1],["SmokeShell",4,1],["7Rnd_408_Mag",6,7],["16Rnd_9x21_Mag",1,17]]],["ace_gunbag_Tan",[["30Rnd_65x39_caseless_mag",3,30],["30Rnd_65x39_caseless_mag_Tracer",1,30],["NVGoggles",1]]],"H_Booniehat_mcamo","G_Lowprofile",["ACE_Vector","","","",[],[],""],["ItemMap","","","ItemCompass","ItemWatch",""]];

CREATE_LOADOUT(sniper,_baseLoadout);

_gunbagLoadout = [["arifle_MXC_F","muzzle_snds_65_TI_blk_F","acc_pointer_IR","optic_Aco",["30Rnd_65x39_caseless_mag",30],[],""],[],[],[],[],[],"","",[],["","","","","",""]];

PUT_GUN_IN_GUNBAG(sniper,_gunbagLoadout);


// Crewman Loadout

_baseLoadout = [["SMG_01_F","","acc_flashlight_smg_01","optic_ACO_grn_smg",["30Rnd_45ACP_Mag_SMG_01",25],[],""],[],[],["U_B_HeliPilotCoveralls",[["ACE_elasticBandage",3],["ACE_morphine",2],["ACE_epinephrine",1],["ACE_packingBandage",3],["ACE_tourniquet",2],["ACE_splint",2],["ACRE_PRC343_ID_1",1],["ACRE_PRC148_ID_2",1],["ACRE_PRC152_ID_2",1]]],["V_Chestrig_oli",[["ACE_MapTools",1],["ACE_Flashlight_XL50",1],["SmokeShell",4,1],["30Rnd_45ACP_Mag_SMG_01",5,25],["SmokeShellBlue",1,1],["SmokeShellRed",1,1]]],["B_FieldPack_oli",[["ToolKit",1],["ACE_EntrenchingTool",1]]],"H_HelmetCrew_B","G_Combat",["Binocular","","","",[],[],""],["ItemMap","ItemGPS","","ItemCompass","ItemWatch","NVGoggles_INDEP"]];
Expand Down
10 changes: 10 additions & 0 deletions configuration/loadouts/gear_indfor.sqf
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,16 @@ CREATE_LOADOUT(mk,_baseLoadout);
COPY_ADDONS(mk,rif);


// Sniper Loadout

_baseLoadout = [["srifle_GM6_F","","","optic_LRPS",["5Rnd_127x108_Mag",5],[],""],[],["hgun_ACPC2_F","","","",["9Rnd_45ACP_Mag",8],[],""],["U_I_CombatUniform_shortsleeve",[["ACE_elasticBandage",3],["ACE_epinephrine",1],["ACE_morphine",2],["ACE_packingBandage",3],["ACE_RangeCard",1],["ACE_MapTools",1],["ACE_Flashlight_XL50",1],["ACE_splint",2],["ACE_tourniquet",2],["ACRE_PRC343_ID_15",1],["ACE_Kestrel4500",1],["ACE_microDAGR",1],["9Rnd_45ACP_Mag",1,8]]],["V_TacChestrig_oli_F",[["ACRE_PRC343_ID_31",1],["optic_NVS",1],["SmokeShell",4,1],["5Rnd_127x108_Mag",6,5],["9Rnd_45ACP_Mag",1,8]]],["ace_gunbag",[["30Rnd_556x45_Stanag",4,30],["30Rnd_556x45_Stanag_Tracer_Yellow",1,30],["NVGoggles_INDEP",1]]],"H_Booniehat_dgtl","G_Lowprofile",["ACE_Vector","","","",[],[],""],["ItemMap","","","ItemCompass","ItemWatch",""]];

CREATE_LOADOUT(sniper,_baseLoadout);
COPY_ADDONS(sniper,rif);

PUT_GUN_IN_GUNBAG(sniper,"arifle_Mk20C_ACO_pointer_F");


// Crewman Loadout

_baseLoadout = [["hgun_PDW2000_F","","","optic_Aco_smg",["30Rnd_9x21_Mag",30],[],""],[],[],["U_I_HeliPilotCoveralls",[["ACE_elasticBandage",3],["ACE_morphine",2],["ACE_epinephrine",1],["ACE_packingBandage",3],["ACE_tourniquet",2],["ACRE_PRC343_ID_18",1],["ACRE_PRC148_ID_4",1],["ACE_splint",2],["ACRE_PRC152_ID_1",1]]],["V_Chestrig_khk",[["SmokeShell",4,1],["SmokeShellBlue",1,1],["SmokeShellRed",1,1],["30Rnd_9x21_Mag",5,30]]],["B_FieldPack_khk",[["ToolKit",1],["ACE_EntrenchingTool",1]]],"H_HelmetCrew_I","G_Combat",["Binocular","","","",[],[],""],["ItemMap","ItemGPS","","ItemCompass","ItemWatch","NVGoggles_INDEP"]];
Expand Down
9 changes: 9 additions & 0 deletions configuration/loadouts/gearscript_readme.txt
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,15 @@ ADD_VARIANT(UNIT_NAME,<ACE Arsenal code>);
ADD_VARIANT(rif,<ACE Arsenal code>);
All riflemen will now randomly have an AK-47 or M-16 rifle.

PUT_GUN_IN_GUNBAG(UNIT_NAME,<contents>)
- Allows the backpack of the given unit to be turned into an ACE gunbag, with the given contents placed inside.
The contents can be:
- ACE Arsenal code:
An example of this exists in the default BLUFOR 'sniper' loadout.
- Weapon config class-name:
An example of this exists in the default INDFOR 'sniper' loadout.
You can get the class-name of any weapon by clicking on it in ACE arsenal and then pressing CTRL+C (gets copied to clipboard).
There are advanced weapon classes which have scopes, bipods etc pre-applied. You can find them in the CfgWeapons config. If you don't know how to find these, it may be better to use the ACE Arsenal approach.

-------------------------------------------------

Expand Down
6 changes: 6 additions & 0 deletions gearscript_macros.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@

#define LOADOUT_ITEM_VAR(NAME,ITEM) CONCAT3(LOADOUT_VAR(NAME),_,ITEM)
#define LOADOUT_ITEM_VAR_DYNAMIC(SIDE,NAME,ITEM) (missionNamespace getVariable [format ["f_loadouts_%1_%2_%3", SIDE, NAME, ITEM], []])
#define SET_LOADOUT_ITEM_VAR_DYNAMIC(SIDE,NAME,ITEM,VALUE) missionNamespace setVariable [format ["f_loadouts_%1_%2_%3", SIDE, NAME, ITEM], VALUE]

#define HATS_DYNAMIC(SIDE,NAME) LOADOUT_ITEM_VAR_DYNAMIC(SIDE,NAME,"hats")
#define VESTS_DYNAMIC(SIDE,NAME) LOADOUT_ITEM_VAR_DYNAMIC(SIDE,NAME,"vest")
Expand All @@ -28,6 +29,11 @@

#define ADD_VARIANT(NAME,LOADOUT) LOADOUT_VAR(NAME) pushBack ([LOADOUT] call f_fnc_applyLoadoutModifications)

#define GUNBAG_ITEM(NAME) LOADOUT_ITEM_VAR(NAME,gunbag)
#define GUNBAG_ITEM_DYNAMIC(SIDE,NAME) LOADOUT_ITEM_VAR_DYNAMIC(SIDE,NAME,"gunbag")
#define SET_GUNBAG_CONTENTS(SIDE,NAME,CONTENTS) SET_LOADOUT_ITEM_VAR_DYNAMIC(SIDE,NAME,"gunbag",CONTENTS)
#define PUT_GUN_IN_GUNBAG(NAME,CONTENTS) [#FACTION,#NAME,CONTENTS] call f_fnc_setGunbagVariableFromArsenalExport

#define HATS(NAME) LOADOUT_ITEM_VAR(NAME,hats)
#define VESTS(NAME) LOADOUT_ITEM_VAR(NAME,vest)
#define UNIFORMS(NAME) LOADOUT_ITEM_VAR(NAME,uniforms)
Expand Down
4 changes: 0 additions & 4 deletions init.sqf
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,6 @@ if (IS_CLIENT) then
{
DEBUG_PRINT_LOG("Using CLIENT groups.")

#include "startup\components\globals\clientGlobals.sqf"

#include "customStartup_client.sqf"

#include "startup\configuration\groups\clientConfigGroup.sqf"
Expand All @@ -53,8 +51,6 @@ if (isServer) then
{
DEBUG_PRINT_LOG("Using SERVER groups.")

#include "startup\components\globals\serverGlobals.sqf"

#include "customStartup_server.sqf"

#include "startup\configuration\groups\serverConfigGroup.sqf"
Expand Down
2 changes: 2 additions & 0 deletions startup/components/globals/clientGlobals.sqf
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ LOAD_GLOBALS(squadMarkers)

LOAD_GLOBALS(miscShared)

LOAD_GLOBALS(gearScript)

//LOAD_GLOBALS(respawnWaves)

//LOAD_GLOBALS(zeus_ui)
Expand Down
2 changes: 2 additions & 0 deletions startup/components/globals/serverGlobals.sqf
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@

LOAD_GLOBALS(miscShared)

LOAD_GLOBALS(gearScript)


// Kill tracker init
#ifdef ENABLE_KILL_TRACKING
Expand Down
2 changes: 2 additions & 0 deletions startup/configuration/groups/clientConfigGroup_preInit.sqf
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
#include "macros.hpp"
CLIENT_ONLY;

#include "..\..\components\globals\clientGlobals.sqf"

// Client configuration group
// Includes all config scripts needed for clients.

Expand Down
2 changes: 2 additions & 0 deletions startup/configuration/groups/serverConfigGroup_preInit.sqf
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
#include "macros.hpp"
SERVER_ONLY;

#include "..\..\components\globals\serverGlobals.sqf"

// Server configuration group
// Includes all config scripts needed for the server.

Expand Down

0 comments on commit 397d374

Please sign in to comment.