feat: Implement core game systems for actor, garage, organization, bank, locker, and notifications with client-side UI and server-side data stores.

This commit is contained in:
Jacob Schmidt 2026-01-30 20:19:29 -06:00
parent 9c09976ef2
commit aef7f9ae48
49 changed files with 384 additions and 254 deletions

View File

@ -23,7 +23,7 @@ player addEventHandler ["Respawn", {
[SRPC(economy,onRespawn), [_unit, _corpse, _uid]] call CFUNC(serverEvent);
}];
if (isNil QGVAR(ActorClass)) then { [] call FUNC(initActorClass); };
if (isNil QGVAR(ActorClass)) then { call FUNC(initActorClass); };
[QGVAR(initActor), {
GVAR(ActorClass) call ["init", []];

View File

@ -4,7 +4,7 @@
* File: fnc_handleUIEvents.sqf
* Author: IDSolutions
* Date: 2026-01-28
* Last Update: 2026-01-28
* Last Update: 2026-01-30
* Public: No
*
* Description:
@ -19,7 +19,7 @@
* UI events handled [BOOL]
*
* Example:
* [] call forge_client_actor_fnc_handleUIEvents;
* call forge_client_actor_fnc_handleUIEvents;
*/
params ["_control", "_isConfirmDialog", "_message"];
@ -27,7 +27,7 @@ params ["_control", "_isConfirmDialog", "_message"];
private _alert = fromJSON _message;
private _event = _alert get "event";
private _data = _alert get "data";
private _display = displayChild findDisplay 46;
// private _display = displayChild findDisplay 46;
diag_log format ["[FORGE:Client:Actor] Handling UI event: %1 with data: %2", _event, _data];
@ -35,19 +35,20 @@ switch (_event) do {
case "actor::get::actions": { GVAR(ActorClass) call ["getNearbyActions", [_control]]; };
case "actor::open::atm": { [true] spawn EFUNC(bank,openUI); };
case "actor::open::bank": { [] spawn EFUNC(bank,openUI); };
case "actor::open::device": { hint "Device interaction is not yet implemented."; }; // TODO: Implement device interaction
case "actor::open::garage": { hint "Garage interaction is not yet implemented."; }; // TODO: Implement garage interaction
case "actor::open::device": { hint "Device interaction is not yet implemented."; };
case "actor::open::garage": { hint "Garage interaction is not yet implemented."; };
case "actor::open::vgarage": { [] spawn EFUNC(garage,openVG); };
case "actor::open::org": { [] spawn EFUNC(org,openUI); };
case "actor::open::locker": { hint "Locker interaction is not yet implemented."; }; // TODO: Implement locker interaction
// case "actor::open::locker": { hint "Locker interaction is not yet implemented."; };
case "actor::open::vlocker": { ["Open", [false, FORGE_Locker_Box, player]] spawn BFUNC(arsenal) };
// case "actor::open::phone": { [] spawn EFUNC(phone,openUI) };
case "actor::open::phone": { hint "Phone interaction is not yet implemented."; }; // TODO: Implement phone interaction
case "actor::open::iplayer": { hint "Player interaction is not yet implemented." }; // TODO: Implement player interaction
case "actor::open::store": { hint "Store interaction is not yet implemented."; }; // TODO: Implement store interaction
case "actor::open::phone": { hint "Phone interaction is not yet implemented."; };
case "actor::open::iplayer": { hint "Player interaction is not yet implemented." };
case "actor::open::store": { hint "Store interaction is not yet implemented."; };
default { hint format ["Unhandled UI event: %1", _event]; };
};
if (_event isNotEqualTo "actor::get::actions") then { _display closeDisplay 1; };
// if (_event isNotEqualTo "actor::get::actions") then { _display closeDisplay 1; };
if (_event isNotEqualTo "actor::get::actions") then { closeDialog 1; };
true;

View File

@ -4,7 +4,7 @@
* File: fnc_initActorClass.sqf
* Author: IDSolutions
* Date: 2026-01-28
* Last Update: 2026-01-28
* Last Update: 2026-01-30
* Public: Yes
*
* Description:
@ -18,7 +18,7 @@
* Actor class object [HASHMAP OBJECT]
*
* Example:
* [] call forge_client_actor_fnc_initActorClass
* call forge_client_actor_fnc_initActorClass
*/
#pragma hemtt ignore_variables ["_self"]
@ -131,7 +131,7 @@ GVAR(ActorClass) = createHashMapObject [[
if (_storeType isNotEqualTo "") then { _nearbyActions pushBack ["store", _storeType]; };
if (_isBank) then { _nearbyActions pushBack ["bank", true]; };
if (_isLocker) then { _nearbyActions pushBack ["locker", true]; };
// if (_isLocker) then { _nearbyActions pushBack ["locker", true]; };
if (_isLocker && GVAR(enableVA)) then { _nearbyActions pushBack ["va", true]; };
if (_isGarage) then { _nearbyActions pushBack ["garage", _garageType]; };
if (_isGarage && GVAR(enableVG)) then { _nearbyActions pushBack ["vg", true]; };

View File

@ -4,7 +4,7 @@
* File: fnc_openUI.sqf
* Author: IDSolutions
* Date: 2026-01-28
* Last Update: 2026-01-28
* Last Update: 2026-01-30
* Public: No
*
* Description:
@ -17,11 +17,11 @@
* UI opened [BOOL]
*
* Example:
* [] call forge_client_actor_fnc_openUI;
* call forge_client_actor_fnc_openUI;
*/
private _display = (findDisplay 46) createDisplay "RscActorMenu";
private _ctrl = (_display displayCtrl 1001);
private _display = createDialog ["RscActorMenu", true];
private _ctrl = _display displayCtrl 1001;
_ctrl ctrlAddEventHandler ["JSDialog", {
params ["_control", "_isConfirmDialog", "_message"];

View File

@ -92,13 +92,13 @@ const actionDefinitions = {
icon: "",
action: "actor::open::garage",
},
locker: {
id: "locker",
title: "Locker",
description: "Access your personal locker for storage",
icon: "",
action: "actor::open::locker",
},
// locker: {
// id: "locker",
// title: "Locker",
// description: "Access your personal locker for storage",
// icon: "",
// action: "actor::open::locker",
// },
player: {
id: "player",
title: "Player Interaction",

View File

@ -1,6 +1,6 @@
#include "script_component.hpp"
if (isNil QGVAR(BankClass)) then { [] call FUNC(initBankClass); };
if (isNil QGVAR(BankClass)) then { call FUNC(initBankClass); };
[QGVAR(initBank), {
GVAR(BankClass) call ["init", []];

View File

@ -4,7 +4,7 @@
* File: fnc_handleUIEvents.sqf
* Author: IDSolutions
* Date: 2025-12-16
* Last Update: 2026-01-28
* Last Update: 2026-01-30
* Public: No
*
* Description:
@ -19,7 +19,7 @@
* UI events handled [BOOL]
*
* Example:
* [] call forge_client_bank_fnc_handleUIEvents;
* call forge_client_bank_fnc_handleUIEvents;
*/
params ["_control", "_isConfirmDialog", "_message"];

View File

@ -4,7 +4,7 @@
* File: fnc_initBankClass.sqf
* Author: IDSolutions
* Date: 2025-12-16
* Last Update: 2026-01-28
* Last Update: 2026-01-30
* Public: No
*
* Description:
@ -17,7 +17,7 @@
* Bank class object [HASHMAP OBJECT]
*
* Example:
* [] call forge_client_bank_fnc_initBankClass
* call forge_client_bank_fnc_initBankClass
*/
#pragma hemtt ignore_variables ["_self"]

View File

@ -4,7 +4,7 @@
* File: fnc_openUI.sqf
* Author: IDSolutions
* Date: 2026-01-28
* Last Update: 2026-01-28
* Last Update: 2026-01-30
* Public: No
*
* Description:
@ -22,8 +22,8 @@
params [["_isATM", false, [false]]];
private _display = (findDisplay 46) createDisplay "RscBank";
private _ctrl = (_display displayCtrl 1002);
private _display = createDialog ["RscBank", true];
private _ctrl = _display displayCtrl 1002;
_ctrl ctrlAddEventHandler ["JSDialog", {
params ["_control", "_isConfirmDialog", "_message"];

View File

@ -1,7 +1,7 @@
#include "script_component.hpp"
if (isNil QGVAR(GarageClass)) then { [] call FUNC(initGarageClass); };
if (isNil QGVAR(VGarageClass)) then { [] call FUNC(initVGClass); };
if (isNil QGVAR(GarageClass)) then { call FUNC(initGarageClass); };
if (isNil QGVAR(VGarageClass)) then { call FUNC(initVGClass); };
[QGVAR(initGarage), {
GVAR(GarageClass) call ["init", []];

View File

@ -4,7 +4,7 @@
* File: fnc_handleUIEvents.sqf
* Author: IDSolutions
* Date: 2025-12-16
* Last Update: 2026-01-28
* Last Update: 2026-01-30
* Public: No
*
* Description:
@ -19,5 +19,5 @@
* UI events handled [BOOL]
*
* Example:
* [] call forge_client_garage_fnc_handleUIEvents;
* call forge_client_garage_fnc_handleUIEvents;
*/

View File

@ -4,7 +4,7 @@
* File: fnc_initGarageClass.sqf
* Author: IDSolutions
* Date: 2025-12-17
* Last Update: 2026-01-28
* Last Update: 2026-01-30
* Public: No
*
* Description:
@ -18,7 +18,7 @@
* Garage class object [HASHMAP OBJECT]
*
* Example:
* [] call forge_client_garage_fnc_initGarageClass
* call forge_client_garage_fnc_initGarageClass
*/
#pragma hemtt ignore_variables ["_self"]

View File

@ -4,7 +4,7 @@
* File: fnc_initVGClass.sqf
* Author: IDSolutions
* Date: 2025-12-16
* Last Update: 2026-01-28
* Last Update: 2026-01-30
* Public: No
*
* Description:
@ -18,7 +18,7 @@
* vGarage class object [HASHMAP OBJECT]
*
* Example:
* [] call forge_client_garage_fnc_initVGClass;
* call forge_client_garage_fnc_initVGClass;
*/
#pragma hemtt ignore_variables ["_self"]

View File

@ -4,7 +4,7 @@
* File: fnc_openUI.sqf
* Author: IDSolutions
* Date: 2025-12-16
* Last Update: 2026-01-28
* Last Update: 2026-01-30
* Public: No
*
* Description:
@ -17,5 +17,5 @@
* UI opened [BOOL]
*
* Example:
* [] call forge_client_garage_fnc_openUI;
* call forge_client_garage_fnc_openUI;
*/

View File

@ -4,7 +4,7 @@
* File: fnc_openVG.sqf
* Author: IDSolutions
* Date: 2025-12-16
* Last Update: 2026-01-28
* Last Update: 2026-01-30
* Public: No
*
* Description:
@ -17,7 +17,7 @@
* None
*
* Example:
* [] call forge_client_garage_fnc_openVG
* call forge_client_garage_fnc_openVG
*/
private _locations = (missionConfigFile >> "FORGE_CfgGarages" >> "locations") call BFUNC(getCfgData);

View File

@ -1,7 +1,7 @@
#include "script_component.hpp"
if (isNil QGVAR(LockerClass)) then { [] call FUNC(initLockerClass); };
if (isNil QGVAR(VArsenalClass)) then { [] call FUNC(initVAClass); };
if (isNil QGVAR(LockerClass)) then { call FUNC(initLockerClass); };
if (isNil QGVAR(VArsenalClass)) then { call FUNC(initVAClass); };
[QGVAR(initLocker), {
GVAR(LockerClass) call ["init", []];

View File

@ -1,23 +0,0 @@
#include "..\script_component.hpp"
/*
* File: fnc_handleUIEvents.sqf
* Author: IDSolutions
* Date: 2026-01-28
* Last Update: 2026-01-28
* Public: No
*
* Description:
* Handles the UI events.
*
* Arguments:
* 0: [CONTROL] - The control that triggered the event
* 1: [BOOL] - Whether the event is from a confirm dialog
* 2: [STRING] - The message containing the event data
*
* Return Value:
* UI events handled [BOOL]
*
* Example:
* [] call forge_client_locker_fnc_handleUIEvents;
*/

View File

@ -4,7 +4,7 @@
* File: fnc_initLockerClass.sqf
* Author: IDSolutions
* Date: 2025-12-17
* Last Update: 2026-01-28
* Last Update: 2026-01-30
* Public: No
*
* Description:
@ -18,26 +18,164 @@
* Locker class object [HASHMAP OBJECT]
*
* Example:
* [] call forge_client_locker_fnc_initLockerClass
* call forge_client_locker_fnc_initLockerClass
*/
#pragma hemtt ignore_variables ["_self"]
GVAR(LockerClass) = createHashMapObject [[
["#type", "ILockerClass"],
["#create", {
_self set ["uid", (getPlayerUID player)];
_self set ["locker", createHashMap];
_self set ["isLoaded", false];
_self set ["lastSave", time];
}],
["init", {
private _uid = _self get "uid";
GVAR(LockerRepository) = compileFinal createHashMapFromArray [
["#type", "LockerRepository"],
["get", {
params [["_key", "", [""]], ["_default", nil, [[], "", 0, false, createHashMap]]];
private _locker = _self get "locker";
_locker getOrDefault [_key, _default];
}],
["getCargo", {
params [["_container", objNull, [objNull]], ["_locker", createHashMap, [createHashMap]]];
[SRPC(locker,requestInitLocker), [_uid, _locker]] call CFUNC(serverEvent);
private _cargoData = [
["item", getItemCargo _container],
["weapon", getWeaponCargo _container],
["magazine", getMagazineCargo _container],
["backpack", getBackpackCargo _container]
];
systemChat format ["Locker loaded for %1", (name player)];
diag_log "[FORGE:Client:Locker] Locker Class Initialized!";
{
_x params ["_category", "_data"];
_data params ["_classes", "_counts"];
{
private _class = _x;
private _count = _counts select _forEachIndex;
_locker set [_class, createHashMapFromArray [
["amount", _count],
["classname", _class],
["category", _category]
]];
} forEach _classes;
} forEach _cargoData;
_locker
}],
["getContainerItems", {
params [["_container", objNull, [objNull]], ["_locker", createHashMap, [createHashMap]]];
private _allContainers = everyContainer _container;
{
_x params ["_containerClass", "_containerObj"];
private _isBackpack = isClass (configFile >> "CfgVehicles" >> _containerClass);
private _cfgWeapons = configFile >> "CfgWeapons" >> _containerClass;
private _itemInfoType = getNumber (_cfgWeapons >> "ItemInfo" >> "type");
private _isVest = isClass _cfgWeapons && {_itemInfoType == 701};
private _isUniform = isClass _cfgWeapons && {_itemInfoType == 801};
if (!_isBackpack && !_isVest && !_isUniform) then { continue; };
private _containerItems = getItemCargo _containerObj;
_containerItems params ["_classes", "_counts"];
{
private _class = _x;
private _count = _counts select _forEachIndex;
private _existing = _locker getOrDefault [_class, createHashMap];
private _existingCount = _existing getOrDefault ["amount", 0];
_locker set [_class, createHashMapFromArray [
["amount", _existingCount + _count],
["classname", _class],
["category", "item"]
]];
} forEach _classes;
private _containerMags = getMagazineCargo _containerObj;
_containerMags params ["_classes", "_counts"];
{
private _class = _x;
private _count = _counts select _forEachIndex;
private _existing = _locker getOrDefault [_class, createHashMap];
private _existingCount = _existing getOrDefault ["amount", 0];
_locker set [_class, createHashMapFromArray [
["amount", _existingCount + _count],
["classname", _class],
["category", "magazine"]
]];
} forEach _classes;
private _containerWeapons = getWeaponCargo _containerObj;
_containerWeapons params ["_classes", "_counts"];
{
private _class = _x;
private _count = _counts select _forEachIndex;
private _existing = _locker getOrDefault [_class, createHashMap];
private _existingCount = _existing getOrDefault ["amount", 0];
_locker set [_class, createHashMapFromArray [
["amount", _existingCount + _count],
["classname", _class],
["category", "weapon"]
]];
} forEach _classes;
} forEach _allContainers;
_locker
}],
["getAttachments", {
params [["_container", objNull, [objNull]], ["_locker", createHashMap, [createHashMap]]];
private _weaponItems = weaponsItemsCargo _container;
{
// private _weapon = _x param [0, ""];
private _muzzle = _x param [1, ""];
private _pointer = _x param [2, ""];
private _optic = _x param [3, ""];
private _primaryMag = _x param [4, ["", 0]];
private _underbarrel = _x param [5, ""];
private _bipod = _x param [6, ""];
private _secondaryMag = _x param [7, ["", 0]];
private _attachments = [_muzzle, _pointer, _optic, _underbarrel, _bipod] select {(_x isEqualType "") && {_x != ""}};
{
private _existing = _locker getOrDefault [_x, createHashMap];
private _existingCount = _existing getOrDefault ["amount", 0];
_locker set [_x, createHashMapFromArray [
["amount", _existingCount + 1],
["classname", _x],
["category", "item"]
]];
} forEach _attachments;
if (_primaryMag isNotEqualTo ["", 0]) then {
_primaryMag params ["_magClass", "_ammoCount"];
if (_magClass != "") then {
private _existing = _locker getOrDefault [_magClass, createHashMap];
private _existingCount = _existing getOrDefault ["amount", 0];
_locker set [_magClass, createHashMapFromArray [
["amount", _existingCount + 1],
["classname", _magClass],
["category", "magazine"]
]];
};
};
if (_secondaryMag isNotEqualTo ["", 0]) then {
_secondaryMag params ["_magClass", "_ammoCount"];
if (_magClass != "") then {
private _existing = _locker getOrDefault [_magClass, createHashMap];
private _existingCount = _existing getOrDefault ["amount", 0];
_locker set [_magClass, createHashMapFromArray [
["amount", _existingCount + 1],
["classname", _magClass],
["category", "magazine"]
]];
};
};
} forEach _weaponItems;
_locker
}],
["save", {
private _uid = _self get "uid";
@ -45,25 +183,109 @@ GVAR(LockerClass) = createHashMapObject [[
_self set ["lastSave", time];
}],
["setEventHandlers", {
params [["_locker", objNull, [objNull]]];
_locker addEventHandler ["ContainerOpened", {
params ["_container", "_unit"];
private _index = GVAR(LockerClass) get "locker";
clearBackpackCargo _container;
clearItemCargo _container;
clearMagazineCargo _container;
clearWeaponCargo _container;
{
private _amount = _y get "amount";
private _category = _y get "category";
private _className = _y get "classname";
switch (_category) do {
case "backpack": { _container addBackpackCargo [_className, _amount]; };
case "item": { _container addItemCargo [_className, _amount]; };
case "magazine": { _container addMagazineCargo [_className, _amount]; };
case "weapon": { _container addWeaponCargo [_className, _amount]; };
default { _container addItemCargo [_className, _amount]; };
};
} forEach _index;
}];
_locker addEventHandler ["ContainerClosed", {
params ["_container", "_unit"];
private _newLocker = createHashMap;
_newLocker = GVAR(LockerClass) call ["getCargo", [_container, _newLocker]];
_newLocker = GVAR(LockerClass) call ["getContainerItems", [_container, _newLocker]];
_newLocker = GVAR(LockerClass) call ["getAttachments", [_container, _newLocker]];
private _uid = getPlayerUID _unit;
[SRPC(locker,requestOverrideLocker), [_uid, _newLocker]] call CFUNC(serverEvent);
GVAR(LockerClass) set ["locker", _newLocker];
}];
}],
["setup", {
private _lockers = (allVariables missionNamespace) select {
private _var = missionNamespace getVariable _x;
("locker" in _x) && { _var isEqualType objNull } && { !isNull _var } && { _x isNotEqualTo "forge_locker_box" }
};
if (_lockers isEqualTo []) exitWith { diag_log "[FORGE:Client:Locker] No lockers found in missionNamespace."; };
{
private _globalLocker = missionNamespace getVariable _x;
private _pos = getPosASL _globalLocker;
private _vDir = vectorDir _globalLocker;
private _vUp = vectorUp _globalLocker;
private _localLocker = createVehicleLocal ["Box_NATO_Equip_F", [0, 0, 0]];
_localLocker setPosASL _pos;
_localLocker setVectorDirAndUp [_vDir, _vUp];
_localLocker allowDamage false;
_localLocker setVariable ["isLocker", true];
clearBackpackCargo _localLocker;
clearItemCargo _localLocker;
clearMagazineCargo _localLocker;
clearWeaponCargo _localLocker;
private _localVarName = format ["FORGE_Locker_Local_%1", _forEachIndex];
_localLocker setVehicleVarName _localVarName;
missionNamespace setVariable [_localVarName, _localLocker];
_self call ["setEventHandlers", [_localLocker]];
} forEach _lockers;
}],
["sync", {
params [["_data", createHashMap, [createHashMap]]];
private _locker = _self get "locker";
private _isLoaded = _self get "isLoaded";
private _locker = _self get "locker";
if (_data isEqualTo createHashMap) exitWith { diag_log "[FORGE:Client:Locker] Empty data received for sync, skipping."; };
{ _locker set [_x, _y]; } forEach _data;
_self set ["locker", _locker];
if !(_isLoaded) then { _self set ["isLoaded", true]; };
if !(_isLoaded) then { _self set ["isLoaded", true]; _self call ["setup", []]; };
diag_log "[FORGE:Client:Locker] Sync completed";
}],
["get", {
params [["_key", "", [""]], ["_default", nil, [[], "", 0, false, createHashMap]]];
}]
];
private _locker = _self get "locker";
_locker getOrDefault [_key, _default];
GVAR(LockerClass) = createHashMapObject [[
["#base", GVAR(LockerRepository)],
["#type", "ILockerClass"],
["#create", {
_self set ["uid", (getPlayerUID player)];
_self set ["isLoaded", false];
_self set ["lastSave", time];
_self set ["locker", createHashMap];
}],
["init", {
private _uid = _self get "uid";
[SRPC(locker,requestInitLocker), [_uid]] call CFUNC(serverEvent);
systemChat format ["Locker loaded for %1", (name player)];
diag_log "[FORGE:Client:Locker] Locker Class Initialized!";
}]
]];

View File

@ -4,7 +4,7 @@
* File: fnc_initVAClass.sqf
* Author: IDSolutions
* Date: 2025-12-16
* Last Update: 2026-01-28
* Last Update: 2026-01-30
* Public: No
*
* Description:
@ -18,7 +18,7 @@
* vArsenal class object [HASHMAP OBJECT]
*
* Example:
* [] call forge_client_locker_fnc_initVAClass;
* call forge_client_locker_fnc_initVAClass;
*/
#pragma hemtt ignore_variables ["_self"]
@ -32,9 +32,8 @@ GVAR(VArsenalClass) = createHashMapObject [[
}],
["init", {
private _uid = _self get "uid";
private _vArsenal = _self get "vArsenal";
[SRPC(locker,requestInitVA), [_uid, _vArsenal]] call CFUNC(serverEvent);
[SRPC(locker,requestInitVA), [_uid]] call CFUNC(serverEvent);
FORGE_Locker_Box = "ReammoBox_F" createVehicleLocal [0, 0, -999];
systemChat format ["VArsenal loaded for %1", (name player)];

View File

@ -1,21 +0,0 @@
#include "..\script_component.hpp"
/*
* File: fnc_openUI.sqf
* Author: IDSolutions
* Date: 2026-01-28
* Last Update: 2026-01-28
* Public: No
*
* Description:
* Opens the player locker interaction interface.
*
* Arguments:
* None
*
* Return Value:
* UI opened [BOOL]
*
* Example:
* [] call forge_client_locker_fnc_openUI;
*/

View File

@ -4,8 +4,8 @@
EGVAR(actor,ActorClass) get "isLoaded";
}, {
("NotificationHudLayer" call BFUNC(rscLayer)) cutRsc ["RscNotifications", "PLAIN"];
[] call FUNC(openUI);
if (isNil QGVAR(NotificationClass)) then { [] call FUNC(initNotificationClass); };
call FUNC(openUI);
if (isNil QGVAR(NotificationClass)) then { call FUNC(initNotificationClass); };
}] call CFUNC(waitUntilAndExecute);
[QGVAR(recieveNotification), {

View File

@ -4,7 +4,7 @@
* File: fnc_handleUIEvents.sqf
* Author: IDSolutions
* Date: 2026-01-28
* Last Update: 2026-01-28
* Last Update: 2026-01-30
* Public: No
*
* Description:
@ -19,7 +19,7 @@
* UI events handled [BOOL]
*
* Example:
* [] call forge_client_notifications_fnc_handleUIEvents;
* call forge_client_notifications_fnc_handleUIEvents;
*/
params ["_control", "_isConfirmDialog", "_message"];

View File

@ -4,7 +4,7 @@
* File: fnc_initNotificationClass.sqf
* Author: IDSolutions
* Date: 2026-01-28
* Last Update: 2026-01-28
* Last Update: 2026-01-30
* Public: No
*
* Description:
@ -18,7 +18,7 @@
* Notification class object [HASHMAP OBJECT]
*
* Example:
* [] call forge_client_notifications_fnc_initNotificationClass
* call forge_client_notifications_fnc_initNotificationClass
*/
#pragma hemtt ignore_variables ["_self"]

View File

@ -4,7 +4,7 @@
* File: fnc_openUI.sqf
* Author: IDSolutions
* Date: 2026-01-28
* Last Update: 2026-01-28
* Last Update: 2026-01-30
* Public: No
*
* Description:
@ -17,7 +17,7 @@
* UI opened [BOOL]
*
* Example:
* [] call forge_client_notifications_fnc_openUI;
* call forge_client_notifications_fnc_openUI;
*/
private _display = uiNamespace getVariable ["RscNotifications", nil];

View File

@ -1,6 +1,6 @@
#include "script_component.hpp"
if (isNil QGVAR(OrgClass)) then { [] call FUNC(initOrgClass); };
if (isNil QGVAR(OrgClass)) then { call FUNC(initOrgClass); };
[QGVAR(initOrg), {
GVAR(OrgClass) call ["init", []];

View File

@ -11,7 +11,7 @@
* None
*
* Example:
* [] call forge_client_org_fnc_handleUIEvents;
* call forge_client_org_fnc_handleUIEvents;
*
* Public: No
*/

View File

@ -11,7 +11,7 @@
* None
*
* Examples:
* [] call forge_client_org_fnc_initOrgClass
* call forge_client_org_fnc_initOrgClass
*
* Public: Yes
*/

View File

@ -11,13 +11,13 @@
* None
*
* Example:
* [] call forge_client_org_fnc_openUI;
* call forge_client_org_fnc_openUI;
*
* Public: No
*/
private _display = (findDisplay 46) createDisplay "RscOrg";
private _ctrl = (_display displayCtrl 1003);
private _display = createDialog ["RscOrg", true];
private _ctrl = _display displayCtrl 1003;
_ctrl ctrlAddEventHandler ["JSDialog", {
params ["_control", "_isConfirmDialog", "_message"];

View File

@ -10,7 +10,7 @@
* None
*
* Example:
* [] call forge_client_addonName_fnc_empty;
* call forge_client_addonName_fnc_empty;
*
* Public: No
*/

View File

@ -4,7 +4,7 @@
* File: fnc_initActorStore.sqf
* Author: IDSolutions
* Date: 2025-12-17
* Last Update: 2026-01-28
* Last Update: 2026-01-30
* Public: Yes
*
* Description:
@ -18,7 +18,7 @@
* Actor store object [HASHMAP OBJECT]
*
* Example:
* [] call forge_server_actor_fnc_initActorStore
* call forge_server_actor_fnc_initActorStore
*/
#pragma hemtt ignore_variables ["_self"]

View File

@ -4,7 +4,7 @@
* File: fnc_initBankStore.sqf
* Author: IDSolutions
* Date: 2025-12-17
* Last Update: 2026-01-28
* Last Update: 2026-01-30
* Public: Yes
*
* Description:
@ -18,7 +18,7 @@
* Bank store object [HASHMAP OBJECT]
*
* Example:
* [] call forge_server_bank_fnc_initBankStore
* call forge_server_bank_fnc_initBankStore
*/
#pragma hemtt ignore_variables ["_self"]

View File

@ -4,7 +4,7 @@
* File: fnc_baseStore.sqf
* Author: IDSolutions
* Date: 2026-01-08
* Last Update: 2026-01-28
* Last Update: 2026-01-30
* Public: No
*
* Description:
@ -17,7 +17,7 @@
* Base store [HASHMAP]
*
* Example:
* [] call forge_x_component_fnc_myFunction
* call forge_x_component_fnc_myFunction
*/
#pragma hemtt ignore_variables ["_self"]

View File

@ -6,9 +6,9 @@ PREP_RECOMPILE_END;
// private _category = [QUOTE(MOD_NAME), LLSTRING(displayName)];
if (isNil QGVAR(MEconomyStore)) then { [] call FUNC(initMEconomyStore); };
if (isNil QGVAR(FEconomyStore)) then { [] call FUNC(initFEconomyStore); };
// if (isNil QGVAR(SEconomyStore)) then { [] call FUNC(initSEconomyStore); };
if (isNil QGVAR(MEconomyStore)) then { call FUNC(initMEconomyStore); };
if (isNil QGVAR(FEconomyStore)) then { call FUNC(initFEconomyStore); };
// if (isNil QGVAR(SEconomyStore)) then { call FUNC(initSEconomyStore); };
[QGVAR(FuelStart), {
params ["_source", "_target", "_unit"];

View File

@ -1,3 +1,2 @@
#include "script_component.hpp"
#include "XEH_PREP.hpp"

View File

@ -1,3 +1,3 @@
#include "script_component.hpp"
[] call FUNC(initGarage);
call FUNC(initGarage);

View File

@ -7,10 +7,10 @@ PREP_RECOMPILE_END;
// private _category = [QUOTE(MOD_NAME), LLSTRING(displayName)];
[QGVAR(requestInitGarage), {
params [["_uid", "", [""]], ["_garage", createHashMap, [createHashMap]]];
params [["_uid", "", [""]]];
if (_uid isEqualTo "") exitWith { diag_log "[FORGE:Server:Garage] Empty/Invalid UID!" };
GVAR(GarageStore) call ["init", [_uid, _garage]];
GVAR(GarageStore) call ["init", [_uid]];
}] call CFUNC(addEventHandler);
[QGVAR(requestGetGarage), {
@ -62,12 +62,10 @@ PREP_RECOMPILE_END;
}] call CFUNC(addEventHandler);
[QGVAR(requestInitVG), {
params [["_uid", "", [""]], ["_vGarage", createHashMap, [createHashMap]]];
params [["_uid", "", [""]]];
if (_uid isEqualTo "") exitWith { diag_log "[FORGE:Server:VGarage] Empty/Invalid UID!" };
if (_vGarage isEqualTo createHashMap) exitWith { diag_log "[FORGE:Server:VGarage] Empty/Invalid VGarage data!" };
GVAR(VGarageStore) call ["init", [_uid, _vGarage]];
GVAR(VGarageStore) call ["init", [_uid]];
}] call CFUNC(addEventHandler);
[QGVAR(requestGetVG), {

View File

@ -4,7 +4,7 @@
* File: fnc_initGarage.sqf
* Author: IDSolutions
* Date: 2025-12-17
* Last Update: 2026-01-28
* Last Update: 2026-01-30
* Public: No
*
* Description:
@ -17,7 +17,7 @@
* None
*
* Example:
* [] call forge_server_garage_fnc_initGarage
* call forge_server_garage_fnc_initGarage
*/
// TODO: Refactor to read from placed objects and their variables instead of missionConfig entries.

View File

@ -4,7 +4,7 @@
* File: fnc_initGarageStore.sqf
* Author: IDSolutions
* Date: 2025-12-17
* Last Update: 2026-01-28
* Last Update: 2026-01-30
* Public: No
*
* Description:
@ -18,7 +18,7 @@
* Garage store object [HASHMAP OBJECT]
*
* Example:
* [] call forge_server_garage_fnc_initGarageStore
* call forge_server_garage_fnc_initGarageStore
*/
#pragma hemtt ignore_variables ["_self"]

View File

@ -4,7 +4,7 @@
* File: fnc_initVGStore.sqf
* Author: IDSolutions
* Date: 2025-12-17
* Last Update: 2026-01-28
* Last Update: 2026-01-30
* Public: No
*
* Description:
@ -18,7 +18,7 @@
* VG store object [HASHMAP OBJECT]
*
* Example:
* [] call forge_server_garage_fnc_initVGStore
* call forge_server_garage_fnc_initVGStore
*/
#pragma hemtt ignore_variables ["_self"]

View File

@ -1,3 +1,3 @@
#include "script_component.hpp"
[] call FUNC(initLocker);
call FUNC(initLocker);

View File

@ -7,10 +7,10 @@ PREP_RECOMPILE_END;
// private _category = [QUOTE(MOD_NAME), LLSTRING(displayName)];
[QGVAR(requestInitLocker), {
params [["_uid", "", [""]], ["_locker", createHashMap, [createHashMap]]];
params [["_uid", "", [""]]];
if (_uid isEqualTo "") exitWith { diag_log "[FORGE:Server:Locker] Empty/Invalid UID!" };
GVAR(LockerStore) call ["init", [_uid, _locker]];
GVAR(LockerStore) call ["init", [_uid]];
}] call CFUNC(addEventHandler);
[QGVAR(requestGetLocker), {
@ -54,6 +54,16 @@ PREP_RECOMPILE_END;
[CRPC(locker,responseSyncLocker), [_finalData], _player] call CFUNC(targetEvent);
}] call CFUNC(addEventHandler);
[QGVAR(requestOverrideLocker), {
params [["_uid", "", [""]], ["_data", createHashMap, [createHashMap]]];
if (_uid isEqualTo "") exitWith { diag_log "[FORGE:Server:Locker] Empty/Invalid UID!" };
GVAR(LockerRegistry) set [_uid, _data];
private _player = [_uid] call EFUNC(common,getPlayer);
[CRPC(locker,responseSyncLocker), [_data], _player] call CFUNC(targetEvent);
}] call CFUNC(addEventHandler);
[QGVAR(requestRemoveLocker), {
params [["_uid", "", [""]]];
@ -62,22 +72,16 @@ PREP_RECOMPILE_END;
}] call CFUNC(addEventHandler);
[QGVAR(requestInitVA), {
params [["_uid", "", [""]], ["_vArsenal", createHashMap, [createHashMap]]];
params [["_uid", "", [""]]];
if (_uid isEqualTo "") exitWith { diag_log "[FORGE:Server:VArsenal] Empty/Invalid UID!" };
if (_vArsenal isEqualTo createHashMap) exitWith { diag_log "[FORGE:Server:VArsenal] Empty/Invalid VArsenal data!" };
GVAR(VArsenalStore) call ["init", [_uid, _vArsenal]];
GVAR(VArsenalStore) call ["init", [_uid]];
}] call CFUNC(addEventHandler);
[QGVAR(requestGetVA), {
params [["_uid", "", [""]]];
if (_uid isEqualTo "") exitWith { diag_log "[FORGE:Server:VArsenal] Empty/Invalid UID!" };
private _session = EGVAR(actor,PlayerSessions) getOrDefault [_uid, nil];
if (isNil "_session") exitWith { diag_log "[FORGE:Server:VArsenal] Empty/Invalid Session!" };
GVAR(VArsenalStore) call ["get", [GVAR(VArsenalRegistry), "owned:locker:fetch", _uid]];
}] call CFUNC(addEventHandler);
@ -86,9 +90,6 @@ PREP_RECOMPILE_END;
if (_uid isEqualTo "" || _key isEqualTo "") exitWith { diag_log "[FORGE:Server:VArsenal] Empty/Invalid UID or Key!" };
private _session = EGVAR(actor,PlayerSessions) getOrDefault [_uid, nil];
if (isNil "_session") exitWith { diag_log "[FORGE:Server:VArsenal] Empty/Invalid Session!" };
private _hashMap = GVAR(VArsenalStore) call ["set", [GVAR(VArsenalRegistry), "owned:locker:update", _uid, _key, _value, _sync]];
private _player = [_uid] call EFUNC(common,getPlayer);
@ -101,9 +102,6 @@ PREP_RECOMPILE_END;
if (_uid isEqualTo "") exitWith { diag_log "[FORGE:Server:VArsenal] Empty/Invalid UID!" };
if ((_fieldValuePairs isEqualTo createHashMap) || !(_fieldValuePairs isEqualType createHashMap)) exitWith { diag_log "[FORGE:Server:VArsenal] Empty/Invalid field pairs!" };
private _session = EGVAR(actor,PlayerSessions) getOrDefault [_uid, nil];
if (isNil "_session") exitWith { diag_log "[FORGE:Server:VArsenal] Empty/Invalid Session!" };
private _hashMap = GVAR(VArsenalStore) call ["mset", [GVAR(VArsenalRegistry), "owned:locker:update", _uid, _fieldValuePairs, _sync]];
private _player = [_uid] call EFUNC(common,getPlayer);
@ -115,9 +113,6 @@ PREP_RECOMPILE_END;
if (_uid isEqualTo "") exitWith { diag_log "[FORGE:Server:VArsenal] Empty/Invalid UID!" };
private _session = EGVAR(actor,PlayerSessions) getOrDefault [_uid, nil];
if (isNil "_session") exitWith { diag_log "[FORGE:Server:VArsenal] Empty/Invalid Session!" };
private _finalData = GVAR(VArsenalStore) call ["save", [GVAR(VArsenalRegistry), "owned:locker:update", _uid]];
private _player = [_uid] call EFUNC(common,getPlayer);

View File

@ -4,11 +4,12 @@
* File: fnc_initLocker.sqf
* Author: IDSolutions
* Date: 2025-12-17
* Last Update: 2026-01-28
* Last Update: 2026-01-30
* Public: No
*
* Description:
* Initializes all lockers defined in the mission configuration.
* Initializes lockers by hiding editor-placed global locker objects.
* Each client will create their own local instance.
*
* Arguments:
* None
@ -17,69 +18,20 @@
* None
*
* Example:
* [] call forge_server_locker_fnc_initLocker
* call forge_server_locker_fnc_initLocker
*/
// TODO: Refactor to read from placed objects and their variables instead of missionConfig entries.
private _lockers = (allVariables missionNamespace) select {
private _var = missionNamespace getVariable _x;
("locker" in _x) && { _var isEqualType objNull } && { !isNull _var } && { _x isNotEqualTo "forge_locker_box" }
};
private _mC = "FORGE_CfgLockers";
private _lockers = "true" configClasses (missionConfigFile >> "FORGE_CfgLockers" >> "lockers");
if (_lockers isEqualTo []) exitWith { diag_log "[FORGE:Server:Locker] No editor-placed lockers found."; };
diag_log format ["[FORGE:Server:Locker] Found %1 editor-placed locker(s), hiding globally", count _lockers];
{
private _configName = configName(_x);
private _className = (missionConfigFile >> _mC >> "lockers" >> _configName >> "className") call BFUNC(getCfgData);
private _pos = (missionConfigFile >> _mC >> "lockers" >> _configName >> "pos") call BFUNC(getCfgData);
private _dir = (missionConfigFile >> _mC >> "lockers" >> _configName >> "dir") call BFUNC(getCfgData);
private _locker = missionNamespace getVariable _x;
_locker hideObjectGlobal true;
private _locker = createVehicle [_className, [0, 0, 0]];
// private _prefix = "FORGE_Locker";
// private _varName = format ["%1_%2", _prefix, _forEachIndex];
_locker setPosATL _pos;
_locker setDir _dir;
_locker allowDamage false;
_locker setVariable ["isLocker", true, true];
clearBackpackCargoGlobal _locker;
clearItemCargoGlobal _locker;
clearMagazineCargoGlobal _locker;
clearWeaponCargoGlobal _locker;
// private _pLocker = vehicle _locker;
// _pLocker setVehicleVarName _varName;
// missionNamespace setVariable [_varName, _pLocker, true];
// _locker addEventHandler ["ContainerOpened", {
// params ["_container", "_unit"];
// private _uid = getPlayerUID _unit;
// private _pLocker = GVAR(LockerRegistry) get _uid;
// diag_log text format ["[FORGE] (locker) INFO: Container opened, refreshing inventory: %1 w/ %2", _container, _pLocker];
// // Clear existing cargo
// clearBackpackCargo _container;
// clearItemCargo _container;
// clearMagazineCargo _container;
// clearWeaponCargo _container;
// // Repopulate with current locker items
// {
// private _amount = _y get "amount";
// private _category = _y get "category";
// private _className = _y get "classname";
// switch (_category) do {
// case "backpack": { _container addBackpackCargo [_className, _amount]; };
// case "item": { _container addItemCargo [_className, _amount]; };
// case "magazine": { _container addMagazineCargo [_className, _amount]; };
// case "weapon": { _container addWeaponCargo [_className, _amount]; };
// default { _container addItemCargo [_className, _amount]; };
// };
// } forEach _pLocker;
// diag_log text format ["[FORGE] (locker) INFO: Inventory refreshed"];
// }];
diag_log format ["[FORGE:Server:Locker] ClassName: %1 Pos: %2 Dir: %3", _className, _pos, _dir];
diag_log format ["[FORGE:Server:Locker] Hidden locker: %1 at position %2", _x, getPosASL _locker];
} forEach _lockers;

View File

@ -4,7 +4,7 @@
* File: fnc_initLockerStore.sqf
* Author: IDSolutions
* Date: 2025-12-17
* Last Update: 2026-01-28
* Last Update: 2026-01-30
* Public: No
*
* Description:
@ -18,7 +18,7 @@
* Locker store object [HASHMAP OBJECT]
*
* Example:
* [] call forge_server_locker_fnc_initLockerStore
* call forge_server_locker_fnc_initLockerStore
*/
#pragma hemtt ignore_variables ["_self"]

View File

@ -4,7 +4,7 @@
* File: fnc_initVAStore.sqf
* Author: IDSolutions
* Date: 2025-12-17
* Last Update: 2026-01-28
* Last Update: 2026-01-30
* Public: No
*
* Description:
@ -18,7 +18,7 @@
* VA store object [HASHMAP OBJECT]
*
* Example:
* [] call forge_server_locker_fnc_initVAStore
* call forge_server_locker_fnc_initVAStore
*/
#pragma hemtt ignore_variables ["_self"]

View File

@ -1,3 +1,3 @@
#include "script_component.hpp"
[] call FUNC(initStores);
call FUNC(initStores);

View File

@ -11,31 +11,31 @@
* None
*
* Example:
* [] call forge_server_main_fnc_initStores;
* call forge_server_main_fnc_initStores;
*
* Public: No
*/
// Base
if (isNil QEGVAR(common,BaseStore)) then { [] call EFUNC(common,baseStore); };
if (isNil QEGVAR(common,BaseStore)) then { call EFUNC(common,baseStore); };
// Actor
if (isNil QEGVAR(actor,ActorStore)) then { [] call EFUNC(actor,initActorStore); };
if (isNil QEGVAR(actor,ActorStore)) then { call EFUNC(actor,initActorStore); };
// Bank
if (isNil QEGVAR(bank,BankStore)) then { [] call EFUNC(bank,initBankStore); };
if (isNil QEGVAR(bank,BankStore)) then { call EFUNC(bank,initBankStore); };
// Garage
if (isNil QEGVAR(garage,GarageStore)) then { [] call EFUNC(garage,initGarageStore); };
if (isNil QEGVAR(garage,GarageStore)) then { call EFUNC(garage,initGarageStore); };
// VGarage
if (isNil QEGVAR(garage,VGarageStore)) then { [] call EFUNC(garage,initVGStore); };
if (isNil QEGVAR(garage,VGarageStore)) then { call EFUNC(garage,initVGStore); };
// Locker
if (isNil QEGVAR(locker,LockerStore)) then { [] call EFUNC(locker,initLockerStore); };
if (isNil QEGVAR(locker,LockerStore)) then { call EFUNC(locker,initLockerStore); };
// VArsenal
if (isNil QEGVAR(locker,VArsenalStore)) then { [] call EFUNC(locker,initVAStore); };
if (isNil QEGVAR(locker,VArsenalStore)) then { call EFUNC(locker,initVAStore); };
// Org
if (isNil QEGVAR(org,OrgStore)) then { [] call EFUNC(org,initOrgStore); };
if (isNil QEGVAR(org,OrgStore)) then { call EFUNC(org,initOrgStore); };

View File

@ -11,7 +11,7 @@
* None
*
* Examples:
* [] call forge_server_org_fnc_initOrgStore
* call forge_server_org_fnc_initOrgStore
*
* Public: Yes
*/
@ -63,9 +63,9 @@ GVAR(OrgStore) = createHashMapObject [[
// _finalOrg set ["assets", _assets];
GVAR(OrgRegistry) set [_orgID, _finalOrg, true];
[CRPC(org,responseInitOrg), [_finalOrg], _player] call CFUNC(targetEvent);
["INFO", format ["Found org for %1", _uid], nil, nil] call EFUNC(common,log);
_finalOrg
}],
["default", {

View File

@ -23,6 +23,10 @@ pub struct VGarage {
impl VGarage {
pub fn new() -> Self {
Self::default_unlocks()
}
fn default_unlocks() -> Self {
Self {
cars: vec!["B_Quadbike_01_F".to_string()],
armor: Vec::new(),

View File

@ -19,6 +19,10 @@ pub struct VLocker {
impl VLocker {
pub fn new() -> Self {
Self::default_unlocks()
}
fn default_unlocks() -> Self {
Self {
items: vec![
"FirstAidKit".to_string(),