Refactor: Organization Funds, Reputation, Tasks, and Player Saving
All checks were successful
Build / Build (push) Successful in 26s

This commit refactors how organization funds and reputation are handled, updates task completion logic to use the new organization functions, and modifies player saving to include organization data. Additionally, it introduces string serialization/deserialization and fixes a player save loop.

*   **Organization Funds and Reputation:** Replaces direct server calls for handling funds and reputation with calls to the new organization functions (`EFUNC(org,addFunds)` and `EFUNC(org,addReputation)`). This centralizes fund and reputation management within the organization store.
*   **Task Completion Logic:** Updates task completion functions (`fnc_destroy.sqf`, `fnc_attack.sqf`, `fnc_hostage.sqf`, `fnc_hvt.sqf`, `fnc_defuse.sqf`) to use the new organization functions for adding funds and reputation upon task success or failure. Also adds notifications to inform the player of reputation and fund changes.
*   **Player Saving:** Modifies the player saving function (`fnc_playerDBSave.sqf`) to include the player's organization ID in the saved data.
*   **String Serialization/Deserialization:** Adds `serializeString` and `deserializeString` PREP macros to `XEH_PREP.hpp` and uses them in `fnc_handleOrgLoad.sqf` and `fnc_create.sqf` to handle special characters in organization and member names.
*   **Player Save Loop Fix:** Removes unnecessary brackets from the `call FUNC(playerDBSave)` in `fnc_playerSaveLoop.sqf`.
*   **Organization Purchase Verification:** Adds organization ownership verification to `fnc_handlePurchase.sqf` to ensure only the owner can make purchases using organization funds.
*   **Player Initialization:** Updates `fnc_initPlayer.sqf` to retrieve and set the player's organization upon initialization.
This commit is contained in:
Jacob Schmidt 2025-04-05 14:16:24 -05:00
parent f209a86fe7
commit c87deec60b
41 changed files with 903 additions and 22100 deletions

View File

