diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 0b78e31..72513ec 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -16,7 +16,7 @@ on: jobs: build: name: Build - runs-on: ubuntu-22.04 + runs-on: ubuntu-latest steps: - name: Checkout Source Code uses: actions/checkout@v4 diff --git a/addons/db.7z b/addons/db.7z new file mode 100644 index 0000000..bcca499 Binary files /dev/null and b/addons/db.7z differ diff --git a/addons/db/XEH_PREP.hpp b/addons/db/XEH_PREP.hpp index 7dbd5dc..90ee6a8 100644 --- a/addons/db/XEH_PREP.hpp +++ b/addons/db/XEH_PREP.hpp @@ -1,3 +1 @@ -PREP(saveToMission); -PREP(saveToProfile); -PREP(saveToTempDB); \ No newline at end of file +PREP(requestServerDB); \ No newline at end of file diff --git a/addons/db/XEH_postInit.sqf b/addons/db/XEH_postInit.sqf index a3c56cd..84f2529 100644 --- a/addons/db/XEH_postInit.sqf +++ b/addons/db/XEH_postInit.sqf @@ -1,3 +1 @@ -#include "script_component.hpp" - -GVAR(tempDB) = []; \ No newline at end of file +#include "script_component.hpp" \ No newline at end of file diff --git a/addons/db/XEH_postInit_client.sqf b/addons/db/XEH_postInit_client.sqf index 84f2529..02bbb78 100644 --- a/addons/db/XEH_postInit_client.sqf +++ b/addons/db/XEH_postInit_client.sqf @@ -1 +1,3 @@ -#include "script_component.hpp" \ No newline at end of file +#include "script_component.hpp" + +["forge_db_registerClient", [getPlayerUID player, clientOwner]] call CBA_fnc_serverEvent; \ No newline at end of file diff --git a/addons/db/XEH_preInit.sqf b/addons/db/XEH_preInit.sqf index d7d59fe..dc52c1c 100644 --- a/addons/db/XEH_preInit.sqf +++ b/addons/db/XEH_preInit.sqf @@ -5,4 +5,18 @@ PREP_RECOMPILE_START; #include "XEH_PREP.hpp" PREP_RECOMPILE_END; +// Handle responses from server requests +["forge_db_response", { + params ["_targetUID", "_requestType", "_result", "_requestID"]; + + if (_targetUID isEqualTo getPlayerUID player) then { + if (!isNil QGVAR(pendingCallbacks)) then { + private _callback = GVAR(pendingCallbacks) getOrDefault [_requestID, {}]; + GVAR(pendingCallbacks) deleteAt _requestID; + + [_result, _requestType] call _callback; + }; + }; +}] call CBA_fnc_addEventHandler; + ADDON = true; \ No newline at end of file diff --git a/addons/db/functions/02282025.7z b/addons/db/functions/02282025.7z new file mode 100644 index 0000000..c970469 Binary files /dev/null and b/addons/db/functions/02282025.7z differ diff --git a/addons/db/functions/fnc_requestServerDB.sqf b/addons/db/functions/fnc_requestServerDB.sqf new file mode 100644 index 0000000..9daef63 --- /dev/null +++ b/addons/db/functions/fnc_requestServerDB.sqf @@ -0,0 +1,35 @@ +#include "..\script_component.hpp" + +/* + * Function: forge_client_db_fnc_requestServerDB + * Author: J. Schmidt + * + * Description: + * Sends database requests to the server using CBA events + * + * Arguments: + * 0: _type - Type of database operation + * 1: _data - Data for the operation + * 2: _callback - Function to call when data is returned + * + * Return Value: + * Request ID + */ + +params [ + ["_type", "", [""]], + ["_data", nil, [createHashMap, [], "", 0, true, objNull]], + ["_callback", {}, [{}]] +]; + +private _requestID = format ["%1_%2", diag_tickTime, random 1000]; + +if (isNil QGVAR(pendingCallbacks)) then { + GVAR(pendingCallbacks) = createHashMap; +}; + +GVAR(pendingCallbacks) set [_requestID, _callback]; + +["forge_db_request", [getPlayerUID player, _type, _data, _requestID]] call CBA_fnc_serverEvent; + +_requestID \ No newline at end of file diff --git a/addons/db/functions/fnc_saveToMission.sqf b/addons/db/functions/fnc_saveToMission.sqf deleted file mode 100644 index 5f2035e..0000000 --- a/addons/db/functions/fnc_saveToMission.sqf +++ /dev/null @@ -1,111 +0,0 @@ -#include "..\script_component.hpp" - -/* - * Function: forge_client_db_fnc_saveToMission - * Author: J.Schmidt - * Edit: 07.23.2024 - * Copyright © 2024 J.Schmidt, All rights reserved - * - * Do not edit without permission! - * - * This work is licensed under the Creative Commons Attribution-NonCommercial-NoDerivative 4.0 International License. - * To view a copy of this license, vist https://creativecommons.org/licenses/by-nc-nd/4.0/ or send a letter to Creative Commons, - * PO Box 1866, Mountain View, CA 94042 - * - * [Description] - * Store mission and player data in Mission Namespace. - * - * Arguments: - * N/A - * - * Return Value: - * N/A - * - * Examples: - * [] call forge_client_db_fnc_saveToMission; - * - * Public: Yes - */ - -if (isNil "companyFunds") then { companyFunds = 0 }; -if (isNil "companyRating") then { companyRating = 0 }; -if (isNil "companyGenerals") then { companyGenerals = [] }; -if (isNil "companyGarageUnlocks") then { companyGarageUnlocks = [] }; -if (isNil EGVAR(arsenal,armory_unlocks)) then { EGVAR(arsenal,armory_unlocks) = [[],[],[],[]] }; -if (isNil EGVAR(arsenal,garage_unlocks)) then { EGVAR(arsenal,garage_unlocks) = [[],[],[],[],[],[]] }; - -private _vdata = []; -private _pdata = []; -private _cdata = [ -["key", "CompanyState"], -["funds", [companyFunds]], -["rating", [companyRating]], -["operations", [companyGenerals]], -["garage_unlocks", [companyGarageUnlocks]] -]; - -private _vehicles = nearestObjects [player, ["LandVehicle"], 50] apply { - createHashMapFromArray [ - ["vehicle", _x], - ["class", [typeOf _x]], - ["position", [getPosATL _x]], - ["direction", [getDir _x]], - ["health", [damage _x]] - ]; -}; - -{ - if (alive _x) then { - _vdata pushBackUnique _x; - }; -} forEach _vehicles; - -{ - private _data = [ - ["key", getPlayerUID player], - // ["armory_unlocks", [forge_client_armory_arsenalUnlocks]], - // ["garage_unlocks", [forge_client_armory_garageUnlocks]], - ["armory_unlocks", [EGVAR(arsenal,armory_unlocks)]], - ["garage_unlocks", [EGVAR(arsenal,garage_unlocks)]], - // ["locker", [player getVariable ["Locker", []]]], - // ["garage", [player getVariable ["Garage", []]]], - ["locker", [GETVAR(player,FORGE_Locker,[])]], - ["garage", [GETVAR(player,FORGE_Garage,[])]], - // ["cash", [player getVariable ["FORGE_Cash", 0]]], - // ["bank", [player getVariable ["FORGE_Bank", 0]]], - ["cash", [GETVAR(player,FORGE_Cash,0)]], - ["bank", [GETVAR(player,FORGE_Bank,0)]], - // ["number", [player getVariable ["FORGE_Phone_Number", "unknown"]]], - // ["email", [player getVariable ["FORGE_Email", "unknown@spearnet.mil"]]], - ["number", [GETVAR(player,FORGE_Phone_Number,"unknown")]], - ["email", [GETVAR(player,FORGE_Email,"unknown@spearnet.mil")]], - // ["paygrade", [player getVariable ["Paygrade", "E1"]]], - ["paygrade", [GETVAR(player,FORGE_Paygrade,"E1")]], - ["reputation", [rating player]], - ["loadout", [getUnitLoadout player]], - // ["holster", [player getVariable ["FORGE_Holster_Weapon", true]]], - ["holster", [GETVAR(player,FORGE_Holster_Weapon,true)]], - ["position", [getPosASLVisual player]], - ["direction", [getDirVisual player]] - ]; - - if (isNull objectParent player) then { - _data pushBack "currentWeapon"; - _data pushBack [currentMuzzle player]; - _data pushBack "stance"; - _data pushBack [stance player]; - }; - - _pdata pushBackUnique _data; -} forEach playableUnits; - -private _cHashMap = createHashMapFromArray _cdata; -private _pHashMap = createHashMapFromArray _pdata; -private _vHashMap = createHashMapFromArray _vdata; - -// missionProfileNamespace setVariable ["FORGE_MissionData", _cHashMap]; -// missionProfileNamespace setVariable ["FORGE_PlayerData", _pHashMap]; -// missionProfileNamespace setVariable ["FORGE_VehicleData", _vHashMap]; -SETPVAR(missionNamespace,FORGE_MissionData,_cHashMap); -SETPVAR(missionNamespace,FORGE_PlayerData,_pHashMap); -SETPVAR(missionNamespace,FORGE_VehicleData,_vHashMap); \ No newline at end of file diff --git a/addons/db/functions/fnc_saveToProfile.sqf b/addons/db/functions/fnc_saveToProfile.sqf deleted file mode 100644 index 2e3a22c..0000000 --- a/addons/db/functions/fnc_saveToProfile.sqf +++ /dev/null @@ -1,69 +0,0 @@ -#include "..\script_component.hpp" - -/* - * Function: forge_client_db_fnc_saveToProfile - * Author: J.Schmidt - * Edit: 07.23.2024 - * Copyright © 2024 J.Schmidt, All rights reserved - * - * Do not edit without permission! - * - * This work is licensed under the Creative Commons Attribution-NonCommercial-NoDerivative 4.0 International License. - * To view a copy of this license, vist https://creativecommons.org/licenses/by-nc-nd/4.0/ or send a letter to Creative Commons, - * PO Box 1866, Mountain View, CA 94042 - * - * [Description] - * Store player data in Profile Namespace. - * - * Arguments: - * N/A - * - * Return Value: - * N/A - * - * Examples: - * [] call forge_client_db_fnc_saveToProfile; - * - * Public: Yes - */ - -// if (isNil "forge_client_armory_arsenalUnlocks") then { forge_client_armory_arsenalUnlocks = [] }; -// if (isNil "forge_client_armory_garageUnlocks") then { forge_client_armory_garageUnlocks = [] }; -if (isNil EGVAR(arsenal,armory_unlocks)) then { EGVAR(arsenal,armory_unlocks) = [[],[],[],[]] }; -if (isNil EGVAR(arsenal,garage_unlocks)) then { EGVAR(arsenal,garage_unlocks) = [[],[],[],[],[],[]] }; - -private _data = [ -["key", getPlayerUID player], -["armory_unlocks", [EGVAR(arsenal,armory_unlocks)]], -["garage_unlocks", [EGVAR(arsenal,garage_unlocks)]], -// ["locker", [player getVariable ["Locker", []]]], -// ["garage", [player getVariable ["Garage", []]]], -["locker", [GETVAR(player,FORGE_Locker,[])]], -["garage", [GETVAR(player,FORGE_Garage,[])]], -// ["cash", [player getVariable ["FORGE_Cash", 0]]], -// ["bank", [player getVariable ["FORGE_Bank", 0]]], -["cash", [GETVAR(player,FORGE_Cash,0)]], -["bank", [GETVAR(player,FORGE_Bank,0)]], -// ["number", [player getVariable ["FORGE_Phone_Number", "unknown"]]], -// ["email", [player getVariable ["FORGE_Email", "unknown@spearnet.mil"]]], -["number", [GETVAR(player,FORGE_PhoneNumber,"unknown")]], -["email", [GETVAR(player,FORGE_Email,"unknown@spearnet.mil")]], -// ["paygrade", [player getVariable ["Paygrade", "E1"]]], -["paygrade", [GETVAR(player,FORGE_Paygrade,"E1")]], -["reputation", [rating player]], -["loadout", [getUnitLoadout player]], -// ["holster", [player getVariable ["FORGE_Holster_Weapon", true]]], -["holster", [GETVAR(player,FORGE_Holster_Weapon,true)]], -["position", [getPosASLVisual player]], -["direction", [getDirVisual player]] -]; - -if (isNull objectParent player) then { - _data pushBack ["currentWeapon", [currentMuzzle player]]; - _data pushBack ["stance", [stance player]]; -}; - -private _hashMap = createHashMapFromArray _data; - -// profileNamespace setVariable ["FORGE_PlayerData", _hashMap]; -SETVAR(profileNamespace,FORGE_PlayerData,_hashMap); \ No newline at end of file diff --git a/addons/db/functions/fnc_saveToTempDB.sqf b/addons/db/functions/fnc_saveToTempDB.sqf deleted file mode 100644 index ec097f0..0000000 --- a/addons/db/functions/fnc_saveToTempDB.sqf +++ /dev/null @@ -1,51 +0,0 @@ -#include "..\script_component.hpp" - -/* - * Function: forge_client_db_fnc_saveToTempDB - * Author: J.Schmidt - * Edit: 07.23.2024 - * Copyright © 2024 J.Schmidt, All rights reserved - * - * Do not edit without permission! - * - * This work is licensed under the Creative Commons Attribution-NonCommercial-NoDerivative 4.0 International License. - * To view a copy of this license, vist https://creativecommons.org/licenses/by-nc-nd/4.0/ or send a letter to Creative Commons, - * PO Box 1866, Mountain View, CA 94042 - * - * [Description] - * Store data in Temp DB. - * - * Arguments: - * 0: Name of Event - * 1: Name of DB - * 2: UID of Player - * 3: Name of Key - * 4: Value to store in key - * - * Return Value: - * N/A - * - * Examples: - * ["playerStatus", "players", "76561198027566824", "status", "available"] call forge_client_db_fnc_saveToTempDB; - * - * Public: Yes - */ - -params [["_event", "", [""]], ["_db", "", [""]], ["_uid", "", [""]], ["_key", "", [""]], ["_value", "", [[], 0, "", false]]]; - -if (isNil "_event") exitWith { ["No Event provided"] call BFUNC(log); }; -if (isNil "_db") exitWith { ["No DB provided"] call BFUNC(log); }; -if (isNil "_uid") exitWith { ["No UID provided"] call BFUNC(log); }; -if (isNil "_key") exitWith { ["No key provided"] call BFUNC(log); }; -if (isNil "_value") exitWith { ["No Value provided"] call BFUNC(log); }; - -["Received event: %1", _this] call BFUNC(logFormat); - -private _response = [GVAR(tempDB), [_db, _uid, _key], _value] call BFUNC(dbValueSet); - -if !(_response) then { - ["Failed to set Key '%1' for UID '%2' with '%3' to DB", _key, _uid, _value] call BFUNC(logFormat); -} else { - SETPVAR(missionNamespace,FORGE_TempDb,GVAR(tempDB)); - ["Successfully set key '%1' for UID '%2' with '%3'", _key, _uid, _value] call BFUNC(logFormat); -}; \ No newline at end of file diff --git a/addons/main/CfgMods.hpp b/addons/main/CfgMods.hpp index 01054b7..b60efa4 100644 --- a/addons/main/CfgMods.hpp +++ b/addons/main/CfgMods.hpp @@ -3,7 +3,7 @@ class CfgMods { dir = "@forge_client"; name = "FORGE Client"; author = "IDSolutions"; - picture = "A3\Ui_f\data\Logos\arma3_expansion_alpha_ca"; + picture = "A3\Ui_f\data\Logos\arma3_expansion_alpha_ca.paa"; hideName = "false"; hidePicture = "false"; action = "https://innovativedevsolutions.org"; diff --git a/addons/medical/functions/fnc_moveInventory.sqf b/addons/medical/functions/fnc_moveInventory.sqf index d25a886..52fbb2c 100644 --- a/addons/medical/functions/fnc_moveInventory.sqf +++ b/addons/medical/functions/fnc_moveInventory.sqf @@ -59,7 +59,7 @@ if (_backpack != "") then { { private _holderWeapons = ((getWeaponCargo _x) select 0) select { _x in _weapons }; - if !(_holderWeapons isEqualTo []) then { + if (_holderWeapons isNotEqualTo []) then { deleteVehicle _x; }; } forEach _nearHolders; \ No newline at end of file diff --git a/addons/org/$PBOPREFIX$ b/addons/org/$PBOPREFIX$ new file mode 100644 index 0000000..6fa59ff --- /dev/null +++ b/addons/org/$PBOPREFIX$ @@ -0,0 +1 @@ +z\forge_client\addons\org \ No newline at end of file diff --git a/addons/org/CfgEventHandlers.hpp b/addons/org/CfgEventHandlers.hpp new file mode 100644 index 0000000..78b189a --- /dev/null +++ b/addons/org/CfgEventHandlers.hpp @@ -0,0 +1,19 @@ +class Extended_PreStart_EventHandlers { + class ADDON { + init = QUOTE(call COMPILE_FILE(XEH_preStart)); + }; +}; + +class Extended_PreInit_EventHandlers { + class ADDON { + init = QUOTE(call COMPILE_FILE(XEH_preInit)); + serverInit = QUOTE(call COMPILE_FILE(XEH_preInit_server)); + }; +}; + +class Extended_PostInit_EventHandlers { + class ADDON { + init = QUOTE(call COMPILE_FILE(XEH_postInit)); + clientInit = QUOTE(call COMPILE_FILE(XEH_postInit_client)); + }; +}; \ No newline at end of file diff --git a/addons/org/XEH_PREP.hpp b/addons/org/XEH_PREP.hpp new file mode 100644 index 0000000..43b4c4e --- /dev/null +++ b/addons/org/XEH_PREP.hpp @@ -0,0 +1,13 @@ +PREP(acceptInvite); +PREP(addAsset); +PREP(addFunds); +PREP(addReputation); +PREP(create); +PREP(disband); +PREP(initOrgStore); +PREP(invite); +PREP(join); +PREP(leave); +PREP(listInvites); +PREP(removeAsset); +PREP(verifyOrgStore); \ No newline at end of file diff --git a/addons/org/XEH_postInit.sqf b/addons/org/XEH_postInit.sqf new file mode 100644 index 0000000..84f2529 --- /dev/null +++ b/addons/org/XEH_postInit.sqf @@ -0,0 +1 @@ +#include "script_component.hpp" \ No newline at end of file diff --git a/addons/org/XEH_postInit_client.sqf b/addons/org/XEH_postInit_client.sqf new file mode 100644 index 0000000..b16ff31 --- /dev/null +++ b/addons/org/XEH_postInit_client.sqf @@ -0,0 +1,6 @@ +#include "script_component.hpp" + +// Initialize organization store +[{!isNil "FORGE_STORE_REG"}, { + [] call FUNC(initOrgStore); +}] call CFUNC(waitUntilAndExecute); \ No newline at end of file diff --git a/addons/org/XEH_preInit.sqf b/addons/org/XEH_preInit.sqf new file mode 100644 index 0000000..d7d59fe --- /dev/null +++ b/addons/org/XEH_preInit.sqf @@ -0,0 +1,8 @@ +#include "script_component.hpp" +ADDON = false; + +PREP_RECOMPILE_START; +#include "XEH_PREP.hpp" +PREP_RECOMPILE_END; + +ADDON = true; \ No newline at end of file diff --git a/addons/org/XEH_preInit_server.sqf b/addons/org/XEH_preInit_server.sqf new file mode 100644 index 0000000..84f2529 --- /dev/null +++ b/addons/org/XEH_preInit_server.sqf @@ -0,0 +1 @@ +#include "script_component.hpp" \ No newline at end of file diff --git a/addons/org/XEH_preStart.sqf b/addons/org/XEH_preStart.sqf new file mode 100644 index 0000000..7dca066 --- /dev/null +++ b/addons/org/XEH_preStart.sqf @@ -0,0 +1,2 @@ +#include "script_component.hpp" +#include "XEH_PREP.hpp" \ No newline at end of file diff --git a/addons/org/config.cpp b/addons/org/config.cpp new file mode 100644 index 0000000..338b901 --- /dev/null +++ b/addons/org/config.cpp @@ -0,0 +1,16 @@ +#include "script_component.hpp" + +class CfgPatches { + class ADDON { + name = COMPONENT_NAME; + units[] = {}; + weapons[] = {}; + requiredVersion = REQUIRED_VERSION; + requiredAddons[] = {"forge_client_main"}; + authors[] = {"J. Schmidt", "Creedcoder"}; + author = "IDSolutions"; + VERSION_CONFIG; + }; +}; + +#include "CfgEventHandlers.hpp" \ No newline at end of file diff --git a/addons/org/functions/fnc_acceptInvite.sqf b/addons/org/functions/fnc_acceptInvite.sqf new file mode 100644 index 0000000..23126ca --- /dev/null +++ b/addons/org/functions/fnc_acceptInvite.sqf @@ -0,0 +1,31 @@ +#include "..\script_component.hpp" + +/* + * Function: forge_client_org_fnc_acceptInvite + * Author: J. Schmidt + * + * Description: + * Allows a player to accept an organization invite from their stored invites + * + * Arguments: + * 0: _playerUID - Player UID + * 1: _playerName - Player Name + * 2: _inviteKey - Invite key from the player's invites + * + * Return Value: + * Success + */ + +params [["_playerUID", "", [""]], ["_playerName", "", [""]], ["_inviteKey", "", [""]]]; + +if (_playerUID == "" || _playerName == "" || _inviteKey == "") exitWith { TRACE_3("Invalid parameters for accepting invitation",_playerUID,_playerName,_inviteKey); false }; + +private _playerInvites = GETVAR(profileNamespace,FORGE_ORG_INVITES,createHashMap); +private _invite = _playerInvites get _inviteKey; + +if (isNil "_invite") exitWith { TRACE_1("Invite not found",_inviteKey); false }; + +private _orgName = _invite get "orgName"; +private _ownerUID = _invite get "ownerUID"; + +[_ownerUID, _orgName, _playerUID, _playerName, "member"] call FUNC(join); \ No newline at end of file diff --git a/addons/org/functions/fnc_addAsset.sqf b/addons/org/functions/fnc_addAsset.sqf new file mode 100644 index 0000000..9c863d2 --- /dev/null +++ b/addons/org/functions/fnc_addAsset.sqf @@ -0,0 +1,49 @@ +#include "..\script_component.hpp" + +/* + * Function: forge_client_org_fnc_addAsset + * Author: J. Schmidt + * + * Description: + * Adds an asset to an organization's inventory + * + * Arguments: + * 0: _uid - Player UID + * 1: _name - Organization name + * 2: _assetType - Type of asset (vehicle, building, etc.) + * 3: _assetData - Asset data + * + * Return Value: + * Updated assets collection + */ + +params [["_uid", "", [""]], ["_name", "", [""]], ["_assetType", "", [""]], ["_assetData", createHashMap, [createHashMap]]]; + +if (_uid == "" || _name == "" || _assetType == "") exitWith { TRACE_3("Invalid parameters for adding asset",_uid,_name,_assetType); nil }; + +private _store = call FUNC(verifyOrgStore); +private _key = format ["%1_%2", _uid, _name]; +private _org = _store call ["getByKey", [_key]]; + +private _timestamp = systemTimeUTC apply { if (_x < 10) then { "0" + str _x } else { str _x }}; +private _dateTime = format ["%1-%2-%3_%4:%5:%6.%7", _timestamp#0, _timestamp#1, _timestamp#2, _timestamp#3, _timestamp#4, _timestamp#5, _timestamp#6]; + +if (isNil "_org") exitWith { TRACE_1("Organization not found",_key); nil }; + +private _assets = _org get "assets"; +private _logs = _org get "logs"; +private _owner = _org get "owner"; + +if (isNil { _assets get _assetType }) then { _assets set [_assetType, []]; }; + +private _typeAssets = _assets get _assetType; + +_typeAssets pushBack _assetData; +_org set ["assets", _assets]; + +_logs pushBack [_dateTime, "ASSET_ADDED", _assetType, _assetData]; +_org set ["logs", _logs]; + +_store call ["post", [_owner, _name]]; + +_assets \ No newline at end of file diff --git a/addons/org/functions/fnc_addFunds.sqf b/addons/org/functions/fnc_addFunds.sqf new file mode 100644 index 0000000..cb3ac8e --- /dev/null +++ b/addons/org/functions/fnc_addFunds.sqf @@ -0,0 +1,44 @@ +#include "..\script_component.hpp" + +/* + * Function: forge_client_org_fnc_addFunds + * Author: J. Schmidt + * + * Description: + * Adds funds to an organization's account + * + * Arguments: + * 0: _uid - Player UID + * 1: _name - Organization name + * 2: _amount - Amount to add (can be negative for withdrawals) + * + * Return Value: + * New funds amount + */ + +params [["_uid", "", [""]], ["_name", "", [""]], ["_amount", 0, [0]]]; + +if (_uid == "" || _name == "") exitWith { TRACE_2("Invalid parameters for adding funds",_uid,_name); nil }; + +private _store = call FUNC(verifyOrgStore); +private _key = format ["%1_%2", _uid, _name]; +private _org = _store call ["getByKey", [_key]]; + +private _timestamp = systemTimeUTC apply { if (_x < 10) then { "0" + str _x } else { str _x }}; +private _dateTime = format ["%1-%2-%3_%4:%5:%6.%7", _timestamp#0, _timestamp#1, _timestamp#2, _timestamp#3, _timestamp#4, _timestamp#5, _timestamp#6]; + +if (isNil "_org") exitWith { TRACE_1("Organization not found",_key); nil }; + +private _funds = _org get "funds"; +private _logs = _org get "logs"; +private _owner = _org get "owner"; +private _newFunds = _funds + _amount; + +_org set ["funds", _newFunds]; + +_logs pushBack [_dateTime, "FUNDS_ADDED", _amount, _newFunds]; +_org set ["logs", _logs]; + +_store call ["post", [_owner, _name]]; + +_newFunds \ No newline at end of file diff --git a/addons/org/functions/fnc_addReputation.sqf b/addons/org/functions/fnc_addReputation.sqf new file mode 100644 index 0000000..7ce09a9 --- /dev/null +++ b/addons/org/functions/fnc_addReputation.sqf @@ -0,0 +1,44 @@ +#include "..\script_component.hpp" + +/* + * Function: forge_client_org_fnc_addReputation + * Author: J. Schmidt + * + * Description: + * Adds reputation to an organization + * + * Arguments: + * 0: _uid - Player UID + * 1: _name - Organization name + * 2: _amount - Amount of reputation to add (can be negative) + * + * Return Value: + * New reputation amount + */ + +params [["_uid", "", [""]], ["_name", "", [""]], ["_amount", 0, [0]]]; + +if (_uid == "" || _name == "") exitWith { TRACE_2("Invalid parameters for adding reputation",_uid,_name); nil }; + +private _store = call FUNC(verifyOrgStore); +private _key = format ["%1_%2", _uid, _name]; +private _org = _store call ["getByKey", [_key]]; + +private _timestamp = systemTimeUTC apply { if (_x < 10) then { "0" + str _x } else { str _x }}; +private _dateTime = format ["%1-%2-%3_%4:%5:%6.%7", _timestamp#0, _timestamp#1, _timestamp#2, _timestamp#3, _timestamp#4, _timestamp#5, _timestamp#6]; + +if (isNil "_org") exitWith { TRACE_1("Organization not found",_key); nil }; + +private _reputation = _org get "reputation"; +private _logs = _org get "logs"; +private _owner = _org get "owner"; +private _newReputation = _reputation + _amount; + +_org set ["reputation", _newReputation]; + +_logs pushBack [_dateTime, "REPUTATION", _amount, _newReputation]; +_org set ["logs", _logs]; + +_store call ["post", [_owner, _name]]; + +_newReputation \ No newline at end of file diff --git a/addons/org/functions/fnc_create.sqf b/addons/org/functions/fnc_create.sqf new file mode 100644 index 0000000..b6bbe50 --- /dev/null +++ b/addons/org/functions/fnc_create.sqf @@ -0,0 +1,43 @@ +#include "..\script_component.hpp" + +/* + * Function: forge_client_org_fnc_create + * Author: J. Schmidt + * + * Description: + * Creates a new organization for a player + * + * Arguments: + * 0: _ownerUID - Player UID + * 1: _ownerName - Player name + * 2: _name - Organization name + * + * Return Value: + * Success + */ + +params [["_ownerUID", "", [""]], ["_ownerName", "", [""]], ["_name", "", [""]]]; + +if (_ownerUID == "" || _ownerName == "" || _name == "") exitWith { TRACE_3("Invalid parameters for organization creation",_ownerUID,_ownerName,_name); false }; + +private _store = call FUNC(verifyOrgStore); +private _key = format ["%1_%2", _ownerUID, _name]; +private _existingOrg = _store call ["getByKey", [_key]]; +private _playerAlreadyInOrg = false; + +{ + private _org = _x; + private _members = _org get "members"; + if (!isNil { _members get _ownerUID }) exitWith { + _playerAlreadyInOrg = true; + }; +} forEach (_store call ["get", []]); + +if (_playerAlreadyInOrg) exitWith { TRACE_1("Player already in an organization",_ownerUID); false }; + +_store call ["post", [_ownerUID, _name, 0, 0]]; +[_name, _ownerUID, _ownerName, "owner"] call FUNC(join); + +TRACE_2("Organization created successfully",_name,_ownerUID); + +true \ No newline at end of file diff --git a/addons/org/functions/fnc_disband.sqf b/addons/org/functions/fnc_disband.sqf new file mode 100644 index 0000000..5b5b893 --- /dev/null +++ b/addons/org/functions/fnc_disband.sqf @@ -0,0 +1,33 @@ +#include "..\script_component.hpp" + +/* + * Function: forge_client_org_fnc_disband + * Author: J. Schmidt + * + * Description: + * Disbands an organization if requested by the owner + * + * Arguments: + * 0: _uid - UID of the player attempting to disband + * 1: _name - Organization name + * + * Return Value: + * Success + */ + +params [["_uid", "", [""]], ["_name", "", [""]]]; + +if (_uid == "" || _name == "") exitWith { TRACE_2("Invalid parameters for disbanding organization",_uid,_name); false }; + +private _store = call FUNC(verifyOrgStore); +private _key = format ["%1_%2", _uid, _name]; +private _org = _store call ["getByKey", [_key]]; + +if (isNil "_org") exitWith { TRACE_1("Organization not found",_key); false }; +if ((_org get "owner") != _uid) exitWith { TRACE_2("Player is not the owner of this organization",_uid,_name); false }; + +_store call ["delete", [_key]]; + +TRACE_1("Organization disbanded successfully",_name); + +true \ No newline at end of file diff --git a/addons/org/functions/fnc_initOrgStore.sqf b/addons/org/functions/fnc_initOrgStore.sqf new file mode 100644 index 0000000..6c15eea --- /dev/null +++ b/addons/org/functions/fnc_initOrgStore.sqf @@ -0,0 +1,134 @@ +#include "..\script_component.hpp" + +/* + * Function: forge_client_org_fnc_initOrgStore + * Author: J. Schmidt + * + * Description: + * Initializes player organization data using the database interface + * + * Arguments: + * None + * + * Return Value: + * Organization interface + */ + +private _orgStoreInterface = createHashMapObject [[ + ["#type", "IOrganizationStore"], + ["#create", { + private _store = GETMVAR(FORGE_STORE_REG,nil); + + if (isNil "_store") exitWith { ERROR_MSG("Store not initialized"); false }; + + private _orgStore = _store call ["getStore", ["organizations"]]; + private _orgNameIndex = _store call ["getStore", ["organizationNameIndex"]]; + private _orgRegistry = GETVAR(profileNamespace,FORGE_ORG_REG,createHashMap); + + if (isNil "_orgStore" || isNil "_orgNameIndex") then { _orgStore = _store call ["createStore", ["organizations"]]; }; + if (isNil "_orgNameIndex") then { _orgNameIndex = _store call ["createStore", ["organizationNameIndex"]]; }; + + private _name = _orgRegistry get "name"; + private _uid = _orgRegistry get "owner"; + + if (!isNil "_name" && !isNil "_uid") then { + private _key = format ["%1_%2", _uid, _name]; + + _orgStore set [_key, _orgRegistry]; + _orgNameIndex set [_key, _name]; + }; + + true + }], + ["post", { + params [["_uid", "", [""]], ["_name", "", [""]], ["_initialFunds", 0, [0]], ["_initialReputation", 0, [0]]]; + + if (_uid == "" || _name == "") exitWith { ERROR_MSG("Owner UID and, or name cannot be empty"); nil }; + + private _store = GETMVAR(FORGE_STORE_REG,nil); + private _key = format ["%1_%2", _uid, _name]; + + private _timestamp = systemTimeUTC apply { if (_x < 10) then { "0" + str _x } else { str _x }}; + private _dateTime = format ["%1-%2-%3_%4:%5:%6.%7", _timestamp#0, _timestamp#1, _timestamp#2, _timestamp#3, _timestamp#4, _timestamp#5, _timestamp#6]; + + private _orgRegistry = GETVAR(profileNamespace,FORGE_ORG_REG,createHashMap); + + private _existingOrgKey = _store call ["get", ["organizationNameIndex", _key]]; + private _existingOrg = nil; + private _orgData = nil; + + if !(isNil "_existingOrgKey") then { + _existingOrg = _store call ["get", ["organizations", _existingOrgKey]]; + }; + + if !(isNil "_existingOrg") then { + _orgData = _existingOrg; + } else { + _orgData = createHashMapFromArray [ + ["name", _name], + ["owner", _uid], + ["funds", _initialFunds], + ["reputation", _initialReputation], + ["assets", createHashMap], + ["members", createHashMap], + ["invites", createHashMap], + ["logs", []], + ["created", _dateTime] + ]; + + _orgRegistry set [_key, _orgData]; + + SETVAR(profileNamespace,FORGE_ORG_REG,_orgRegistry); + saveProfileNamespace; + }; + + _store call ["set", ["organizationNameIndex", _key, _name]]; + _store call ["set", ["organizations", _key, _orgData]]; + + _orgData + }], + ["get", { + private _store = GETMVAR(FORGE_STORE_REG,nil); + private _orgStore = _store call ["getStore", ["organizations"]]; + + if (isNil "_orgStore") exitWith { createHashMap }; + + _orgStore + }], + ["getByKey", { + params [["_key", "", [""]]]; + + if (_key == "") exitWith { ERROR_MSG("Key cannot be empty"); nil }; + + private _store = GETMVAR(FORGE_STORE_REG,nil); + private _org = _store call ["get", ["organizations", _key]] + + if (isNil "_org") exitWith { ERROR_MSG_1("Organization with composite key %1 not found", _key); nil }; + + _org + }], + ["delete", { + params [["_key", "", [""]]]; + + if (_key == "") exitWith { ERROR_MSG("Key cannot be empty"); false }; + + private _store = GETMVAR(FORGE_STORE_REG,nil); + private _key = _store call ["get", ["organizationNameIndex", _key, nil]]; + + _store call ["delete", ["organizationNameIndex", _key]]; + + if (isNil "_key") exitWith { ERROR_MSG_1("Key for organization not found", _key); false }; + + _store call ["delete", ["organizations", _key]]; + + private _orgRegistry = GETVAR(profileNamespace,FORGE_ORG_REG,createHashMap); + _orgRegistry deleteAt _key; + SETVAR(profileNamespace,FORGE_ORG_REG,_orgRegistry); + saveProfileNamespace; + + true + }] +]]; + +SETMVAR(FORGE_ORG_STORE_REG,_orgStoreInterface); +GETMVAR(FORGE_ORG_STORE_REG,nil) \ No newline at end of file diff --git a/addons/org/functions/fnc_invite.sqf b/addons/org/functions/fnc_invite.sqf new file mode 100644 index 0000000..3bb4013 --- /dev/null +++ b/addons/org/functions/fnc_invite.sqf @@ -0,0 +1,76 @@ +#include "..\script_component.hpp" + +/* + * Function: forge_client_org_fnc_invite + * Author: J. Schmidt + * + * Description: + * Sends an invitation to a player to join an organization + * + * Arguments: + * 0: _uid - Player UID + * 1: _name - Organization name + * 2: _targetUID - Target player's UID + * 3: _targetName - Target player's name + * + * Return Value: + * Success + */ + +params [["_uid", "", [""]], ["_name", "", [""]], ["_targetUID", "", [""]], ["_targetName", "", [""]]]; + +if (_uid == "" || _name == "" || _targetUID == "" || _targetName == "") exitWith { TRACE_3("Invalid parameters for organization invitation",_uid,_name,_targetUID); false }; + +private _store = call FUNC(verifyOrgStore); +private _key = format ["%1_%2", _uid, _name]; +private _org = _store call ["getByKey", [_key]]; + +private _timestamp = systemTimeUTC apply { if (_x < 10) then { "0" + str _x } else { str _x }}; +private _dateTime = format ["%1-%2-%3_%4:%5:%6.%7", _timestamp#0, _timestamp#1, _timestamp#2, _timestamp#3, _timestamp#4, _timestamp#5, _timestamp#6]; + +if (isNil "_org") exitWith { TRACE_1("Organization not found",_key); false }; + +private _invites = _org get "invites"; +private _logs = _org get "logs"; + +private _invite = createHashMapFromArray [ + ["uid", _targetUID], + ["name", _targetName], + ["timestamp", _dateTime], + ["status", "pending"] +]; + +_invites set [_targetUID, _invite]; +_org set ["invites", _invites]; + +_logs pushBack [_dateTime, "INVITE", _targetName, _targetUID]; +_org set ["logs", _logs]; + +_store call ["post", [_uid, _name]]; + +[_targetUID, _uid, _name, _dateTime] spawn { + params ["_targetUID", "_ownerUID", "_orgName", "_timestamp"]; + + if (isRemoteExecuted && remoteExecutedOwner != 2) exitWith {}; + + private _target = [_targetUID] call BIS_fnc_getUnitByUID; + + if !(isNull _target) then { + private _orgInvites = GETVAR(profileNamespace,FORGE_ORG_INVITES,createHashMap); + private _inviteKey = format ["%1_%2", _ownerUID, _orgName]; + + _orgInvites set [_inviteKey, createHashMapFromArray [ + ["orgName", _orgName], + ["ownerUID", _ownerUID], + ["timestamp", _timestamp], + ["status", "pending"] + ]]; + + SETVAR(profileNamespace,FORGE_ORG_INVITES,_orgInvites); + saveProfileNamespace; + + [format ["You have been invited to join %1", _orgName]] remoteExec ["hint", _target]; + }; +}; + +true \ No newline at end of file diff --git a/addons/org/functions/fnc_join.sqf b/addons/org/functions/fnc_join.sqf new file mode 100644 index 0000000..6714bf0 --- /dev/null +++ b/addons/org/functions/fnc_join.sqf @@ -0,0 +1,86 @@ +#include "..\script_component.hpp" + +/* + * Function: forge_client_org_fnc_join + * Author: J. Schmidt + * + * Description: + * Adds a player to an organization, either as a new member or the owner + * + * Arguments: + * 0: _uid - Player UID + * 1: _name - Organization name + * 2: _targetUID - Target player's UID + * 3: _targetName - Target player's name + * 4: _targetRank - Player's rank in organization (default: "member") + * + * Return Value: + * Success + */ + +params [["_uid", "", [""]], ["_name", "", [""]], ["_targetUID", "", [""]], ["_targetName", "", [""]], ["_targetRank", "member", [""]]]; + +if (_uid == "" || _name == "" || _targetUID == "" || _targetName == "") exitWith { TRACE_3("Invalid parameters for joining organization",_name,_targetUID,_targetName); false }; + +private _store = call FUNC(verifyOrgStore); +private _key = format ["%1_%2", _uid, _name]; +private _org = _store call ["getByKey", [_key]]; +private _playerAlreadyInOrg = false; + +private _timestamp = systemTimeUTC apply { if (_x < 10) then { "0" + str _x } else { str _x }}; +private _dateTime = format ["%1-%2-%3_%4:%5:%6.%7", _timestamp#0, _timestamp#1, _timestamp#2, _timestamp#3, _timestamp#4, _timestamp#5, _timestamp#6]; + +if (isNil "_org") exitWith { TRACE_1("Organization not found",_key); false }; + +private _invites = _org get "invites"; +private _logs = _org get "logs"; +private _members = _org get "members"; + +{ + private _checkOrg = _x; + private _checkMembers = _checkOrg get "members"; + if (!isNil { _checkMembers get _targetUID }) exitWith { + _playerAlreadyInOrg = true; + }; +} forEach (_store call ["get", []]); + +if (_playerAlreadyInOrg) exitWith { TRACE_2("Player already in an organization",_targetUID,_targetName); false }; + +private _member = createHashMapFromArray [ + ["uid", _targetUID], + ["name", _targetName], + ["rank", _targetRank], + ["joinDate", _dateTime] +]; + +if (_targetRank == "owner") then { + _members set [_targetUID, _member]; + _org set ["members", _members]; + + _store call ["post", [_uid, _name]]; + true +} else { + if !(isNil { _invites get _targetUID }) then { + _invites deleteAt _targetUID; + _members set [_targetUID, _member]; + + _org set ["members", _members]; + _org set ["invites", _invites]; + + _logs pushBack [_dateTime, "JOIN", _targetName, _targetUID]; + _org set ["logs", _logs]; + + private _inviteKey = format ["%1_%2", _uid, _name]; + private _orgInvites = GETVAR(profileNamespace,FORGE_ORG_INVITES,createHashMap); + + _orgInvites deleteAt _inviteKey; + SETVAR(profileNamespace,FORGE_ORG_INVITES,_orgInvites); + saveProfileNamespace; + + _store call ["post", [_uid, _name]]; + true + } else { + TRACE_2("Player not invited to this organization",_targetUID,_name); + false + }; +}; \ No newline at end of file diff --git a/addons/org/functions/fnc_leave.sqf b/addons/org/functions/fnc_leave.sqf new file mode 100644 index 0000000..1f6a532 --- /dev/null +++ b/addons/org/functions/fnc_leave.sqf @@ -0,0 +1,50 @@ +#include "..\script_component.hpp" + +/* + * Function: forge_client_org_fnc_leave + * Author: J. Schmidt + * + * Description: + * Removes a player from an organization + * + * Arguments: + * 0: _ownerUID - Organization owner's UID + * 1: _orgName - Organization name + * 2: _playerUID - Player's UID who is leaving + * 3: _playerName - Player's name who is leaving + * + * Return Value: + * Success + */ + +params [["_ownerUID", "", [""]], ["_orgName", "", [""]], ["_playerUID", "", [""]], ["_playerName", "", [""]]]; + +if (_ownerUID == "" || _orgName == "" || _playerUID == "" || _playerName == "") exitWith { TRACE_4("Invalid parameters for leaving organization",_ownerUID,_orgName,_playerUID,_playerName); false }; + +private _store = call FUNC(verifyOrgStore); +private _key = format ["%1_%2", _ownerUID, _orgName]; +private _org = _store call ["getByKey", [_key]]; + +private _timestamp = systemTimeUTC apply { if (_x < 10) then { "0" + str _x } else { str _x }}; +private _dateTime = format ["%1-%2-%3_%4:%5:%6.%7", _timestamp#0, _timestamp#1, _timestamp#2, _timestamp#3, _timestamp#4, _timestamp#5, _timestamp#6]; + +if (isNil "_org") exitWith { TRACE_1("Organization not found", _key); false }; + +private _members = _org get "members"; +private _logs = _org get "logs"; + +if (isNil { _members get _playerUID }) exitWith { TRACE_2("Player not in this organization",_playerUID,_orgName); false }; + +private _memberData = _members get _playerUID; + +if (_memberData get "rank" == "owner") exitWith { TRACE_2("Owner cannot leave organization, must transfer ownership first",_playerUID,_orgName); false }; + +_logs pushBack [_dateTime, "LEAVE", _playerName, _playerUID]; +_org set ["logs", _logs]; + +_members deleteAt _playerUID; +_org set ["members", _members]; + +_store call ["post", [_ownerUID, _orgName]]; + +true \ No newline at end of file diff --git a/addons/org/functions/fnc_listInvites.sqf b/addons/org/functions/fnc_listInvites.sqf new file mode 100644 index 0000000..421388d --- /dev/null +++ b/addons/org/functions/fnc_listInvites.sqf @@ -0,0 +1,36 @@ +#include "..\script_component.hpp" + +/* + * Function: forge_client_org_fnc_listPlayerInvites + * Author: J. Schmidt + * + * Description: + * Lists all organization invites for the current player + * + * Arguments: + * 0: _playerUID - Player UID + * + * Return Value: + * Array of organization invites + */ + +params [["_playerUID", "", [""]]]; + +if (_playerUID == "") exitWith { TRACE_1("Invalid player UID",_playerUID); [] }; + +private _playerInvites = GETVAR(profileNamespace,FORGE_ORG_INVITES,createHashMap); +private _invitesList = []; + +{ + private _inviteKey = _x; + private _invite = _playerInvites get _inviteKey; + + _invitesList pushBack [ + _inviteKey, + _invite get "orgName", + _invite get "ownerUID", + _invite get "timestamp" + ]; +} forEach (keys _playerInvites); + +_invitesList \ No newline at end of file diff --git a/addons/org/functions/fnc_removeAsset.sqf b/addons/org/functions/fnc_removeAsset.sqf new file mode 100644 index 0000000..027c96d --- /dev/null +++ b/addons/org/functions/fnc_removeAsset.sqf @@ -0,0 +1,52 @@ +#include "..\script_component.hpp" + +/* + * Function: forge_client_org_fnc_removeAsset + * Author: J. Schmidt + * + * Description: + * Removes an asset from an organization's inventory + * + * Arguments: + * 0: _uid - Player UID + * 1: _name - Organization name + * 2: _assetType - Type of asset (vehicle, building, etc.) + * 3: _assetId - Unique identifier of the asset + * + * Return Value: + * Updated assets collection + */ + +params [["_uid", "", [""]], ["_name", "", [""]], ["_assetType", "", [""]], ["_assetId", "", [""]]]; + +if (_uid isEqualTo "" || _name isEqualTo "" || _assetType isEqualTo "" || _assetId isEqualTo "") exitWith { TRACE_4("Invalid parameters for removing asset",_uid,_name,_assetType,_assetId); createHashMap }; + +private _store = call FUNC(verifyOrgStore); +private _key = format ["%1_%2", _uid, _name]; +private _org = _store call ["getByKey", [_key]]; + +private _timestamp = systemTimeUTC apply { if (_x < 10) then { "0" + str _x } else { str _x }}; +private _dateTime = format ["%1-%2-%3_%4:%5:%6.%7", _timestamp#0, _timestamp#1, _timestamp#2, _timestamp#3, _timestamp#4, _timestamp#5, _timestamp#6]; + +if (isNil "_org") exitWith { TRACE_1("Organization not found",_name); createHashMap }; + +private _assets = _org get "assets"; +private _logs = _org get "logs"; +private _typeAssets = _assets getOrDefault [_assetType, []]; +private _index = _typeAssets findIf { (_x getOrDefault ["id", ""]) == _assetId }; + +if (_index != -1) then { + private _assetToRemove = _typeAssets select _index; + private _assetName = _assetToRemove getOrDefault ["name", "Unknown Asset"]; + + _typeAssets deleteAt _index; + + _logs pushBack [_dateTime, "ASSET_REMOVED", _assetType, _assetName]; + _org set ["logs", _logs]; +}; + +_org set ["assets", _assets]; + +_store call ["post", [_uid, _name]]; + +_assets \ No newline at end of file diff --git a/addons/org/functions/fnc_verifyOrgStore.sqf b/addons/org/functions/fnc_verifyOrgStore.sqf new file mode 100644 index 0000000..2ccd549 --- /dev/null +++ b/addons/org/functions/fnc_verifyOrgStore.sqf @@ -0,0 +1,22 @@ +#include "..\script_component.hpp" + +/* + * Function: forge_client_org_fnc_verifyOrgStore + * Author: J. Schmidt + * + * Description: + * Ensures the store is initialized and returns the store object + * + * Arguments: + * None + * + * Return Value: + * Store object + */ + +private _store = GETMVAR(FORGE_ORG_STORE_REG,nil); +if (isNil "_store") then { + _store = [] call FUNC(initOrgStore); +}; + +_store \ No newline at end of file diff --git a/addons/org/script_component.hpp b/addons/org/script_component.hpp new file mode 100644 index 0000000..c44062d --- /dev/null +++ b/addons/org/script_component.hpp @@ -0,0 +1,16 @@ +#define COMPONENT org +#define COMPONENT_BEAUTIFIED Org +#include "\z\forge_client\addons\main\script_mod.hpp" + +// #define DEBUG_MODE_FULL +// #define DISABLE_COMPILE_CACHE + +#ifdef DEBUG_ENABLED_ORG + #define DEBUG_MODE_FULL +#endif + +#ifdef DEBUG_SETTINGS_ORG + #define DEBUG_SETTINGS DEBUG_SETTINGS_ORG +#endif + +#include "\z\forge_client\addons\main\script_macros.hpp" \ No newline at end of file diff --git a/addons/store/functions/fnc_buyItem.sqf b/addons/store/functions/fnc_buyItem.sqf index f9b9dee..d86846b 100644 --- a/addons/store/functions/fnc_buyItem.sqf +++ b/addons/store/functions/fnc_buyItem.sqf @@ -30,6 +30,6 @@ switch (_configType) do { // player setVariable ["FORGE_Locker", _locker, true]; SETPVAR(player,FORGE_Locker,_locker); -[_className, _itemType] call EFUNC(armory,addArmoryItem); +[_className, _itemType] call EFUNC(arsenal,addArmoryItem); [format ["You have purchased %1 for $%2.", _displayName, _price], "info", 3, "right"] call EFUNC(misc,notify); \ No newline at end of file