347 lines
14 KiB
Plaintext
347 lines
14 KiB
Plaintext
#include "..\script_component.hpp"
|
|
|
|
/*
|
|
* File: fnc_initMEconomyStore.sqf
|
|
* Author: IDSolutions
|
|
* Date: 2025-12-20
|
|
* Last Update: 2026-06-03
|
|
* Public: No
|
|
*
|
|
* Description:
|
|
* Initializes the medical economy store. Respawn, body-bag, and spawn
|
|
* occupancy behavior remains server-local, while money mutations are
|
|
* routed through player bank hot state first, then organization hot state
|
|
* with a repayable member debt when personal funds cannot cover the bill.
|
|
*
|
|
* Parameter(s):
|
|
* N/A
|
|
*
|
|
* Returns:
|
|
* Medical economy store object [HASHMAP OBJECT]
|
|
*
|
|
* Example(s):
|
|
* call forge_server_economy_fnc_initMEconomyStore
|
|
*/
|
|
|
|
#pragma hemtt ignore_variables ["_self"]
|
|
GVAR(MEconomyStore) = createHashMapObject [[
|
|
["#type", "IMedEconomy"],
|
|
["#create", {
|
|
_self set ["mSpawns", createHashMap];
|
|
|
|
GVAR(occupancyTriggers) = [];
|
|
GVAR(SpawnCost) = 100;
|
|
["INFO", "Medical Store Initialized!", nil, nil] call EFUNC(common,log);
|
|
}],
|
|
["numberSetting", {
|
|
params [["_name", "", [""]], ["_default", 0, [0]]];
|
|
|
|
private _configDefault = _default;
|
|
private _serviceConfig = missionConfigFile >> "CfgServicePricing";
|
|
if !(isClass _serviceConfig) then { _serviceConfig = configFile >> "CfgServicePricing"; };
|
|
if (isNumber (_serviceConfig >> _name)) then {
|
|
_configDefault = getNumber (_serviceConfig >> _name);
|
|
};
|
|
|
|
private _paramValue = [_name, _configDefault] call BIS_fnc_getParamValue;
|
|
private _value = missionNamespace getVariable [_name, _paramValue];
|
|
if (_value isEqualType "") exitWith { (parseNumber _value) max 0 };
|
|
if (_value isEqualType 0) exitWith { _value max 0 };
|
|
_configDefault
|
|
}],
|
|
["init", {
|
|
private _mSpawns = (_self get "mSpawns");
|
|
private _prefix = "med_spawn";
|
|
|
|
for "_i" from 0 to 10 do {
|
|
private _var = if (_i == 0) then { _prefix } else { format ["%1_%2", _prefix, _i] };
|
|
private _obj = missionNamespace getVariable [_var, objNull];
|
|
|
|
if (!isNull _obj) then {
|
|
_mSpawns set [_var, [_obj, (getPos _obj)]];
|
|
};
|
|
};
|
|
|
|
if (_mSpawns isEqualTo createHashMap) then {
|
|
["WARNING", "No medical spawns found in the world.", nil, nil] call EFUNC(common,log);
|
|
} else {
|
|
{
|
|
_y params ["_obj", "_pos"];
|
|
private _trigger = createTrigger ["EmptyDetector", _pos];
|
|
|
|
_trigger setVariable ["isOccupied", false, true];
|
|
_trigger setVariable ["linkedObject", _obj, true];
|
|
_trigger setTriggerArea [5, 5, 0, true, 5];
|
|
_trigger setTriggerActivation ["ANYPLAYER", "PRESENT", true];
|
|
_trigger setTriggerStatements [
|
|
"{ (_x isKindOf 'CAManBase') && _x distance thisTrigger < 0.5 } count thisList > 0",
|
|
"thisTrigger setVariable ['isOccupied', true, true];",
|
|
"thisTrigger setVariable ['isOccupied', false, true];"
|
|
];
|
|
|
|
GVAR(occupancyTriggers) pushBack _trigger;
|
|
} forEach _mSpawns;
|
|
};
|
|
}],
|
|
["notify", {
|
|
params [["_unit", objNull, [objNull]], ["_type", "info", [""]], ["_title", "Medical Billing", [""]], ["_message", "", [""]]];
|
|
|
|
if (isNull _unit || { _message isEqualTo "" }) exitWith { false };
|
|
|
|
private _uid = getPlayerUID _unit;
|
|
if (_uid isEqualTo "") exitWith { false };
|
|
if (isNil QEGVAR(common,EventBus)) then {
|
|
[CRPC(notifications,recieveNotification), [_type, _title, _message], _unit] call CFUNC(targetEvent);
|
|
} else {
|
|
EGVAR(common,EventBus) call ["emit", [
|
|
"notification.requested",
|
|
createHashMapFromArray [
|
|
["uids", [_uid]],
|
|
["notificationType", _type],
|
|
["title", _title],
|
|
["message", _message]
|
|
],
|
|
createHashMapFromArray [["source", "economy"]]
|
|
]];
|
|
};
|
|
|
|
true
|
|
}],
|
|
["chargePlayer", {
|
|
params [["_uid", "", [""]], ["_amount", 0, [0]]];
|
|
|
|
private _result = createHashMapFromArray [
|
|
["success", false],
|
|
["fallbackEligible", false],
|
|
["source", ""],
|
|
["message", "Unable to charge personal funds."]
|
|
];
|
|
|
|
if (_uid isEqualTo "") exitWith {
|
|
_result set ["message", "A valid player UID is required for medical billing."];
|
|
_result
|
|
};
|
|
if (_amount <= 0) exitWith {
|
|
_result set ["success", true];
|
|
_result
|
|
};
|
|
if (isNil QEGVAR(bank,BankStore)) exitWith {
|
|
_result set ["message", "Personal billing is unavailable. Medical service cannot complete."];
|
|
_result
|
|
};
|
|
|
|
private _account = EGVAR(bank,BankStore) call ["get", [_uid, ""]];
|
|
if (_account isEqualTo createHashMap) exitWith {
|
|
_result set ["message", "Personal account could not be loaded for medical billing."];
|
|
_result
|
|
};
|
|
|
|
private _source = "";
|
|
if ((_account getOrDefault ["bank", 0]) >= _amount) then {
|
|
_source = "bank";
|
|
} else {
|
|
if ((_account getOrDefault ["cash", 0]) >= _amount) then {
|
|
_source = "cash";
|
|
};
|
|
};
|
|
|
|
if (_source isEqualTo "") exitWith {
|
|
_result set ["fallbackEligible", true];
|
|
_result set ["message", "Personal bank and cash balances cannot cover this medical service."];
|
|
_result
|
|
};
|
|
|
|
private _charge = EGVAR(bank,BankStore) call ["chargeCheckout", [_uid, _source, _amount, true]];
|
|
if !(_charge getOrDefault ["success", false]) exitWith {
|
|
_result set ["message", _charge getOrDefault ["message", "Personal funds could not be charged for medical service."]];
|
|
_result
|
|
};
|
|
|
|
private _patch = _charge getOrDefault ["patch", createHashMap];
|
|
if (_patch isNotEqualTo createHashMap && { !(isNil QEGVAR(bank,BankMessenger)) }) then {
|
|
if (isNil QEGVAR(common,EventBus)) then {
|
|
EGVAR(bank,BankMessenger) call ["sendAccountSync", [_uid, _patch]];
|
|
} else {
|
|
EGVAR(common,EventBus) call ["emit", [
|
|
"bank.account.sync.requested",
|
|
createHashMapFromArray [
|
|
["uid", _uid],
|
|
["account", +_patch]
|
|
],
|
|
createHashMapFromArray [["source", "economy"]]
|
|
]];
|
|
};
|
|
};
|
|
|
|
private _savedAccount = EGVAR(bank,BankStore) call ["save", [_uid]];
|
|
if (_savedAccount isEqualTo createHashMap) then {
|
|
["ERROR", format ["Medical charge for %1 succeeded in hot bank state, but durable bank save failed.", _uid]] call EFUNC(common,log);
|
|
};
|
|
|
|
_result set ["success", true];
|
|
_result set ["source", _source];
|
|
_result set ["message", ""];
|
|
_result
|
|
}],
|
|
["chargeMedicalService", {
|
|
params [
|
|
["_unit", objNull, [objNull]],
|
|
["_amount", 0, [0]],
|
|
["_serviceLabel", "Medical service", [""]],
|
|
["_requirePayment", true, [true]]
|
|
];
|
|
|
|
if (isNull _unit) exitWith {
|
|
["WARNING", format ["Invalid unit provided: %1", (name _unit)], nil, nil] call EFUNC(common,log);
|
|
false
|
|
};
|
|
private _uid = getPlayerUID _unit;
|
|
if (_uid isEqualTo "") exitWith {
|
|
["WARNING", "Unable to charge medical service for unit without UID.", nil, nil] call EFUNC(common,log);
|
|
!_requirePayment
|
|
};
|
|
|
|
if (_amount <= 0) exitWith { true };
|
|
|
|
private _personalCharge = _self call ["chargePlayer", [_uid, _amount]];
|
|
if (_personalCharge getOrDefault ["success", false]) exitWith {
|
|
private _sourceLabel = ["cash", "bank"] select ((_personalCharge getOrDefault ["source", "bank"]) isEqualTo "bank");
|
|
_self call ["notify", [_unit, "info", "Medical Billing", format ["%1 charged $%2 from your %3.", _serviceLabel, [_amount] call EFUNC(common,formatNumber), _sourceLabel]]];
|
|
true
|
|
};
|
|
|
|
if !(_personalCharge getOrDefault ["fallbackEligible", false]) exitWith {
|
|
private _message = _personalCharge getOrDefault ["message", "Personal funds could not be charged for medical service."];
|
|
_self call ["notify", [_unit, "danger", "Medical Billing", _message]];
|
|
!_requirePayment
|
|
};
|
|
|
|
if (isNil QGVAR(SEconomyStore)) exitWith {
|
|
["ERROR", "Service economy store unavailable for medical organization fallback charge.", nil, nil] call EFUNC(common,log);
|
|
_self call ["notify", [_unit, "danger", "Medical Billing", "Organization billing is unavailable. Medical service cannot complete."]];
|
|
!_requirePayment
|
|
};
|
|
|
|
private _chargeResult = GVAR(SEconomyStore) call ["chargeOrg", [_unit, _amount, "Medical", true]];
|
|
if !(_chargeResult getOrDefault ["success", false]) exitWith {
|
|
private _message = _chargeResult getOrDefault ["message", "Organization funds cannot cover this medical service."];
|
|
_self call ["notify", [_unit, "danger", "Medical Billing", _message]];
|
|
!_requirePayment
|
|
};
|
|
|
|
_self call ["notify", [_unit, "info", "Medical Billing", format ["Personal funds could not cover %1. Organization charged $%2; repay it through your organization credit line.", _serviceLabel, [_amount] call EFUNC(common,formatNumber)]]];
|
|
true
|
|
}],
|
|
["onHealed", {
|
|
params [["_unit", objNull, [objNull]]];
|
|
|
|
private _healCost = _self call ["numberSetting", ["medicalHealCost", 100]];
|
|
if !(_self call ["chargeMedicalService", [_unit, _healCost, "Medical service", true]]) exitWith {};
|
|
|
|
[CRPC(actor,onActorHealed), [], _unit] call CFUNC(targetEvent);
|
|
}],
|
|
["onRespawn", {
|
|
params [["_unit", objNull, [objNull]], ["_corpse", objNull, [objNull]], ["_uid", "", [""]]];
|
|
|
|
private _loadout = [[], [], [], ["U_BG_Guerrilla_6_1", []], [], [], "", "", [], ["", "", "", "", "", ""]];
|
|
private _medSpawn = (GVAR(occupancyTriggers) select { !(GETVAR(_x,isOccupied,false)) }) param [0, objNull];
|
|
private _medSpawnObj = _medSpawn getVariable ["linkedObject", objNull];
|
|
private _medSpawnPos = (getPosATL _medSpawnObj) vectorAdd [0.05, -0.125, 0.45];
|
|
private _medSpawnDir = getDir _medSpawnObj;
|
|
|
|
deleteVehicle _corpse;
|
|
|
|
private _player = [_uid] call EFUNC(common,getPlayer);
|
|
private _spawnCost = _self call ["numberSetting", ["medicalSpawnCost", GVAR(SpawnCost)]];
|
|
_self call ["chargeMedicalService", [_player, _spawnCost, "Medical spawn", false]];
|
|
[CRPC(actor,onActorRespawn), [_loadout, _medSpawnPos, _medSpawnDir], _player] call CFUNC(targetEvent);
|
|
}],
|
|
["onKilled", {
|
|
params [["_unit", objNull, [objNull]]];
|
|
|
|
private _unitPos = getPosATL _unit;
|
|
private _bodyBag = createVehicle ["forge_bodyBag", _unitPos, [], 0, "NONE"];
|
|
|
|
_self call ["saveWeapons", [_unit]];
|
|
_self call ["moveInventory", [_unit, _bodyBag]];
|
|
}],
|
|
["saveWeapons", {
|
|
params [["_unit", objNull, [objNull]]];
|
|
|
|
private _droppedWeapons = [];
|
|
private _droppedItems = [];
|
|
|
|
_droppedWeapons pushBack (primaryWeapon _unit);
|
|
_droppedItems append (primaryWeaponItems _unit);
|
|
_droppedItems append (primaryWeaponMagazine _unit);
|
|
_droppedWeapons pushBack (secondaryWeapon _unit);
|
|
_droppedItems append (secondaryWeaponItems _unit);
|
|
_droppedItems append (secondaryWeaponMagazine _unit);
|
|
|
|
if (isPlayer _unit) then { _droppedItems pushBack (goggles _unit); };
|
|
if (currentWeapon _unit isEqualTo handgunWeapon _unit) then {
|
|
_droppedWeapons pushBack (handgunWeapon _unit);
|
|
_droppedItems append (handgunItems _unit);
|
|
_droppedItems append (handgunMagazine _unit);
|
|
};
|
|
|
|
_unit setVariable [QGVAR(droppedWeapons), _droppedWeapons, true];
|
|
_unit setVariable [QGVAR(droppedItems), _droppedItems, true];
|
|
}],
|
|
["moveInventory", {
|
|
params [["_unit", objNull, [objNull]], ["_bodyBag", objNull, [objNull]]];
|
|
|
|
private _items = [];
|
|
private _weapons = [];
|
|
private _backpack = backpack _unit;
|
|
private _nearHolders = _bodyBag nearObjects ["WeaponHolderSimulated", 3];
|
|
|
|
_items pushBack (headgear _unit);
|
|
_items pushBack (uniform _unit);
|
|
_items append (uniformItems _unit);
|
|
_items pushBack (vest _unit);
|
|
_items append (vestItems _unit);
|
|
_items append (backpackItems _unit);
|
|
_weapons pushBack (primaryWeapon _unit);
|
|
_items append (primaryWeaponItems _unit);
|
|
_items append (primaryWeaponMagazine _unit);
|
|
_weapons pushBack (secondaryWeapon _unit);
|
|
_items append (secondaryWeaponItems _unit);
|
|
_items append (secondaryWeaponMagazine _unit);
|
|
_weapons pushBack (handgunWeapon _unit);
|
|
_items append (handgunItems _unit);
|
|
_items append (handgunMagazine _unit);
|
|
_weapons append (_unit getVariable [QGVAR(droppedWeapons), []]);
|
|
_items append (_unit getVariable [QGVAR(droppedItems), []]);
|
|
_items append (assignedItems _unit);
|
|
_items pushBack (_unit call CFUNC(binocularMagazine));
|
|
|
|
if !((goggles _unit ) in (_unit getVariable [QGVAR(droppedItems), []])) then { _items pushBack (goggles _unit); };
|
|
|
|
_items = _items select { _x isNotEqualTo "" };
|
|
_weapons = _weapons select { _x isNotEqualTo "" };
|
|
|
|
{ _bodyBag addItemCargoGlobal [_x, 1] } forEach _items;
|
|
|
|
{
|
|
private _weaponNonPresent = [_x] call CFUNC(getNonPresetClass);
|
|
if (_weaponNonPresent == "") then { _weaponNonPresent = _x; };
|
|
_bodyBag addWeaponCargoGlobal [_weaponNonPresent, 1];
|
|
} forEach _weapons;
|
|
|
|
if (_backpack isNotEqualTo "") then {
|
|
private _backpackNonPresent = [_backpack, "CfgVehicles"] call CFUNC(getNonPresetClass);
|
|
if (_backpackNonPresent == "") then { _backpackNonPresent = _backpack; };
|
|
_bodyBag addItemCargoGlobal [_backpackNonPresent, 1];
|
|
};
|
|
|
|
{
|
|
private _holderWeapons = ((getWeaponCargo _x) select 0) select { _x in _weapons };
|
|
if (_holderWeapons isNotEqualTo []) then { deleteVehicle _x; };
|
|
} forEach _nearHolders;
|
|
}]
|
|
]];
|
|
|
|
SETMVAR(FORGE_MEconomyStore,GVAR(MEconomyStore));
|
|
GVAR(MEconomyStore)
|