@ -48,70 +48,58 @@ if (_data isEqualTo [""]) then {
switch (_key) do {
case "reputation": {
// player setVariable ["Reputation", _value, true];
SETPVAR(player,Reputation,_value);
player addRating _value;
};
case "loadout": {
// player setVariable ["Loadout", _value, true];
SETPVAR(player,Loadout,_value);
player setUnitLoadout _value;
};
case "direction": {
// player setVariable ["Direction", _value, true];
SETPVAR(player,Direction,_value);
player setDir _value;
};
case "cash": {
// player setVariable ["FORGE_Cash", _value, true];
SETPVAR(player,FORGE_Cash,_value);
};
case "bank": {
// player setVariable ["FORGE_Bank", _value, true];
SETPVAR(player,FORGE_Bank,_value);
};
case "armory_unlocks": {
// player setVariable ["Armory_Unlocks", _value, true];
SETPVAR(player,Armory_Unlocks,_value);
};
case "garage_unlocks": {
// player setVariable ["Garage_Unlocks", _value, true];
SETPVAR(player,Garage_Unlocks,_value);
};
case "locker": {
// player setVariable ["FORGE_Locker", _value, true];
SETPVAR(player,FORGE_Locker,_value);
};
case "garage": {
// player setVariable ["FORGE_Garage", _value, true];
SETPVAR(player,FORGE_Garage,_value);
};
case "email": {
// player setVariable ["FORGE_Email", _value, true];
SETPVAR(player,FORGE_Email,_value);
};
case "number": {
// player setVariable ["FORGE_Phone_Number", _value, true];
SETPVAR(player,FORGE_Phone_Number,_value);
};
case "paygrade": {
// player setVariable ["Paygrade", _value, true];
SETPVAR(player,Paygrade,_value);
};
case "organization": {
SETPVAR(player,FORGE_Organization,_value);
};
case "stance": {
// player setVariable ["Stance", _value, true];
SETPVAR(player,Stance,_value);
player playAction _value;
};
case "holster": {
// player setVariable ["FORGE_Holster_Weapon", _value, true];
SETPVAR(player,FORGE_Holster_Weapon,_value);
if (_value) then {
[player] call AFUNC(weaponselect,putWeaponAway);
};
};
case "position": {
// player setVariable ["Position", _value, true];
SETPVAR(player,Position,_value);
player setPosASL _value;
@ -127,7 +115,6 @@ if (_data isEqualTo [""]) then {
};
if (needReload player == 1) then { reload player };
// player setVariable ["value_loadDone", true, true];
SETPVAR(player,value_loadDone,true);
// ["listrng", GETVAR(player,FORGE_Email,_defaultEmail), "", -1, [], "forge_client_phone_fnc_addOfflineEmail", true] spawn dragonfly_db_fnc_addTask;

View File

@ -40,20 +40,15 @@ removeBackpack player;
removeGoggles player;
removeHeadgear player;
// player setVariable ["value_loadDone", false, true];
SETPVAR(player,value_loadDone,false);
cutText ["Loading In...", "BLACK", 1];
// waitUntil { player getVariable ["value_armoryDone", false] };
// waitUntil { GETVAR(player,value_armoryDone,false) };
// ["hgetall", "", "", -1, [], "forge_client_init_fnc_handlePlayerLoad", true] spawn dragonfly_db_fnc_addTask;
["hgetallid", getPlayerUID player, "", -1, [], "forge_client_init_fnc_handlePlayerLoad", true, netId player] remoteExec ["dragonfly_db_fnc_addTask", 2, false];
[] spawn FUNC(playerSaveLoop);
[] spawn EFUNC(interaction,initInteraction);
// waitUntil { player getVariable ["value_loadDone", false] };
waitUntil { GETVAR(player,value_loadDone,false) };
cutText ["", "PLAIN", 1];

View File

@ -33,27 +33,18 @@ private _default_garage_unlocks = [[],[],[],[],[],[]];
private _data = [
getPlayerUID player,
// "armory_unlocks", [player getVariable ["Armory_Unlocks", [[],[],[],[]]]],
// "garage_unlocks", [player getVariable ["Garage_Unlocks", [[],[],[],[],[],[]]]],
"armory_unlocks", [GETVAR(player,Armory_Unlocks,_default_armory_unlocks)],
"garage_unlocks", [GETVAR(player,Garage_Unlocks,_default_garage_unlocks)],
// "locker", [player getVariable ["FORGE_Locker", []]],
// "garage", [player getVariable ["FORGE_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,Paygrade,"E1")],
"organization", [GETVAR(player,FORGE_Organization,"")],
"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]

View File

@ -35,5 +35,5 @@ while { true } do {
sleep ((configFile >> "CfgPatches" >> "forge_client_main" >> "clientSaveLoopTime") call BFUNC(getCfgData));
["Saving player...", "blue-grey", 3] call EFUNC(misc,notify);
[] call FUNC(playerDBSave);
call FUNC(playerDBSave);
};

View File

@ -1,7 +1,9 @@
PREP(cargoToPairs);
PREP(deserializeString);
PREP(formatNumber);
PREP(getSystemTime);
PREP(isAssignableBinocular);
PREP(isWeaponType);
PREP(notify);
PREP(serializeString);
PREP(test);

View File

@ -0,0 +1,19 @@
#include "..\script_component.hpp"
/*
* Function: dragonfly_misc_fnc_deserializeString
* Description:
* Converts underscores in a string to spaces for display
*
* Parameters:
* 0: _string - String to convert <STRING>
*
* Returns:
* Converted string <STRING>
*/
params [["_string", "", [""]]];
if (_string isEqualTo "") exitWith { ERROR_MSG("String is empty"); "" };
(_string splitString "_") joinString " "

View File

@ -0,0 +1,19 @@
#include "..\script_component.hpp"
/*
* Function: dragonfly_misc_fnc_serializeString
* Description:
* Converts spaces in a string to underscores for database storage
*
* Parameters:
* 0: _string - String to convert <STRING>
*
* Returns:
* Converted string <STRING>
*/
params [["_string", "", [""]]];
if (_string isEqualTo "") exitWith { ERROR_MSG("String is empty"); "" };
(_string splitString " ") joinString "_"

126
addons/org/Readme.md Normal file
View File

@ -0,0 +1,126 @@
# Player Organization Module
## Overview
The Player Organization Module provides a comprehensive system for managing player-created organizations in Arma 3. This module enables players to create, join, and manage organizations with features including member management, asset tracking, financial operations, and reputation systems.
## Features
- **Organization Creation & Management**: Create and disband organizations with customizable names
- **Member Management**: Add, remove, and manage organization members with different roles
- **Asset Tracking**: Register and manage organization-owned assets (vehicles, buildings, etc.)
- **Financial System**: Track organization funds with deposit and withdrawal capabilities
- **Reputation System**: Manage organization reputation that can influence gameplay mechanics
- **Database Integration**: Persistent storage using ArmaDragonflyClient for reliable data management
- **User-Friendly Notifications**: Visual feedback for all organization operations
## Usage
### Creating an Organization
```sqf
// Create a new organization with default funds and reputation
[getPlayerUID player, "My Organization"] call forge_client_org_fnc_create;
// Create an organization with custom initial funds and reputation
[getPlayerUID player, "Elite Squad", 5000, 100] call forge_client_org_fnc_create;
```
### Managing Members
```sqf
// Add a member to your organization
["76561198012345678", "John Doe"] call forge_client_org_fnc_addMember;
// Remove a member from your organization
["76561198012345678"] call forge_client_org_fnc_removeMember;
// Leave an organization (for members)
[] call forge_client_org_fnc_leave;
```
### Managing Assets
```sqf
// Add a vehicle to organization assets
["vehicle", "B_MRAP_01_F"] call forge_client_org_fnc_addAsset;
// Add a vehicle with custom properties
private _properties = createHashMap;
_properties set ["color", "red"];
_properties set ["plate", "ORG-001"];
["vehicle", "B_MRAP_01_F", _properties] call forge_client_org_fnc_addAsset;
// Remove an asset from the organization
["vehicle", "B_MRAP_01_F_1234567890"] call forge_client_org_fnc_removeAsset;
```
### Financial Operations
```sqf
// Add funds to organization account
[1000] call forge_client_org_fnc_addFunds;
// Remove funds from organization account
[-500] call forge_client_org_fnc_addFunds;
```
### Reputation Management
```sqf
// Increase organization reputation
[10] call forge_client_org_fnc_addReputation;
// Decrease organization reputation
[-5] call forge_client_org_fnc_addReputation;
```
### Disbanding an Organization
```sqf
// Permanently delete the organization (owner only)
[] call forge_client_org_fnc_disband;
```
## Technical Architecture
The module is built around a central organization store interface that provides a clean API for all organization operations. This interface handles data validation, database persistence, and user feedback.
### Core Components
- **Organization Store**: Central interface for all organization operations
- **Database Integration**: Persistent storage using ArmaDragonflyClient
- **User Notifications**: Visual feedback system for all operations
- **Data Validation**: Comprehensive input validation to ensure data integrity
### Data Structure
Organizations are stored as structured hashmaps with the following key components:
- **Basic Information**: ID, name, owner, creation date
- **Members**: List of members with roles and join dates
- **Assets**: Categorized inventory of organization-owned assets
- **Finances**: Current funds and transaction history
- **Reputation**: Current reputation score and history
- **Logs**: Comprehensive activity logs for auditing
## Integration with Other Systems
The organization module is designed to integrate with other game systems:
- **Vehicle Garage**: Register organization-owned vehicles
- **Property System**: Manage organization-owned buildings and territories
- **Mission System**: Organization-specific missions and objectives
- **Economy System**: Organization financial operations and investments
## Developer Notes
- All organization operations are performed through the organization store interface
- The store is initialized automatically when needed via `verifyOrgStore`
- Database operations are asynchronous and use callback functions
- User feedback is provided through the notification system
- Error handling is comprehensive with appropriate user feedback
---
*Developed by J. Schmidt*

View File

@ -1,31 +1,43 @@
#include "..\script_component.hpp"
/*
* Function: forge_client_org_fnc_addAsset
* Author: J. Schmidt
*
* Description:
* Adds an asset to an organization's inventory
* Adds an asset to an organization's inventory.
*
* Arguments:
* 0: _assetType - Type of asset (vehicle, building, etc.) <STRING>
* 1: _className - Class name of the asset <STRING>
* 0: Asset Type <STRING> - Type of asset (vehicle, building, etc.)
* 1: Class Name <STRING> - Class name of the asset
*
* Return Value:
* Success <BOOLEAN>
* Asset ID <STRING> - Unique ID of the added asset, or nil if failed
*
* Example:
* ["vehicle", "B_MRAP_01_F"] call forge_client_org_fnc_addAsset
*
* Public: Yes
*/
params [["_assetType", "", [""]], ["_className", "", [""]]];
if (_assetType == "" || _className == "") exitWith { TRACE_2("Invalid parameters for adding asset",_assetType,_className); nil };
private _store = call FUNC(verifyOrgStore);
private _assetId = _store call ["addAsset", [_assetType, _className]];
if (_assetId != "") then {
TRACE_2("Asset added successfully",_assetType,_className);
} else {
TRACE_2("Failed to add asset",_assetType,_className);
// Validate input parameters
if (_assetType == "" || _className == "") exitWith {
["Invalid parameters for adding asset", "error", 5, "right"] call forge_client_misc_fnc_notify;
nil
};
// Get the organization store interface
private _store = call FUNC(verifyOrgStore);
// Add the asset to the organization's inventory
// This will generate a unique ID and store all asset information
private _assetId = _store call ["addAsset", [_assetType, _className]];
// Provide feedback based on success or failure
if (_assetId != "") then {
[format ["Asset added: %1 (%2)", _className, _assetType], "success", 5, "right"] call forge_client_misc_fnc_notify;
} else {
["Failed to add asset to organization", "error", 5, "right"] call forge_client_misc_fnc_notify;
};
// Return the asset ID for further operations
_assetId

View File

@ -1,28 +1,39 @@
#include "..\script_component.hpp"
/*
* Function: forge_client_org_fnc_addFunds
* Author: J. Schmidt
*
* Description:
* Adds funds to an organization's account
* Adds or removes funds from an organization's account.
* Positive values increase funds, negative values decrease funds.
*
* Arguments:
* 0: _amount - Amount to add (can be negative for withdrawals) <NUMBER>
* 0: Amount <NUMBER> - Amount to add (positive) or withdraw (negative)
*
* Return Value:
* New funds amount <NUMBER>
* Success <BOOLEAN> - True if funds were updated successfully, false otherwise
*
* Example:
* [1000] call forge_client_org_fnc_addFunds // Add 1000 funds
* [-500] call forge_client_org_fnc_addFunds // Remove 500 funds
*
* Public: Yes
*/
params [["_amount", 0, [0]]];
// Get the organization store interface
private _store = call FUNC(verifyOrgStore);
// Update the organization's funds
private _result = _store call ["updateFunds", [_amount]];
// Provide feedback based on success or failure
if (_result) then {
TRACE_1("Funds updated successfully",_amount);
private _actionText = ["removed from", "added to"] select (_amount > 0);
private _absAmount = abs _amount call EFUNC(misc,formatNumber);
[format ["$%1 %2 organization funds", _absAmount, _actionText], "info", 5, "right"] call forge_client_misc_fnc_notify;
} else {
TRACE_1("Failed to update funds",_amount);
["Failed to update organization funds", "error", 5, "right"] call forge_client_misc_fnc_notify;
};
// Return the result for further operations
_result

View File

@ -1,31 +1,44 @@
#include "..\script_component.hpp"
/*
* Function: forge_client_org_fnc_addMember
* Author: J. Schmidt
*
* Description:
* Adds a member to an organization
* Adds a new member to an organization. Only the organization owner can add members.
* The new member will be assigned the default "member" role.
*
* Arguments:
* 0: _uid - Target player UID <STRING>
* 1: _name - Target player name <STRING>
* 0: Player UID <STRING> - Unique identifier of the player to add
* 1: Player Name <STRING> - Display name of the player to add
*
* Return Value:
* Success <BOOL>
* Success <BOOLEAN> - True if member was added successfully, false otherwise
*
* Example:
* ["76561198012345678", "John Doe"] call forge_client_org_fnc_addMember
*
* Public: Yes
*/
params [["_uid", "", [""]], ["_name", "", [""]]];
if (_uid == "" || _name == "") exitWith { TRACE_2("Invalid parameters for organization invitation",_uid,_name); false };
private _store = call FUNC(verifyOrgStore);
private _result = _store call ["addMember", [_uid, _name]];
if (_result) then {
TRACE_2("Member added successfully",_uid,_name);
} else {
TRACE_2("Failed to add member",_uid,_name);
// Validate input parameters
if (_uid == "" || _name == "") exitWith {
["Invalid parameters for organization invitation", "error", 5, "right"] call forge_client_misc_fnc_notify;
false
};
// Get the organization store interface
private _store = call FUNC(verifyOrgStore);
// Add the member to the organization
// This will validate ownership permissions and handle database updates
private _result = _store call ["addMember", [_uid, _name]];
// Provide feedback based on success or failure
if (_result) then {
[format ["%1 added to organization", _name], "success", 5, "right"] call forge_client_misc_fnc_notify;
} else {
["Failed to add member to organization", "error", 5, "right"] call forge_client_misc_fnc_notify;
};
// Return the result for further operations
_result

View File

@ -1,28 +1,40 @@
#include "..\script_component.hpp"
/*
* Function: forge_client_org_fnc_addReputation
* Author: J. Schmidt
*
* Description:
* Adds reputation to an organization
* Adds or removes reputation from an organization.
* Positive values increase reputation, negative values decrease reputation.
*
* Arguments:
* 0: _amount - Amount of reputation to add (can be negative) <NUMBER>
* 0: Amount <NUMBER> - Amount of reputation to add (positive) or subtract (negative)
*
* Return Value:
* New reputation amount <NUMBER>
* Success <BOOLEAN> - True if reputation was updated successfully, false otherwise
*
* Example:
* [10] call forge_client_org_fnc_addReputation // Add 10 reputation
* [-5] call forge_client_org_fnc_addReputation // Remove 5 reputation
*
* Public: Yes
*/
params [["_amount", 0, [0]]];
// Get the organization store interface
private _store = call FUNC(verifyOrgStore);
// Update the organization's reputation
private _result = _store call ["updateReputation", [_amount]];
// Provide feedback based on success or failure
if (_result) then {
TRACE_1("Reputation updated successfully",_amount);
// Format a user-friendly message based on whether we're adding or subtracting
private _actionText = ["decreased", "increased"] select (_amount > 0);
private _absAmount = abs _amount;
[format ["Organization reputation %1 by %2 points", _actionText, _absAmount], "info", 5, "right"] call forge_client_misc_fnc_notify;
} else {
TRACE_1("Failed to update reputation",_amount);
["Failed to update organization reputation", "error", 5, "right"] call forge_client_misc_fnc_notify;
};
// Return the result for further operations
_result

View File

@ -1,21 +1,24 @@
#include "..\script_component.hpp"
/*
* Function: forge_client_org_fnc_create
* Author: J. Schmidt
*
* Description:
* Creates a new organization for a player
* Creates a new organization for a player.
* Initializes the organization with the specified name, owner, and optional starting funds and reputation.
*
* Arguments:
* 0: _ownerUID - Player UID <STRING>
* 1: _ownerName - Player name <STRING> (unused, gets name from player object)
* 2: _name - Organization name <STRING>
* 3: _initialFunds - Initial funds for the org <NUMBER> (Optional, default: 0)
* 4: _initialReputation - Initial reputation for the org <NUMBER> (Optional, default: 0)
* 0: Owner UID <STRING> - Player UID who will own the organization
* 1: Organization Name <STRING> - Name of the organization
* 2: Initial Funds <NUMBER> (Optional, default: 0) - Starting funds for the organization
* 3: Initial Reputation <NUMBER> (Optional, default: 0) - Starting reputation for the organization
*
* Return Value:
* Organization data <HASHMAP> or nil on failure
* Organization Data <HASHMAP> - The newly created organization data, or nil if creation failed
*
* Example:
* [getPlayerUID player, "Alpha Squad", 5000, 100] call forge_client_org_fnc_create
* [getPlayerUID player, "Bravo Team"] call forge_client_org_fnc_create // With default funds and reputation
*
* Public: Yes
*/
params [
@ -25,25 +28,24 @@ params [
["_initialReputation", 0, [0]]
];
// Validate input parameters
if (_ownerUID == "" || _name == "") exitWith {
TRACE_2("Invalid parameters for organization creation",_ownerUID,_name);
["Invalid parameters for organization creation", "error", 5, "right"] call forge_client_misc_fnc_notify;
nil
};
// Get the organization store interface
private _store = call FUNC(verifyOrgStore);
// The createOrg method in the store already handles:
// - Checking if player already has an organization
// - Creating the organization with basic data
// - Adding the owner as a member
// - Saving to database
// Create the organization with the provided parameters
private _orgData = _store call ["createOrg", [_ownerUID, _name, _initialFunds, _initialReputation]];
// Provide feedback based on success or failure
if (isNil "_orgData") then {
TRACE_2("Failed to create organization",_name,_ownerUID);
[format ["Failed to create organization '%1'", _name], "error", 5, "right"] call forge_client_misc_fnc_notify;
} else {
TRACE_2("Organization created successfully",_name,_ownerUID);
[format ["Organization '%1' created successfully", _name], "success", 5, "right"] call forge_client_misc_fnc_notify;
};
// Return the organization data
// Return the organization data for further operations
_orgData

View File

@ -1,26 +1,36 @@
#include "..\script_component.hpp"
/*
* Function: forge_client_org_fnc_disband
* Author: J. Schmidt
*
* Description:
* Disbands an organization if requested by the owner
* Disbands an organization if requested by the owner.
* This permanently deletes the organization from the database and cannot be undone.
* Only the organization owner can perform this action.
*
* Arguments:
* None
*
* Return Value:
* Success <BOOL>
* Success <BOOLEAN> - True if organization was disbanded successfully, false otherwise
*
* Example:
* [] call forge_client_org_fnc_disband
*
* Public: Yes
*/
// Get the organization store interface
private _store = call FUNC(verifyOrgStore);
// Attempt to delete the organization
// This will validate ownership permissions and handle database deletion
private _result = _store call ["deleteOrg", []];
// Provide feedback based on success or failure
if (_result) then {
TRACE_1("Organization disbanded successfully",_result);
["Organization disbanded successfully", "success", 5, "right"] call forge_client_misc_fnc_notify;
} else {
TRACE_1("Failed to disband organization",_result);
["Failed to disband organization", "error", 5, "right"] call forge_client_misc_fnc_notify;
};
// Return the result for further operations
_result

View File

@ -1,37 +1,48 @@
#include "..\script_component.hpp"
/*
* Function: forge_client_org_fnc_handleOrgLoad
* Author: J. Schmidt
*
* Description:
* Handles organization data loaded from database
* Processes and transforms raw organization data from a database into a structured hashMap.
* Handles data normalization, type conversion, and ensures all required organization fields are present.
* This function is called as a callback when organization data is loaded from the database.
*
* Arguments:
* 0: Result <ARRAY> - Redis HGETALL result
* 0: Raw Data <ARRAY> - DragonflyDB HGETALL result containing raw organization data
*
* Return Value:
* None
*
* Example:
* _orgData call forge_client_org_fnc_handleOrgLoad
*
* Public: No
*/
// Log the received data for debugging purposes
diag_log text format ["[FORGE Organization] Organization data received: '%1'", _this];
// Store the raw data and get player information
private _data = _this;
private _playerNetId = netId player;
private _store = call FUNC(verifyOrgStore);
// Validate the received data
if (isNil "_data" || {!(_data isEqualType [])} || {count _data < 2} || {_data isEqualTo [""]}) exitWith {
diag_log text "[FORGE Organization] Empty or invalid organization data received";
// Mark the store as loaded but with no organization
if !(isNil "_store") then {
_store set ["currentOrganization", nil];
_store set ["isLoaded", true];
};
["No organization data found", "info", 5, "right"] call forge_client_misc_fnc_notify;
};
// Create organization data hashMap
// Create organization data hashMap to store the processed data
private _orgData = createHashMap;
// Process the data array
// Process the data array - convert from flat key-value pairs to structured hashMap
for "_i" from 0 to (count _data - 1) step 2 do {
private _key = _data select _i;
private _value = _data select (_i + 1);
@ -75,6 +86,7 @@ for "_i" from 0 to (count _data - 1) step 2 do {
_assetId = format ["%1_%2", _class, diag_tickTime];
};
// Add ID and class to asset map
_assetMap set ["id", _assetId];
_assetMap set ["className", _class];
@ -100,7 +112,7 @@ for "_i" from 0 to (count _data - 1) step 2 do {
};
case "members": {
// Convert to hashMap by memberUID
// Convert to hashMap by playerUID
private _flattenedMembers = [];
// Handle multi-level nesting and ensure it's flattened first
@ -123,11 +135,11 @@ for "_i" from 0 to (count _data - 1) step 2 do {
private _uid = _x select 0;
private _name = _x select 1;
private _role = _x select 2;
private _joinDate = if (count _x > 3) then {_x select 3} else {""};
private _joinDate = if (count _x > 3) then { _x select 3 } else { "" };
// Replace underscores with spaces in name
if (_name isEqualType "") then {
_name = (_name splitString "_") joinString " ";
_name = [_name] call EFUNC(misc,deserializeString);
};
// Create member hashMap
@ -179,17 +191,17 @@ for "_i" from 0 to (count _data - 1) step 2 do {
};
};
// Process string values
// Process string values - deserialize names and owner
if (_value isEqualType "" && _key in ["name", "owner"]) then {
_value = (_value splitString "_") joinString " ";
_value = [_value] call EFUNC(misc,deserializeString);
};
// Convert numeric values
// Convert numeric values from strings to numbers
if (_key in ["funds", "reputation"] && _value isEqualType "") then {
_value = parseNumber _value;
};
// Store in hashMap
// Store processed value in hashMap
_orgData set [_key, _value];
};
@ -224,7 +236,10 @@ private _requiredFields = ["id", "name", "owner", "funds", "reputation", "assets
_store set ["currentOrganization", _orgData];
_store set ["isLoaded", true];
// Log successful load
if (!isNil { _orgData get "name" }) then {
diag_log text format ["[FORGE Organization] Organization successfully loaded: %1", _orgData get "name"];
private _orgName = _orgData get "name";
// Log successful load and notify the user
if (!isNil "_orgName") then {
diag_log text format ["[FORGE Organization] Organization successfully loaded: %1", _orgName];
[format ["Organization '%1' loaded", _orgName], "success", 5, "right"] call forge_client_misc_fnc_notify;
};

View File

@ -5,21 +5,38 @@
* Author: J. Schmidt
*
* Description:
* Initializes player organization data interface for CRUD operations
* This interfaces with ArmaDragonflyClient database for persistence
* Initializes a client-side organization store interface for managing player organization data
* Provides CRUD operations for organizations, including database persistence through ArmaDragonflyClient
*
* Arguments:
* None
* Creates a hashMap object with methods for:
* - Creating, loading, and saving organizations
* - Managing organization funds and reputation
* - Adding, removing, and querying organization members and assets
*
* Return Value:
* Organization interface <OBJECT>
* Returns:
* Organization store interface <HASHMAP>
*
* Example:
* private _orgStore = call forge_client_org_fnc_initOrgStore;
* _orgStore call ["createOrg", [getPlayerUID player, "My Organization"]];
*/
private _orgStoreInterface = createHashMapObject [[
["#type", "IOrganizationStore"],
["#create", {
/**
* Initializes the organization store interface
*
* Sets up the initial state of the organization store:
* - Clears any existing organization data
* - Sets the current user's UID as the playerUID
* - Marks the store as not loaded
* - Triggers database loading of organization data
*
* @return {Boolean} True if initialization was successful
*/
_self set ["currentOrganization", nil];
_self set ["memberUID", getPlayerUID player];
_self set ["playerUID", getPlayerUID player];
_self set ["isLoaded", false];
_self call ["loadFromDatabase", []];
@ -27,7 +44,17 @@ private _orgStoreInterface = createHashMapObject [[
true
}],
["loadFromDatabase", {
private _playerUID = _self get "memberUID";
/**
* Loads organization data from the database
*
* Retrieves organization data associated with the current player's UID
* from the database using the ArmaDragonflyClient database system.
* Sets isLoaded to false until the data is retrieved and processed by
* the handleOrgLoad callback function.
*
* @return {Void} No return value
*/
private _playerUID = _self get "playerUID";
private _orgID = format ["%1_org", _playerUID];
["hgetallid", _orgID, "", -1, [], QFUNC(handleOrgLoad), false, netId player] remoteExecCall ["dragonfly_db_fnc_addTask", 2, false];
@ -35,9 +62,23 @@ private _orgStoreInterface = createHashMapObject [[
_self set ["isLoaded", false];
}],
["saveToDatabase", {
/**
* Saves the current organization data to the database
*
* Processes the organization data structure for database storage:
* - Serializes string values for name and owner
* - Converts the members hashMap to a flattened array format
* - Converts the assets hashMap to a flattened array format
* - Sends the processed data to the database using ArmaDragonflyClient
*
* @return {Boolean} True if save was successful, false if no organization data exists
*/
private _orgData = _self get "currentOrganization";
if (isNil "_orgData") exitWith { ERROR_MSG("No organization data to save"); false };
if (isNil "_orgData") exitWith {
["No organization data to save", "error", 5, "right"] call forge_client_misc_fnc_notify;
false
};
private _processedData = createHashMapFromArray [];
{
@ -45,7 +86,7 @@ private _orgStoreInterface = createHashMapObject [[
private _value = _orgData get _key;
if (_key in ["name", "owner"] && _value isEqualType "") then {
_value = (_value splitString " ") joinString "_";
_value = [_value] call EFUNC(misc,serializeString);
};
// Convert members hashMap back to array format for storage
@ -59,12 +100,11 @@ private _orgStoreInterface = createHashMapObject [[
private _name = _memberMap get "name";
// Replace spaces with underscores for storage
if (_name isEqualType "") then {
_name = (_name splitString " ") joinString "_";
_name = [_name] call EFUNC(misc,serializeString);
};
private _role = _memberMap get "role";
private _joinDate = _memberMap get "joinDate";
private _memberArray = [_uid, _name, _role, _joinDate];
// Add any additional properties
@ -88,6 +128,7 @@ private _orgStoreInterface = createHashMapObject [[
{
private _type = _x;
private _typeAssets = _value get _type;
{
private _assetMap = _x;
private _id = _assetMap get "id";
@ -130,22 +171,54 @@ private _orgStoreInterface = createHashMapObject [[
true
}],
["generateOrgID", {
/**
* Generates a unique organization ID based on the owner's UID
*
* Creates a standardized organization ID format by appending "_org"
* to the player's UID, ensuring consistent ID generation for database storage.
*
* @param {String} _uid The player UID to use as the base for the organization ID
* @return {String} The generated organization ID, or empty string if UID is invalid
*/
params [["_uid", "", [""]]];
if (_uid == "") exitWith { ERROR_MSG("Owner UID cannot be empty"); "" };
if (_uid == "") exitWith {
["Owner UID cannot be empty", "error", 5, "right"] call forge_client_misc_fnc_notify;
""
};
private _orgID =format ["%1_org", _uid];
private _orgID = format ["%1_org", _uid];
_orgID
}],
["createOrg", {
/**
* Creates a new organization with the specified parameters
*
* Initializes a new organization with the given name and owner,
* setting up the initial structure with default values for funds,
* reputation, assets, members, and logs. Adds the current player
* as the owner in the members list and saves to the database.
*
* @param {String} _uid The player UID who will be the organization owner
* @param {String} _name The name of the organization
* @param {Number} _initialFunds Starting funds for the organization (default: 0)
* @param {Number} _initialReputation Starting reputation for the organization (default: 0)
* @return {HashMap} The newly created organization data, or nil if creation failed
*/
params [["_uid", "", [""]], ["_name", "", [""]], ["_initialFunds", 0, [0]], ["_initialReputation", 0, [0]]];
if (_uid == "" || _name == "") exitWith { ERROR_MSG("Owner UID and name cannot be empty"); nil };
if (!isNil {_self get "currentOrganization"}) exitWith { ERROR_MSG("Player is already part of an organization"); nil };
if (_uid == "" || _name == "") exitWith {
["Owner UID and name cannot be empty", "error", 5, "right"] call forge_client_misc_fnc_notify;
nil
};
if (!isNil {_self get "currentOrganization"}) exitWith {
["You are already part of an organization", "warning", 5, "right"] call forge_client_misc_fnc_notify;
nil
};
private _dateTime = call EFUNC(misc,getSystemTime);
private _orgID = _self call ["generateOrgID", [_uid]];
private _orgData = createHashMapFromArray [
["id", _orgID],
["name", _name],
@ -174,26 +247,42 @@ private _orgStoreInterface = createHashMapObject [[
_self set ["currentOrganization", _orgData];
_self call ["saveToDatabase", []];
SETPVAR(player,FORGE_Organization,_orgID);
_orgData
}],
["getCurrentOrg", {
["getOrg", {
/**
* Retrieves the current organization data
*
* Gets the organization data for the current player. If the data
* hasn't been loaded yet, waits until the loading process completes
* before returning the data.
*
* @return {HashMap} The current organization data, or nil if not in an organization
*/
if (!(_self get "isLoaded")) then {
waitUntil { _self get "isLoaded" };
};
_self get "currentOrganization"
}],
["getOrgID", {
private _orgData = _self call ["getCurrentOrg", []];
if (isNil "_orgData") exitWith { ERROR_MSG("No organization found"); "" };
_orgData get "id"
}],
["syncWithDatabase", {
/**
* Synchronizes the current organization data with the database
*
* Updates the lastModified timestamp and saves the current
* organization data to the database. Used to ensure database
* consistency after making changes to the organization.
*
* @return {Boolean} True if sync was successful, false if no organization data exists
*/
private _orgData = _self get "currentOrganization";
if (isNil "_orgData") exitWith { ERROR_MSG("No organization data to sync"); false };
if (isNil "_orgData") exitWith {
["No organization data to sync", "error", 5, "right"] call forge_client_misc_fnc_notify;
false
};
_orgData set ["lastModified", call EFUNC(misc,getSystemTime)];
_self set ["currentOrganization", _orgData];
@ -202,11 +291,24 @@ private _orgStoreInterface = createHashMapObject [[
true
}],
["updateFunds", {
/**
* Updates the organization's funds balance
*
* Adds or subtracts the specified amount from the organization's funds.
* Records the transaction in the organization logs with timestamp,
* amount changed, and new balance.
*
* @param {Number} _amount The amount to add (positive) or subtract (negative)
* @return {Boolean} True if update was successful, false if no organization exists
*/
params [["_amount", 0, [0]]];
private _orgData = _self call ["getCurrentOrg", []];
private _orgData = _self call ["getOrg", []];
if (isNil "_orgData") exitWith { ERROR_MSG("No organization found"); false };
if (isNil "_orgData") exitWith {
["No organization found", "error", 5, "right"] call forge_client_misc_fnc_notify;
false
};
private _funds = _orgData get "funds";
private _dateTime = call EFUNC(misc,getSystemTime);
@ -215,6 +317,7 @@ private _orgStoreInterface = createHashMapObject [[
_orgData set ["funds", _newFunds];
_orgData set ["lastModified", _dateTime];
// Add to logs
private _logs = _orgData get "logs";
_logs pushBack [_dateTime, "FUNDS_UPDATED", _amount, _newFunds];
_orgData set ["logs", _logs];
@ -225,25 +328,50 @@ private _orgStoreInterface = createHashMapObject [[
true
}],
["getFunds", {
private _orgData = _self call ["getCurrentOrg", []];
/**
* Retrieves the current funds balance of the organization
*
* Gets the current financial balance of the organization.
* Used for displaying funds or checking if sufficient funds
* are available for transactions.
*
* @return {Number} The current funds amount, or nil if no organization exists
*/
private _orgData = _self call ["getOrg", []];
if (isNil "_orgData") exitWith { ERROR_MSG("No organization found"); nil };
if (isNil "_orgData") exitWith {
["No organization found", "error", 5, "right"] call forge_client_misc_fnc_notify;
nil
};
_orgData get "funds"
_orgData getOrDefault ["funds", 0]
}],
["updateReputation", {
/**
* Updates the organization's reputation value
*
* Adds or subtracts the specified amount from the organization's reputation.
* Records the change in the organization logs with timestamp,
* amount changed, and new reputation value.
*
* @param {Number} _amount The amount to add (positive) or subtract (negative)
* @return {Boolean} True if update was successful, false if no organization exists
*/
params [["_amount", 0, [0]]];
private _orgData = _self call ["getCurrentOrg", []];
private _orgData = _self call ["getOrg", []];
if (isNil "_orgData") exitWith { ERROR_MSG("No organization found"); false };
if (isNil "_orgData") exitWith {
["No organization found", "error", 5, "right"] call forge_client_misc_fnc_notify;
false
};
private _reputation = _orgData get "reputation";
private _newReputation = _reputation + _amount;
_orgData set ["reputation", _newReputation];
_orgData set ["lastModified", call EFUNC(misc,getSystemTime)];
// Add to logs
private _dateTime = call EFUNC(misc,getSystemTime);
private _logs = _orgData get "logs";
_logs pushBack [_dateTime, "REPUTATION_UPDATED", _amount, _newReputation];
@ -255,19 +383,50 @@ private _orgStoreInterface = createHashMapObject [[
true
}],
["getReputation", {
private _orgData = _self call ["getCurrentOrg", []];
/**
* Retrieves the current reputation value of the organization
*
* Gets the current reputation score of the organization.
* Used for displaying reputation or checking if sufficient reputation
* is available for certain actions or unlocks.
*
* @return {Number} The current reputation value, or nil if no organization exists
*/
private _orgData = _self call ["getOrg", []];
if (isNil "_orgData") exitWith { ERROR_MSG("No organization found"); nil };
if (isNil "_orgData") exitWith {
["No organization found", "error", 5, "right"] call forge_client_misc_fnc_notify;
nil
};
_orgData get "reputation"
_orgData getOrDefault ["reputation", 0]
}],
["addAsset", {
/**
* Adds a new asset to the organization's inventory
*
* Creates and stores a new asset entry in the organization's assets collection.
* Assets are organized by type (vehicles, buildings, etc.) and include
* a unique ID, class name, and any additional custom properties.
* Records the addition in the organization logs.
*
* @param {String} _assetType The category/type of the asset (e.g., "vehicle", "building")
* @param {String} _className The class name of the asset in the game
* @param {HashMap} _properties Additional properties to store with the asset
* @return {String} The generated unique ID for the asset, or false if failed
*/
params [["_assetType", "", [""]], ["_className", "", [""]], ["_properties", createHashMap, [createHashMap]]];
if (_assetType == "" || _className == "") exitWith { ERROR_MSG("Asset type and className cannot be empty"); false };
if (_assetType == "" || _className == "") exitWith {
["Asset type and className cannot be empty", "error", 5, "right"] call forge_client_misc_fnc_notify;
false
};
private _orgData = _self call ["getCurrentOrg", []];
if (isNil "_orgData") exitWith { ERROR_MSG("No organization found"); false };
private _orgData = _self call ["getOrg", []];
if (isNil "_orgData") exitWith {
["No organization found", "error", 5, "right"] call forge_client_misc_fnc_notify;
false
};
private _assets = _orgData get "assets";
if !(_assets isEqualType createHashMap) then {
@ -299,6 +458,7 @@ private _orgStoreInterface = createHashMapObject [[
_orgData set ["assets", _assets];
_orgData set ["lastModified", call EFUNC(misc,getSystemTime)];
// Add to logs
private _dateTime = call EFUNC(misc,getSystemTime);
private _logs = _orgData get "logs";
_logs pushBack [_dateTime, "ASSET_ADDED", _assetType, _className, _assetId];
@ -310,10 +470,26 @@ private _orgStoreInterface = createHashMapObject [[
_assetId // Return the generated ID
}],
["getAssets", {
/**
* Retrieves assets from the organization's inventory
*
* Flexible method to get assets from the organization with multiple retrieval options:
* - Get all assets across all types
* - Get all assets of a specific type
* - Get a specific asset by ID or className
*
* @param {String} _assetType Optional type/category to filter assets (empty for all types)
* @param {String} _idOrClassName Optional ID or className to find a specific asset
* @param {Boolean} _findById If true, search by ID; if false, search by className
* @return {Array|HashMap|Nil} Asset data based on search parameters, or nil if not found
*/
params [["_assetType", "", [""]], ["_idOrClassName", "", [""]], ["_findById", false, [false]]];
private _orgData = _self call ["getCurrentOrg", []];
if (isNil "_orgData") exitWith { ERROR_MSG("No organization found"); nil };
private _orgData = _self call ["getOrg", []];
if (isNil "_orgData") exitWith {
["No organization found", "error", 5, "right"] call forge_client_misc_fnc_notify;
nil
};
private _assets = _orgData get "assets";
if !(_assets isEqualType createHashMap) then {
@ -368,12 +544,29 @@ private _orgStoreInterface = createHashMapObject [[
}
}],
["removeAsset", {
/**
* Removes an asset from the organization's inventory
*
* Deletes a specific asset from the organization's assets collection
* based on its type and unique ID. Records the removal in the
* organization logs with details about the removed asset.
*
* @param {String} _assetType The category/type of the asset to remove
* @param {String} _assetId The unique ID of the asset to remove
* @return {Boolean} True if asset was successfully removed, false if not found or error
*/
params [["_assetType", "", [""]], ["_assetId", "", [""]]];
if (_assetType == "" || _assetId == "") exitWith { ERROR_MSG("Asset type and asset ID cannot be empty"); false };
if (_assetType == "" || _assetId == "") exitWith {
["Asset type and asset ID cannot be empty", "error", 5, "right"] call forge_client_misc_fnc_notify;
false
};
private _orgData = _self call ["getCurrentOrg", []];
if (isNil "_orgData") exitWith { ERROR_MSG("No organization found"); false };
private _orgData = _self call ["getOrg", []];
if (isNil "_orgData") exitWith {
["No organization found", "error", 5, "right"] call forge_client_misc_fnc_notify;
false
};
private _assets = _orgData get "assets";
if !(_assets isEqualType createHashMap) then {
@ -391,6 +584,7 @@ private _orgStoreInterface = createHashMapObject [[
_assets set [_assetType, _typeAssets];
_orgData set ["assets", _assets];
// Add to logs
private _dateTime = call EFUNC(misc,getSystemTime);
private _logs = _orgData get "logs";
_logs pushBack [_dateTime, "ASSET_REMOVED", _assetType, _className, _assetId];
@ -402,20 +596,40 @@ private _orgStoreInterface = createHashMapObject [[
true
} else {
ERROR_MSG_2("Asset with ID %1 not found in type %2",_assetId,_assetType);
false
};
}],
["addMember", {
/**
* Adds a new member to the organization
*
* Creates and stores a new member entry in the organization's members collection.
* Only the organization owner can add new members. Each member has a UID, name,
* role, and join date. Records the addition in the organization logs.
*
* @param {String} _uid The unique player ID of the member to add
* @param {String} _name The display name of the member
* @param {String} _role The role/rank of the member in the organization (default: "member")
* @return {Boolean} True if member was successfully added, false if error or not authorized
*/
params [["_uid", "", [""]], ["_name", "", [""]], ["_role", "member", [""]]];
if (_uid == "" || _name == "") exitWith { ERROR_MSG("Member UID and name cannot be empty"); false };
if (_uid == "" || _name == "") exitWith {
["Member UID and name cannot be empty", "error", 5, "right"] call forge_client_misc_fnc_notify;
false
};
private _orgData = _self call ["getCurrentOrg", []];
if (isNil "_orgData") exitWith { ERROR_MSG("No organization found"); false };
private _orgData = _self call ["getOrg", []];
if (isNil "_orgData") exitWith {
["No organization found", "error", 5, "right"] call forge_client_misc_fnc_notify;
false
};
private _playerUID = _self get "memberUID";
if ((_orgData get "owner") != _playerUID) exitWith { ERROR_MSG("Only the owner can add members"); false };
private _playerUID = _self get "playerUID";
if ((_orgData get "owner") != _playerUID) exitWith {
["Only the owner can add members", "error", 5, "right"] call forge_client_misc_fnc_notify;
false
};
private _members = _orgData get "members";
if !(_members isEqualType createHashMap) then {
@ -423,12 +637,17 @@ private _orgStoreInterface = createHashMapObject [[
};
// Check if member already exists
if (!isNil {_members get _uid}) exitWith { ERROR_MSG_1("Member already in this organization: %1",_uid); true };
if (!isNil {_members get _uid}) exitWith {
private _errorMsg = format ["Member already in this organization: %1", _uid];
[_errorMsg, "warning", 5, "right"] call forge_client_misc_fnc_notify;
true
};
// Create member hashMap
private _memberMap = createHashMap;
private _joinDate = call EFUNC(misc,getSystemTime);
// Add member data to hashMap
_memberMap set ["uid", _uid];
_memberMap set ["name", _name];
_memberMap set ["role", _role];
@ -439,6 +658,7 @@ private _orgStoreInterface = createHashMapObject [[
_orgData set ["members", _members];
_orgData set ["lastModified", call EFUNC(misc,getSystemTime)];
// Add to logs
private _dateTime = call EFUNC(misc,getSystemTime);
private _logs = _orgData get "logs";
_logs pushBack [_dateTime, "MEMBER_ADDED", _uid, _name, _role];
@ -450,15 +670,34 @@ private _orgStoreInterface = createHashMapObject [[
true
}],
["removeMember", {
/**
* Removes a member from the organization
*
* Deletes a member from the organization's members collection based on their UID.
* Only the organization owner can remove members, and the owner cannot remove themselves.
* Records the removal in the organization logs.
*
* @param {String} _uid The unique player ID of the member to remove
* @return {Boolean} True if member was successfully removed, false if not found or not authorized
*/
params [["_uid", "", [""]]];
if (_uid == "") exitWith { ERROR_MSG("Member UID cannot be empty"); false };
if (_uid == "") exitWith {
["Member UID cannot be empty", "error", 5, "right"] call forge_client_misc_fnc_notify;
false
};
private _orgData = _self call ["getCurrentOrg", []];
if (isNil "_orgData") exitWith { ERROR_MSG("No organization found"); false };
private _orgData = _self call ["getOrg", []];
if (isNil "_orgData") exitWith {
["No organization found", "error", 5, "right"] call forge_client_misc_fnc_notify;
false
};
private _playerUID = _self get "memberUID";
if ((_orgData get "owner") != _playerUID) exitWith { ERROR_MSG("Only the owner can remove members"); false };
private _playerUID = _self get "playerUID";
if ((_orgData get "owner") != _playerUID) exitWith {
["Only the owner can remove members", "error", 5, "right"] call forge_client_misc_fnc_notify;
false
};
private _members = _orgData get "members";
if !(_members isEqualType createHashMap) then {
@ -467,10 +706,17 @@ private _orgStoreInterface = createHashMapObject [[
// Get member and check if they exist
private _memberMap = _members get _uid;
if (isNil "_memberMap") exitWith { ERROR_MSG_1("Member not in organization: %1",_uid); false };
if (isNil "_memberMap") exitWith {
private _errorMsg = format ["Member not in organization: %1", _uid];
[_errorMsg, "error", 5, "right"] call forge_client_misc_fnc_notify;
false
};
// Check if trying to remove the owner
if ((_memberMap get "role") == "owner") exitWith { ERROR_MSG("Cannot remove the organization owner"); false };
if ((_memberMap get "role") == "owner") exitWith {
["Cannot remove the organization owner", "error", 5, "right"] call forge_client_misc_fnc_notify;
false
};
// Get name for logging
private _name = _memberMap get "name";
@ -480,6 +726,7 @@ private _orgStoreInterface = createHashMapObject [[
_orgData set ["members", _members];
_orgData set ["lastModified", call EFUNC(misc,getSystemTime)];
// Add to logs
private _dateTime = call EFUNC(misc,getSystemTime);
private _logs = _orgData get "logs";
_logs pushBack [_dateTime, "MEMBER_REMOVED", _uid, _name];
@ -488,13 +735,27 @@ private _orgStoreInterface = createHashMapObject [[
_self set ["currentOrganization", _orgData];
_self call ["saveToDatabase", []];
[format ["Member %1 removed from organization", _name], "info", 5, "right"] call forge_client_misc_fnc_notify;
true
}],
["getMembers", {
/**
* Retrieves members from the organization
*
* Gets either a specific member by UID or all members of the organization.
* Returns member data including UID, name, role, and join date.
*
* @param {String} _uid Optional UID to get a specific member (empty for all members)
* @return {HashMap|Array|Nil} Member data for specific member, array of all members, or nil if error
*/
params [["_uid", "", [""]]];
private _orgData = _self call ["getCurrentOrg", []];
if (isNil "_orgData") exitWith { ERROR_MSG("No organization found"); nil };
private _orgData = _self call ["getOrg", []];
if (isNil "_orgData") exitWith {
["No organization found", "error", 5, "right"] call forge_client_misc_fnc_notify;
nil
};
private _members = _orgData get "members";
if !(_members isEqualType createHashMap) then {
@ -515,12 +776,27 @@ private _orgStoreInterface = createHashMapObject [[
}
}],
["deleteOrg", {
private _orgData = _self call ["getCurrentOrg", []];
/**
* Deletes the entire organization
*
* Permanently removes the organization from the database.
* Only the organization owner can delete the organization.
* Clears the current organization data from the store after deletion.
*
* @return {Boolean} True if organization was successfully deleted, false if not authorized
*/
private _orgData = _self call ["getOrg", []];
if (isNil "_orgData") exitWith { ERROR_MSG("No organization found"); false };
if (isNil "_orgData") exitWith {
["No organization found", "error", 5, "right"] call forge_client_misc_fnc_notify;
false
};
private _playerUID = _self get "memberUID";
if ((_orgData get "owner") != _playerUID) exitWith { ERROR_MSG("Only the owner can delete the organization"); false };
private _playerUID = _self get "playerUID";
if ((_orgData get "owner") != _playerUID) exitWith {
["Only the owner can delete the organization", "error", 5, "right"] call forge_client_misc_fnc_notify;
false
};
private _orgID = _orgData get "id";
["del", _orgID, "", -1, [], "", false, netId player] remoteExecCall ["dragonfly_db_fnc_addTask", 2, false];
@ -531,11 +807,26 @@ private _orgStoreInterface = createHashMapObject [[
true
}],
["leaveOrg", {
private _orgData = _self call ["getCurrentOrg", []];
if (isNil "_orgData") exitWith { ERROR_MSG("No organization found"); false };
/**
* Removes the current player from the organization
*
* Allows a member to leave the organization they're currently in.
* The organization owner cannot use this method (must use deleteOrg instead).
* Records the departure in the organization logs before removing player access.
*
* @return {Boolean} True if player successfully left the organization, false if error or owner
*/
private _orgData = _self call ["getOrg", []];
if (isNil "_orgData") exitWith {
["No organization found", "error", 5, "right"] call forge_client_misc_fnc_notify;
false
};
private _playerUID = _self get "memberUID";
if ((_orgData get "owner") == _playerUID) exitWith { ERROR_MSG("Organization owner cannot leave, must delete instead"); false };
private _playerUID = _self get "playerUID";
if ((_orgData get "owner") == _playerUID) exitWith {
["Organization owner cannot leave, must delete instead", "warning", 5, "right"] call forge_client_misc_fnc_notify;
false
};
private _members = _orgData get "members";
if !(_members isEqualType createHashMap) then {
@ -547,6 +838,8 @@ private _orgStoreInterface = createHashMapObject [[
if (!isNil "_memberMap") then {
private _dateTime = call EFUNC(misc,getSystemTime);
private _memberName = _memberMap get "name";
// Add to logs
private _logs = _orgData get "logs";
_logs pushBack [_dateTime, "MEMBER_LEFT", _playerUID, _memberName];
_orgData set ["logs", _logs];
@ -557,9 +850,11 @@ private _orgStoreInterface = createHashMapObject [[
_self set ["currentOrganization", nil];
_self set ["isLoaded", true];
["You have left the organization", "info", 5, "right"] call forge_client_misc_fnc_notify;
true
}]
]];
SETMVAR(FORGE_ORG_STORE_REG,_orgStoreInterface);
GETMVAR(FORGE_ORG_STORE_REG,nil)
GETMVAR(FORGE_ORG_STORE_REG,_orgStoreInterface)

View File

@ -1,26 +1,36 @@
#include "..\script_component.hpp"
/*
* Function: forge_client_org_fnc_leave
* Author: J. Schmidt
*
* Description:
* Removes a player from an organization
* Removes the current player from an organization.
* This allows a member to leave their organization voluntarily.
* Organization owners cannot use this function and must use disband instead.
*
* Arguments:
* None
*
* Return Value:
* Success <BOOL>
* Success <BOOLEAN> - True if player successfully left the organization, false otherwise
*
* Example:
* [] call forge_client_org_fnc_leave
*
* Public: Yes
*/
// Get the organization store interface
private _store = call FUNC(verifyOrgStore);
// Attempt to leave the organization
// This will validate that the player is not the owner and handle database updates
private _result = _store call ["leaveOrg", []];
// Provide feedback based on success or failure
if (_result) then {
TRACE_1("Left organization successfully",_result);
["You have left the organization", "success", 5, "right"] call forge_client_misc_fnc_notify;
} else {
TRACE_1("Failed to leave organization",_result);
["Failed to leave organization", "error", 5, "right"] call forge_client_misc_fnc_notify;
};
// Return the result for further operations
_result

View File

@ -1,31 +1,43 @@
#include "..\script_component.hpp"
/*
* Function: forge_client_org_fnc_removeAsset
* Author: J. Schmidt
*
* Description:
* Removes an asset from an organization's inventory
* Removes an asset from an organization's inventory.
* Deletes the specified asset based on its type and unique identifier.
*
* Arguments:
* 0: _assetType - Type of asset (vehicle, building, etc.) <STRING>
* 1: _assetId - Unique identifier of the asset <STRING>
* 0: Asset Type <STRING> - Type of asset (vehicle, building, etc.)
* 1: Asset ID <STRING> - Unique identifier of the asset to remove
*
* Return Value:
* Success <BOOLEAN>
* Success <BOOLEAN> - True if asset was removed successfully, false otherwise
*
* Example:
* ["vehicle", "B_MRAP_01_F_1234567890"] call forge_client_org_fnc_removeAsset
*
* Public: Yes
*/
params [["_assetType", "", [""]], ["_assetId", "", [""]]];
if (_assetType isEqualTo "" || _assetId isEqualTo "") exitWith { TRACE_2("Invalid parameters for removing asset",_assetType,_assetId); createHashMap };
private _store = call FUNC(verifyOrgStore);
private _result = _store call ["removeAsset", [_assetType, _assetId]];
if (_result) then {
TRACE_1("Asset removed successfully",_assetId);
} else {
TRACE_1("Failed to remove asset",_assetId);
// Validate input parameters
if (_assetType isEqualTo "" || _assetId isEqualTo "") exitWith {
["Invalid parameters for removing asset", "error", 5, "right"] call forge_client_misc_fnc_notify;
false
};
// Get the organization store interface
private _store = call FUNC(verifyOrgStore);
// Remove the asset from the organization's inventory
private _result = _store call ["removeAsset", [_assetType, _assetId]];
// Provide feedback based on success or failure
if (_result) then {
[format ["Asset removed successfully: %1", _assetId], "success", 5, "right"] call forge_client_misc_fnc_notify;
} else {
[format ["Failed to remove asset: %1", _assetId], "error", 5, "right"] call forge_client_misc_fnc_notify;
};
// Return the result for further operations
_result

View File

@ -1,21 +1,34 @@
#include "..\script_component.hpp"
/*
* Function: forge_client_org_fnc_verifyOrgStore
* Author: J. Schmidt
*
* Description:
* Ensures the store is initialized and returns the store object
* Ensures the organization store is initialized and returns the store object.
* Acts as a singleton accessor for the organization store interface.
* If the store doesn't exist yet, it initializes it first.
*
* Arguments:
* None
*
* Return Value:
* Store object <OBJECT>
* Organization Store <OBJECT> - The organization store interface object
*
* Example:
* private _orgStore = call forge_client_org_fnc_verifyOrgStore
*
* Public: No
*/
// Attempt to retrieve the existing organization store from the global variable
private _store = GETMVAR(FORGE_ORG_STORE_REG,nil);
if (isNil "_store") then { _store = [] call FUNC(initOrgStore); };
// If the store doesn't exist yet, initialize it
if (isNil "_store") then {
// Create a new organization store
_store = call FUNC(initOrgStore);
// Log the initialization for debugging
diag_log text "[FORGE Organization] Organization store initialized";
};
// Return the organization store interface
_store

View File

@ -1,4 +1,4 @@
GetCurrentOrg: [["assets",[["vehicle",[[["id","B_MRAP_01_F_2025-03-30_21:42:43.261"],["className","B_MRAP_01_F"]]]]]],["created","2025-03-30_21:42:23.900"],["lastModified","2025-03-30_21:42:43.261"],["name","Blackwater Corp"],["logs",[["2025-03-30_21:42:43.261","ASSET_ADDED","vehicle","B_MRAP_01_F","B_MRAP_01_F_2025-03-30_21:42:43.261"],["2025-03-30_21:47:05.667","ASSET_ADDED","vehicle","B_MRAP_01_F","B_MRAP_01_F_2025-03-30_21:47:05.667"]]],["id","76561198027566824_org"],["funds",5000],["reputation",500],["owner","76561198027566824"],["members",[["76561198027566824",[["name","Jacob Schmidt"],["uid","76561198027566824"],["role","owner"],["joinDate","2025-03-30_21:42:23.900"]]]]]]
getOrg: [["assets",[["vehicle",[[["id","B_MRAP_01_F_2025-03-30_21:42:43.261"],["className","B_MRAP_01_F"]]]]]],["created","2025-03-30_21:42:23.900"],["lastModified","2025-03-30_21:42:43.261"],["name","Blackwater Corp"],["logs",[["2025-03-30_21:42:43.261","ASSET_ADDED","vehicle","B_MRAP_01_F","B_MRAP_01_F_2025-03-30_21:42:43.261"],["2025-03-30_21:47:05.667","ASSET_ADDED","vehicle","B_MRAP_01_F","B_MRAP_01_F_2025-03-30_21:47:05.667"]]],["id","76561198027566824_org"],["funds",5000],["reputation",500],["owner","76561198027566824"],["members",[["76561198027566824",[["name","Jacob Schmidt"],["uid","76561198027566824"],["role","owner"],["joinDate","2025-03-30_21:42:23.900"]]]]]]
GetAssets: [["vehicle","B_MRAP_01_F","id","B_MRAP_01_F_2025-03-30_21:42:43.261"]]
GetAssets(Vehicle): [[["id","B_MRAP_01_F_2025-03-30_21:42:43.261"],["className","B_MRAP_01_F"]]]
GetAssets(Vehicle,ID): [["id","B_MRAP_01_F_2025-03-30_21:42:43.261"],["className","B_MRAP_01_F"]]

View File

@ -16,8 +16,23 @@ if (count _payment > 3) then {
};
};
if (_payment select 0 == "Organization") then {
private _store = missionNamespace getVariable ["FORGE_ORG_STORE_REG", createHashMap];
private _org = _store call ["getCurrentOrg", []];
private _ownerUID = _org get "owner";
if (getPlayerUID player != _ownerUID) then {
["You do not own this organization!", "warning", 3, "right"] call EFUNC(misc,notify);
false breakOut "main";
};
};
private _varType = _payment select 2;
private _balance = switch (_varType) do {
case "organization": {
private _store = missionNamespace getVariable ["FORGE_ORG_STORE_REG", createHashMap];
_store call ["getFunds", []];
};
case "player": { player getVariable [_payment select 1, 0] };
case "mission": { missionNamespace getVariable [_payment select 1, 0] };
default { 0 };
@ -29,6 +44,10 @@ if (_balance < _price) exitWith {
};
switch (_varType) do {
case "organization": {
private _store = missionNamespace getVariable ["FORGE_ORG_STORE_REG", createHashMap];
_store call ["updateFunds", -_price];
};
case "player": {
player setVariable [_payment select 1, (_balance - _price), true];
};

View File

@ -63,7 +63,9 @@ if (_result == 1) then {
["MissionFail", false] remoteExecCall ["BIS_fnc_endMission", playerSide];
};
["deduct", _ratingFail] remoteExecCall ["forge_server_rating_fnc_handleRating", 2];
// ["deduct", _ratingFail] remoteExecCall ["forge_server_rating_fnc_handleRating", 2];
[_ratingFail] call EFUNC(org,addReputation);
[format ["Task failed: %1 reputation", _ratingFail], "warning", 5, "right"] call EFUNC(misc,notify);
sleep 1;
@ -77,11 +79,15 @@ if (_result == 1) then {
["MissionSuccess", true] remoteExecCall ["BIS_fnc_endMission", playerSide];
};
["advance", _ratingSuccess] remoteExecCall ["forge_server_rating_fnc_handleRating", 2];
// ["advance", _ratingSuccess] remoteExecCall ["forge_server_rating_fnc_handleRating", 2];
[_ratingSuccess] call EFUNC(org,addReputation);
[format ["Task completed: %1 reputation", _ratingSuccess], "success", 5, "right"] call EFUNC(misc,notify);
sleep 1;
{ [_x, _ratingSuccess] remoteExec ["addRating", -2] } forEach allPlayers;
["advance", _companyFunds] remoteExecCall ["forge_server_money_fnc_handleFunds", 2];
// ["advance", _companyFunds] remoteExecCall ["forge_server_money_fnc_handleFunds", 2];
[_companyFunds] call EFUNC(org,addFunds);
[format ["Task completed: %1 funds", _companyFunds], "success", 5, "right"] call EFUNC(misc,notify);
};

View File

@ -62,7 +62,9 @@ if (_result == 1) then {
["MissionFail", false] remoteExecCall ["BIS_fnc_endMission", playerSide];
};
["deduct", _ratingFail] remoteExecCall ["forge_server_rating_fnc_handleRating", 2];
// ["deduct", _ratingFail] remoteExecCall ["forge_server_rating_fnc_handleRating", 2];
[_ratingFail] call EFUNC(org,addReputation);
[format ["Task failed: %1 reputation", _ratingFail], "warning", 5, "right"] call EFUNC(misc,notify);
sleep 1;
@ -77,13 +79,17 @@ if (_result == 1) then {
["MissionSuccess", true] remoteExecCall ["BIS_fnc_endMission", playerSide];
};
["advance", _ratingSuccess] remoteExecCall ["forge_server_rating_fnc_handleRating", 2];
// ["advance", _ratingSuccess] remoteExecCall ["forge_server_rating_fnc_handleRating", 2];
[_ratingSuccess] call EFUNC(org,addReputation);
[format ["Task completed: %1 reputation", _ratingSuccess], "success", 5, "right"] call EFUNC(misc,notify);
sleep 1;
{ [_x, _ratingSuccess] remoteExec ["addRating", -2] } forEach allPlayers;
["advance", _companyFunds] remoteExecCall ["forge_server_money_fnc_handleFunds", 2];
// ["advance", _companyFunds] remoteExecCall ["forge_server_money_fnc_handleFunds", 2];
[_companyFunds] call EFUNC(org,addFunds);
[format ["Task completed: %1 funds", _companyFunds], "success", 5, "right"] call EFUNC(misc,notify);
};
GVAR(defusedCount) = 0;

View File

@ -63,7 +63,9 @@ if (_result == 1) then {
["MissionFail", false] remoteExecCall ["BIS_fnc_endMission", playerSide];
};
["deduct", _ratingFail] remoteExecCall ["forge_server_rating_fnc_handleRating", 2];
// ["deduct", _ratingFail] remoteExecCall ["forge_server_rating_fnc_handleRating", 2];
[_ratingFail] call EFUNC(org,addReputation);
[format ["Task failed: %1 reputation", _ratingFail], "warning", 5, "right"] call EFUNC(misc,notify);
sleep 1;
@ -77,11 +79,15 @@ if (_result == 1) then {
["MissionSuccess", true] remoteExecCall ["BIS_fnc_endMission", playerSide];
};
["advance", _ratingSuccess] remoteExecCall ["forge_server_rating_fnc_handleRating", 2];
// ["advance", _ratingSuccess] remoteExecCall ["forge_server_rating_fnc_handleRating", 2];
[_ratingSuccess] call EFUNC(org,addReputation);
[format ["Task completed: %1 reputation", _ratingSuccess], "success", 5, "right"] call EFUNC(misc,notify);
sleep 1;
{ [_x, _ratingSuccess] remoteExec ["addRating", -2] } forEach allPlayers;
["advance", _companyFunds] remoteExecCall ["forge_server_money_fnc_handleFunds", 2];
// ["advance", _companyFunds] remoteExecCall ["forge_server_money_fnc_handleFunds", 2];
[_companyFunds] call EFUNC(org,addFunds);
[format ["Task completed: %1 funds", _companyFunds], "success", 5, "right"] call EFUNC(misc,notify);
};

View File

@ -117,7 +117,9 @@ if (_result == 1) then {
["MissionFail", false] remoteExecCall ["BIS_fnc_endMission", playerSide];
};
["deduct", _ratingFail] remoteExecCall ["forge_server_rating_fnc_handleRating", 2];
// ["deduct", _ratingFail] remoteExecCall ["forge_server_rating_fnc_handleRating", 2];
[_ratingFail] call EFUNC(org,addReputation);
[format ["Task failed: %1 reputation", _ratingFail], "warning", 5, "right"] call EFUNC(misc,notify);
sleep 1;
@ -132,11 +134,15 @@ if (_result == 1) then {
["MissionSuccess", true] remoteExecCall ["BIS_fnc_endMission", playerSide];
};
["advance", _ratingSuccess] remoteExecCall ["forge_server_rating_fnc_handleRating", 2];
// ["advance", _ratingSuccess] remoteExecCall ["forge_server_rating_fnc_handleRating", 2];
[_ratingSuccess] call EFUNC(org,addReputation);
[format ["Task completed: %1 reputation", _ratingSuccess], "success", 5, "right"] call EFUNC(misc,notify);
sleep 1;
{ [_x, _ratingSuccess] remoteExec ["addRating", -2] } forEach allPlayers;
["advance", _companyFunds] remoteExecCall ["forge_server_money_fnc_handleFunds", 2];
// ["advance", _companyFunds] remoteExecCall ["forge_server_money_fnc_handleFunds", 2];
[_companyFunds] call EFUNC(org,addFunds);
[format ["Task completed: %1 funds", _companyFunds], "success", 5, "right"] call EFUNC(misc,notify);
};

View File

@ -75,7 +75,9 @@ if (_result == 1) then {
["MissionFail", false] remoteExecCall ["BIS_fnc_endMission", playerSide];
};
["deduct", _ratingFail] remoteExecCall ["forge_server_rating_fnc_handleRating", 2];
// ["deduct", _ratingFail] remoteExecCall ["forge_server_rating_fnc_handleRating", 2];
[_ratingFail] call EFUNC(org,addReputation);
[format ["Task failed: %1 reputation", _ratingFail], "warning", 5, "right"] call EFUNC(misc,notify);
sleep 1;
@ -89,11 +91,15 @@ if (_result == 1) then {
["MissionSuccess", true] remoteExecCall ["BIS_fnc_endMission", playerSide];
};
["advance", _ratingSuccess] remoteExecCall ["forge_server_rating_fnc_handleRating", 2];
// ["advance", _ratingSuccess] remoteExecCall ["forge_server_rating_fnc_handleRating", 2];
[_ratingSuccess] call EFUNC(org,addReputation);
[format ["Task succeeded: %1 reputation", _ratingSuccess], "success", 5, "right"] call EFUNC(misc,notify);
sleep 1;
{ [_x, _ratingSuccess] remoteExec ["addRating", -2] } forEach allPlayers;
["advance", _companyFunds] remoteExecCall ["forge_server_money_fnc_handleFunds", 2];
// ["advance", _companyFunds] remoteExecCall ["forge_server_money_fnc_handleFunds", 2];
[_companyFunds] call EFUNC(org,addFunds);
[format ["Task succeeded: %1 funds", _companyFunds], "success", 5, "right"] call EFUNC(misc,notify);
};

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff