Updated Docs #9
@ -2,7 +2,8 @@
|
||||
|
||||
## Overview
|
||||
The garage addon provides player vehicle storage UI, vehicle store/retrieve
|
||||
actions, and virtual garage state on the client.
|
||||
actions, selected nearby vehicle service requests, and virtual garage state on
|
||||
the client.
|
||||
|
||||
## Dependencies
|
||||
- `forge_client_common`
|
||||
@ -17,8 +18,8 @@ actions, and virtual garage state on the client.
|
||||
details.
|
||||
- `fnc_initContextService.sqf` gathers nearby/current vehicle context.
|
||||
- `fnc_initPayloadService.sqf` builds browser hydrate payloads.
|
||||
- `fnc_initActionService.sqf` sends store/retrieve requests and handles action
|
||||
responses.
|
||||
- `fnc_initActionService.sqf` sends store/retrieve requests, forwards selected
|
||||
nearby vehicle refuel/repair service requests, and handles action responses.
|
||||
- `fnc_initUIBridge.sqf` pushes hydrate/sync events to the browser.
|
||||
- `fnc_openUI.sqf` opens `RscGarage`.
|
||||
- `fnc_openVG.sqf` opens the Arma garage-style virtual garage view.
|
||||
@ -28,8 +29,15 @@ actions, and virtual garage state on the client.
|
||||
- `garage::refresh`
|
||||
- `garage::vehicle::retrieve::request`
|
||||
- `garage::vehicle::store::request`
|
||||
- `garage::vehicle::refuel::request`
|
||||
- `garage::vehicle::repair::request`
|
||||
- `garage::close`
|
||||
|
||||
## Runtime Notes
|
||||
The client builds vehicle context and sends requests. The server garage addon
|
||||
and extension own stored vehicle state.
|
||||
|
||||
Refuel and repair buttons are available from the selected vehicle detail panel
|
||||
for nearby world vehicles. Stored records must be retrieved before they can be
|
||||
serviced because fuel and repair operate on live vehicle objects. Service
|
||||
billing is handled by the server economy addon and charges organization funds.
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
* File: fnc_handleUIEvents.sqf
|
||||
* Author: IDSolutions
|
||||
* Date: 2025-12-16
|
||||
* Last Update: 2026-01-30
|
||||
* Last Update: 2026-04-18
|
||||
* Public: No
|
||||
*
|
||||
* Description:
|
||||
@ -53,6 +53,16 @@ switch (_event) do {
|
||||
GVAR(GarageActionService) call ["handleStoreRequest", [_data]];
|
||||
};
|
||||
};
|
||||
case "garage::vehicle::refuel::request": {
|
||||
if !(isNil QGVAR(GarageActionService)) then {
|
||||
GVAR(GarageActionService) call ["handleRefuelRequest", [_data]];
|
||||
};
|
||||
};
|
||||
case "garage::vehicle::repair::request": {
|
||||
if !(isNil QGVAR(GarageActionService)) then {
|
||||
GVAR(GarageActionService) call ["handleRepairRequest", [_data]];
|
||||
};
|
||||
};
|
||||
case "garage::refresh": {
|
||||
if !(isNil QGVAR(GarageUIBridge)) then {
|
||||
GVAR(GarageUIBridge) call ["refreshGarage", []];
|
||||
|
||||
@ -4,10 +4,12 @@
|
||||
* File: fnc_initActionService.sqf
|
||||
* Author: IDSolutions
|
||||
* Date: 2026-03-27
|
||||
* Last Update: 2026-04-18
|
||||
* Public: No
|
||||
*
|
||||
* Description:
|
||||
* Initializes the garage action service for retrieve and store world actions.
|
||||
* Initializes the garage action service for retrieve, store, refuel, and
|
||||
* repair world actions.
|
||||
*
|
||||
* Arguments:
|
||||
* None
|
||||
@ -26,6 +28,52 @@ GVAR(GarageActionServiceBaseClass) = compileFinal createHashMapFromArray [
|
||||
_self set ["pendingStoreVehicle", objNull];
|
||||
_self set ["pendingRetrieve", createHashMap];
|
||||
}],
|
||||
["sendServiceResult", compileFinal {
|
||||
params [["_action", "", [""]], ["_success", false, [false]], ["_message", "", [""]]];
|
||||
|
||||
private _event = ["garage::service::failure", "garage::service::success"] select _success;
|
||||
GVAR(GarageUIBridge) call ["sendEvent", [_event, createHashMapFromArray [["action", _action], ["message", _message]]]];
|
||||
}],
|
||||
["refreshAfterService", compileFinal {
|
||||
[] spawn {
|
||||
sleep 0.75;
|
||||
if !(isNil QGVAR(GarageUIBridge)) then {
|
||||
GVAR(GarageUIBridge) call ["refreshGarage", []];
|
||||
};
|
||||
};
|
||||
}],
|
||||
["resolveServiceVehicle", compileFinal {
|
||||
params [["_data", createHashMap, [createHashMap]], ["_action", "service", [""]]];
|
||||
|
||||
private _netId = _data getOrDefault ["netId", ""];
|
||||
if (_netId isEqualTo "") exitWith {
|
||||
_self call ["sendServiceResult", [_action, false, "Select a nearby vehicle first."]];
|
||||
objNull
|
||||
};
|
||||
|
||||
private _vehicle = objectFromNetId _netId;
|
||||
if (isNull _vehicle) exitWith {
|
||||
_self call ["sendServiceResult", [_action, false, "The selected vehicle is no longer available."]];
|
||||
objNull
|
||||
};
|
||||
|
||||
if !(_vehicle isKindOf "Car" || { _vehicle isKindOf "Tank" } || { _vehicle isKindOf "Air" } || { _vehicle isKindOf "Ship" }) exitWith {
|
||||
_self call ["sendServiceResult", [_action, false, "Selected object is not a serviceable vehicle."]];
|
||||
objNull
|
||||
};
|
||||
|
||||
_vehicle
|
||||
}],
|
||||
["vehicleNeedsRepair", compileFinal {
|
||||
params [["_vehicle", objNull, [objNull]]];
|
||||
|
||||
if (isNull _vehicle) exitWith { false };
|
||||
if ((damage _vehicle) > 0.001) exitWith { true };
|
||||
|
||||
private _rawHitPoints = getAllHitPointsDamage _vehicle;
|
||||
private _hitPointValues = if (_rawHitPoints isEqualType [] && { count _rawHitPoints >= 3 }) then { _rawHitPoints param [2, []] } else { [] };
|
||||
({ _x > 0.001 } count _hitPointValues) > 0
|
||||
}],
|
||||
["handleRetrieveRequest", compileFinal {
|
||||
params [["_data", createHashMap, [createHashMap]]];
|
||||
|
||||
@ -97,6 +145,38 @@ GVAR(GarageActionServiceBaseClass) = compileFinal createHashMapFromArray [
|
||||
_self set ["pendingStoreVehicle", _vehicle];
|
||||
[SRPC(garage,requestStoreVehicle), [getPlayerUID player, typeOf _vehicle, fuel _vehicle, damage _vehicle, _hitPointsJson]] call CFUNC(serverEvent);
|
||||
}],
|
||||
["handleRefuelRequest", compileFinal {
|
||||
params [["_data", createHashMap, [createHashMap]]];
|
||||
|
||||
private _vehicle = _self call ["resolveServiceVehicle", [_data, "refuel"]];
|
||||
if (isNull _vehicle) exitWith { false };
|
||||
|
||||
if ((fuel _vehicle) >= 0.999) exitWith {
|
||||
_self call ["sendServiceResult", ["refuel", false, "Vehicle fuel tank is already full."]];
|
||||
false
|
||||
};
|
||||
|
||||
[SRPC(economy,RefuelService), [_vehicle, player]] call CFUNC(serverEvent);
|
||||
_self call ["sendServiceResult", ["refuel", true, "Refuel request sent. Billing result will appear as a notification."]];
|
||||
_self call ["refreshAfterService", []];
|
||||
true
|
||||
}],
|
||||
["handleRepairRequest", compileFinal {
|
||||
params [["_data", createHashMap, [createHashMap]]];
|
||||
|
||||
private _vehicle = _self call ["resolveServiceVehicle", [_data, "repair"]];
|
||||
if (isNull _vehicle) exitWith { false };
|
||||
|
||||
if !(_self call ["vehicleNeedsRepair", [_vehicle]]) exitWith {
|
||||
_self call ["sendServiceResult", ["repair", false, "Vehicle has no reported damage."]];
|
||||
false
|
||||
};
|
||||
|
||||
[SRPC(economy,RepairService), [_vehicle, player, -1]] call CFUNC(serverEvent);
|
||||
_self call ["sendServiceResult", ["repair", true, "Repair request sent. Billing result will appear as a notification."]];
|
||||
_self call ["refreshAfterService", []];
|
||||
true
|
||||
}],
|
||||
["handleActionResponse", compileFinal {
|
||||
params [["_payload", createHashMap, [createHashMap]]];
|
||||
|
||||
|
||||
File diff suppressed because one or more lines are too long
@ -23,6 +23,14 @@
|
||||
return bridge.send("garage::vehicle::store::request", payload);
|
||||
}
|
||||
|
||||
function requestRefuel(payload) {
|
||||
return bridge.send("garage::vehicle::refuel::request", payload);
|
||||
}
|
||||
|
||||
function requestRepair(payload) {
|
||||
return bridge.send("garage::vehicle::repair::request", payload);
|
||||
}
|
||||
|
||||
function notifyReady() {
|
||||
return bridge.ready({ loaded: true });
|
||||
}
|
||||
@ -75,11 +83,33 @@
|
||||
}
|
||||
});
|
||||
|
||||
bridge.on("garage::service::success", (payloadData) => {
|
||||
store.finishAction();
|
||||
if (GarageApp.actions) {
|
||||
GarageApp.actions.showNotice(
|
||||
"success",
|
||||
payloadData.message || "Service request sent.",
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
bridge.on("garage::service::failure", (payloadData) => {
|
||||
store.finishAction();
|
||||
if (GarageApp.actions) {
|
||||
GarageApp.actions.showNotice(
|
||||
"error",
|
||||
payloadData.message || "Unable to service vehicle.",
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
GarageApp.bridge = {
|
||||
notifyReady,
|
||||
receive: bridge.receive,
|
||||
requestClose,
|
||||
requestRefresh,
|
||||
requestRefuel,
|
||||
requestRepair,
|
||||
requestRetrieve,
|
||||
requestStore,
|
||||
sendEvent: bridge.send,
|
||||
|
||||
@ -343,11 +343,16 @@
|
||||
|
||||
const isStored = currentSelection.entryKind === "stored";
|
||||
const pendingAction = String(state.pendingAction || "");
|
||||
const isBusy =
|
||||
pendingAction === "retrieve" || pendingAction === "store";
|
||||
const isBusy = Boolean(pendingAction);
|
||||
const canRetrieve = isStored && !session.spawnBlocked && !isBusy;
|
||||
const canStore =
|
||||
!isStored && currentSelection.isEmpty !== false && !isBusy;
|
||||
const canRefuel =
|
||||
!isStored && Number(currentSelection.fuel || 0) < 0.999 && !isBusy;
|
||||
const canRepair =
|
||||
!isStored &&
|
||||
Number(currentSelection.health || 0) < 0.999 &&
|
||||
!isBusy;
|
||||
|
||||
return h(
|
||||
"section",
|
||||
@ -461,6 +466,34 @@
|
||||
? "Storing..."
|
||||
: "Store Vehicle",
|
||||
),
|
||||
h(
|
||||
"button",
|
||||
{
|
||||
type: "button",
|
||||
className:
|
||||
"garage-btn garage-btn-secondary",
|
||||
disabled: !canRefuel,
|
||||
onClick: () =>
|
||||
actions.requestRefuelSelected(),
|
||||
},
|
||||
pendingAction === "refuel"
|
||||
? "Refueling..."
|
||||
: "Refuel",
|
||||
),
|
||||
h(
|
||||
"button",
|
||||
{
|
||||
type: "button",
|
||||
className:
|
||||
"garage-btn garage-btn-secondary",
|
||||
disabled: !canRepair,
|
||||
onClick: () =>
|
||||
actions.requestRepairSelected(),
|
||||
},
|
||||
pendingAction === "repair"
|
||||
? "Repairing..."
|
||||
: "Repair",
|
||||
),
|
||||
h(
|
||||
"button",
|
||||
{
|
||||
@ -479,10 +512,10 @@
|
||||
isStored
|
||||
? session.spawnBlocked
|
||||
? "The garage spawn lane is currently blocked."
|
||||
: "Retrieve this stored vehicle into the active spawn lane."
|
||||
: "Retrieve this stored vehicle into the active spawn lane before refuel or repair service."
|
||||
: currentSelection.isEmpty === false
|
||||
? "Only empty nearby vehicles can be stored."
|
||||
: "Store this nearby vehicle back into persistent garage storage.",
|
||||
: "Store this nearby vehicle or request organization-billed refuel and repair service.",
|
||||
),
|
||||
),
|
||||
h(
|
||||
|
||||
@ -159,6 +159,70 @@
|
||||
return true;
|
||||
}
|
||||
|
||||
function requestRefuelSelected() {
|
||||
const selectedEntry = getSelectedEntry();
|
||||
if (!selectedEntry || selectedEntry.entryKind !== "nearby") {
|
||||
showNotice("error", "Select a nearby vehicle to refuel.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (Number(selectedEntry.fuel || 0) >= 0.999) {
|
||||
showNotice("error", "Vehicle fuel tank is already full.");
|
||||
return false;
|
||||
}
|
||||
|
||||
const bridge = GarageApp.bridge;
|
||||
if (!bridge || typeof bridge.requestRefuel !== "function") {
|
||||
showNotice("error", "Garage refuel bridge is unavailable.");
|
||||
return false;
|
||||
}
|
||||
|
||||
store.startAction("refuel");
|
||||
const sent = bridge.requestRefuel({
|
||||
netId: selectedEntry.netId || "",
|
||||
});
|
||||
|
||||
if (!sent) {
|
||||
store.finishAction();
|
||||
showNotice("error", "Garage refuel bridge is unavailable.");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function requestRepairSelected() {
|
||||
const selectedEntry = getSelectedEntry();
|
||||
if (!selectedEntry || selectedEntry.entryKind !== "nearby") {
|
||||
showNotice("error", "Select a nearby vehicle to repair.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (Number(selectedEntry.health || 0) >= 0.999) {
|
||||
showNotice("error", "Vehicle has no reported damage.");
|
||||
return false;
|
||||
}
|
||||
|
||||
const bridge = GarageApp.bridge;
|
||||
if (!bridge || typeof bridge.requestRepair !== "function") {
|
||||
showNotice("error", "Garage repair bridge is unavailable.");
|
||||
return false;
|
||||
}
|
||||
|
||||
store.startAction("repair");
|
||||
const sent = bridge.requestRepair({
|
||||
netId: selectedEntry.netId || "",
|
||||
});
|
||||
|
||||
if (!sent) {
|
||||
store.finishAction();
|
||||
showNotice("error", "Garage repair bridge is unavailable.");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
GarageApp.actions = {
|
||||
showNotice,
|
||||
closeGarage,
|
||||
@ -168,6 +232,8 @@
|
||||
selectCategory,
|
||||
selectEntry,
|
||||
getSelectedEntry,
|
||||
requestRefuelSelected,
|
||||
requestRepairSelected,
|
||||
requestRetrieveSelected,
|
||||
requestStoreSelected,
|
||||
};
|
||||
|
||||
@ -30,9 +30,10 @@ charges such as repairs.
|
||||
shared org-charge helper can also record member debt for medical fallback.
|
||||
|
||||
## Event Surface
|
||||
The addon registers CBA server events for fuel start/tick/stop, repair service,
|
||||
player killed, player respawn, and healing. Medical store initialization runs
|
||||
after post-init to discover configured medical spawn objects.
|
||||
The addon registers CBA server events for fuel start/tick/stop, direct refuel
|
||||
service, repair service, player killed, player respawn, and healing. Medical
|
||||
store initialization runs after post-init to discover configured medical spawn
|
||||
objects.
|
||||
|
||||
Repair service requests use:
|
||||
|
||||
@ -42,6 +43,14 @@ Repair service requests use:
|
||||
|
||||
`_cost` is optional. Passing `-1` uses the configured service repair cost.
|
||||
|
||||
Garage refuel service requests use:
|
||||
|
||||
```sqf
|
||||
[QEGVAR(economy,RefuelService), [_target, _unit]] call CBA_fnc_serverEvent;
|
||||
```
|
||||
|
||||
This fills the selected live vehicle after organization billing succeeds.
|
||||
|
||||
## Billing Rules
|
||||
Economy does not own durable money state. It coordinates Arma-world effects
|
||||
after the relevant hot-cache charge succeeds.
|
||||
@ -56,6 +65,10 @@ Fuel and repair services are organization-funded:
|
||||
5. If the charge fails, do not complete the service. Refueling rolls the target
|
||||
back to its starting fuel level; repairs are not applied.
|
||||
|
||||
Direct refuel service requests, such as those from the garage UI, calculate
|
||||
the missing fuel from `fuelCapacity`, charge the organization, and fill the
|
||||
vehicle only after the charge succeeds.
|
||||
|
||||
Medical services are player-funded first:
|
||||
|
||||
1. Load the player's bank hot state.
|
||||
|
||||
@ -33,6 +33,11 @@ if (isNil QGVAR(SEconomyStore)) then { call FUNC(initSEconomyStore); };
|
||||
GVAR(SEconomyStore) call ["repair", [_target, _unit, _cost]];
|
||||
}] call CFUNC(addEventHandler);
|
||||
|
||||
[QGVAR(RefuelService), {
|
||||
params ["_target", "_unit"];
|
||||
GVAR(FEconomyStore) call ["refuel", [_target, _unit]];
|
||||
}] call CFUNC(addEventHandler);
|
||||
|
||||
[QGVAR(onKilled), {
|
||||
params ["_unit"];
|
||||
GVAR(MEconomyStore) call ["onKilled", [_unit]];
|
||||
|
||||
@ -4,13 +4,14 @@
|
||||
* File: fnc_initFEconomyStore.sqf
|
||||
* Author: IDSolutions
|
||||
* Date: 2025-12-20
|
||||
* Last Update: 2026-01-03
|
||||
* Last Update: 2026-04-18
|
||||
* Public: No
|
||||
*
|
||||
* Description:
|
||||
* Initializes the fuel economy store. Active refueling sessions remain
|
||||
* server-local; payment is routed through the organization extension hot
|
||||
* cache.
|
||||
* cache. Garage service refuels use the same organization billing path
|
||||
* and only fill the vehicle after the charge succeeds.
|
||||
*
|
||||
* Parameter(s):
|
||||
* N/A
|
||||
@ -53,6 +54,43 @@ GVAR(FEconomyStore) = createHashMapObject [[
|
||||
SETVAR(_target,liters,0);
|
||||
true
|
||||
}],
|
||||
["refuel", {
|
||||
params [["_target", objNull, [objNull]], ["_unit", objNull, [objNull]]];
|
||||
|
||||
if (isNull _target || { isNull _unit }) exitWith { false };
|
||||
|
||||
private _currentFuel = fuel _target;
|
||||
private _missingFuel = (1 - _currentFuel) max 0 min 1;
|
||||
if (_missingFuel <= 0.001) exitWith {
|
||||
[CRPC(notifications,recieveNotification), ["info", "Refueling", "Vehicle fuel tank is already full."], _unit] call CFUNC(targetEvent);
|
||||
false
|
||||
};
|
||||
|
||||
if (isNil QGVAR(SEconomyStore)) exitWith {
|
||||
["ERROR", "Service economy store unavailable for garage refueling charge.", nil, nil] call EFUNC(common,log);
|
||||
[CRPC(notifications,recieveNotification), ["danger", "Refueling", "Organization billing is unavailable. Refueling was not completed."], _unit] call CFUNC(targetEvent);
|
||||
false
|
||||
};
|
||||
|
||||
private _fuelCapacity = getNumber (configOf _target >> "fuelCapacity");
|
||||
if (_fuelCapacity <= 0) then { _fuelCapacity = 100; };
|
||||
|
||||
private _totalLiters = _missingFuel * _fuelCapacity;
|
||||
private _totalCost = _totalLiters * GVAR(FuelCost);
|
||||
private _chargeResult = GVAR(SEconomyStore) call ["chargeOrg", [_unit, _totalCost, "Refueling"]];
|
||||
if !(_chargeResult getOrDefault ["success", false]) exitWith {
|
||||
[CRPC(notifications,recieveNotification), ["danger", "Refueling", _chargeResult getOrDefault ["message", "Organization funds cannot cover this refuel. Refueling was not completed."]], _unit] call CFUNC(targetEvent);
|
||||
false
|
||||
};
|
||||
|
||||
_target setFuel 1;
|
||||
SETVAR(_target,liters,0);
|
||||
|
||||
private _formattedTotalCost = [_totalCost] call EFUNC(common,formatNumber);
|
||||
private _formattedTotalLiters = _totalLiters toFixed 2;
|
||||
[CRPC(notifications,recieveNotification), ["info", "Refueling", format ["Refueling complete: %1L<br />Organization charged $%2.", _formattedTotalLiters, _formattedTotalCost]], _unit] call CFUNC(targetEvent);
|
||||
true
|
||||
}],
|
||||
["stop", {
|
||||
params ["_source", "_target"];
|
||||
|
||||
|
||||
@ -1,7 +1,8 @@
|
||||
# Client Garage Usage Guide
|
||||
|
||||
The client garage addon provides player vehicle storage UI, vehicle
|
||||
store/retrieve actions, vehicle context building, and the virtual garage view.
|
||||
store/retrieve actions, selected nearby vehicle service requests, vehicle
|
||||
context building, and the virtual garage view.
|
||||
|
||||
## Open Garage UI
|
||||
|
||||
@ -31,7 +32,7 @@ available vehicle lists from the virtual garage repository.
|
||||
| `GarageHelperService` | Vehicle names, hit points, and payload helpers. |
|
||||
| `GarageContextService` | Nearby/current vehicle context. |
|
||||
| `GaragePayloadService` | Browser hydrate payload construction. |
|
||||
| `GarageActionService` | Store/retrieve request handling. |
|
||||
| `GarageActionService` | Store/retrieve request handling and selected nearby vehicle refuel/repair request forwarding. |
|
||||
| `GarageUIBridge` | Browser ready, hydrate, and sync delivery. |
|
||||
|
||||
## Browser Events
|
||||
@ -42,6 +43,8 @@ available vehicle lists from the virtual garage repository.
|
||||
| `garage::refresh` | Send current garage payload as `garage::sync`. |
|
||||
| `garage::vehicle::retrieve::request` | Forward retrieve request through the action service. |
|
||||
| `garage::vehicle::store::request` | Forward store request through the action service. |
|
||||
| `garage::vehicle::refuel::request` | Forward selected nearby vehicle refuel request to the server economy service. |
|
||||
| `garage::vehicle::repair::request` | Forward selected nearby vehicle repair request to the server economy service. |
|
||||
| `garage::close` | Dispose bridge screen state and close the display. |
|
||||
|
||||
## Browser Response Events
|
||||
@ -50,10 +53,22 @@ available vehicle lists from the virtual garage repository.
|
||||
| --- | --- |
|
||||
| `garage::hydrate` | Initial vehicle and session payload. |
|
||||
| `garage::sync` | Refreshed vehicle payload. |
|
||||
| `garage::service::success` | Browser notice for accepted refuel/repair requests. |
|
||||
| `garage::service::failure` | Browser notice for rejected refuel/repair requests. |
|
||||
|
||||
Server action responses are handled by the action service and notification
|
||||
flow.
|
||||
|
||||
## Vehicle Service
|
||||
|
||||
The selected vehicle detail panel includes refuel and repair actions for nearby
|
||||
world vehicles. Stored records must be retrieved first because server economy
|
||||
services operate on live vehicle objects, not stored garage records.
|
||||
|
||||
Refuel requests use the server economy `RefuelService` event. Repair requests
|
||||
use the server economy `RepairService` event. Both services are billed by the
|
||||
server economy addon through organization funds.
|
||||
|
||||
## Mission Setup
|
||||
|
||||
Garage interactions are normally surfaced through the actor menu when nearby
|
||||
|
||||
@ -24,6 +24,11 @@ syncs the organization patch to online members. If organization funds cannot
|
||||
cover the refuel, the vehicle is rolled back to the fuel level it had when the
|
||||
session started.
|
||||
|
||||
Garage UI refuel requests use the server `RefuelService` event. The fuel store
|
||||
calculates missing fuel from the vehicle config `fuelCapacity`, charges the
|
||||
player's organization, and fills the vehicle only after the organization charge
|
||||
succeeds.
|
||||
|
||||
## Repair
|
||||
|
||||
Repair is organization-funded.
|
||||
@ -37,6 +42,9 @@ Use the repair service event:
|
||||
`_cost` is optional. Passing `-1` uses the configured service repair cost.
|
||||
The target is only repaired after the organization charge succeeds.
|
||||
|
||||
The client garage UI forwards selected nearby vehicle repair requests through
|
||||
the same event.
|
||||
|
||||
## Medical
|
||||
|
||||
Medical is player-funded first.
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user