Update framework mission configuration systems
This commit is contained in:
parent
6229f56ba4
commit
623f718caf
@ -79,14 +79,32 @@ switch (_event) do {
|
|||||||
hint "Transport destination is no longer available.";
|
hint "Transport destination is no longer available.";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
private _transportSetting = {
|
||||||
|
params [["_name", "", [""]], ["_default", 0, [0]]];
|
||||||
|
|
||||||
|
private _configDefault = _default;
|
||||||
|
private _missionConfig = missionConfigFile >> "CfgMissions";
|
||||||
|
if !(isClass _missionConfig) then { _missionConfig = configFile >> "CfgMissions"; };
|
||||||
|
private _serviceConfig = _missionConfig >> "ServicePricing";
|
||||||
|
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
|
||||||
|
};
|
||||||
|
|
||||||
private _options = createHashMapFromArray [
|
private _options = createHashMapFromArray [
|
||||||
["label", _data getOrDefault ["label", "Transport"]],
|
["label", _data getOrDefault ["label", "Transport"]],
|
||||||
["nodePrefix", _data getOrDefault ["nodePrefix", "transport"]],
|
["nodePrefix", _data getOrDefault ["nodePrefix", "transport"]],
|
||||||
["vehiclePrefix", _data getOrDefault ["vehiclePrefix", "transport_vehicle"]],
|
["vehiclePrefix", _data getOrDefault ["vehiclePrefix", "transport_vehicle"]],
|
||||||
["arrivalPrefix", _data getOrDefault ["arrivalPrefix", "transport_arrival"]],
|
["arrivalPrefix", _data getOrDefault ["arrivalPrefix", "transport_arrival"]],
|
||||||
["maxIndexedNodes", _data getOrDefault ["maxIndexedNodes", 10]],
|
["maxIndexedNodes", _data getOrDefault ["maxIndexedNodes", 10]],
|
||||||
["baseFare", _data getOrDefault ["baseFare", 100]],
|
["baseFare", _data getOrDefault ["baseFare", ["transportBaseFare", 100] call _transportSetting]],
|
||||||
["pricePerKm", _data getOrDefault ["pricePerKm", 50]],
|
["pricePerKm", _data getOrDefault ["pricePerKm", ["transportPricePerKm", 50] call _transportSetting]],
|
||||||
["cargoRadius", _data getOrDefault ["cargoRadius", 25]],
|
["cargoRadius", _data getOrDefault ["cargoRadius", 25]],
|
||||||
["includeCargo", _data getOrDefault ["includeCargo", true]]
|
["includeCargo", _data getOrDefault ["includeCargo", true]]
|
||||||
];
|
];
|
||||||
|
|||||||
@ -142,8 +142,25 @@ GVAR(ActorRepositoryBaseClass) = compileFinal createHashMapFromArray [
|
|||||||
if (_isTransport) then {
|
if (_isTransport) then {
|
||||||
private _fromTransportNode = _x;
|
private _fromTransportNode = _x;
|
||||||
private _maxIndexedNodes = _x getVariable ["transportMaxIndexedNodes", 10];
|
private _maxIndexedNodes = _x getVariable ["transportMaxIndexedNodes", 10];
|
||||||
private _baseFare = _x getVariable ["transportBaseFare", 100];
|
private _transportSetting = {
|
||||||
private _pricePerKm = _x getVariable ["transportPricePerKm", 50];
|
params [["_name", "", [""]], ["_default", 0, [0]]];
|
||||||
|
|
||||||
|
private _configDefault = _default;
|
||||||
|
private _missionConfig = missionConfigFile >> "CfgMissions";
|
||||||
|
if !(isClass _missionConfig) then { _missionConfig = configFile >> "CfgMissions"; };
|
||||||
|
private _serviceConfig = _missionConfig >> "ServicePricing";
|
||||||
|
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
|
||||||
|
};
|
||||||
|
private _baseFare = _x getVariable ["transportBaseFare", ["transportBaseFare", 100] call _transportSetting];
|
||||||
|
private _pricePerKm = _x getVariable ["transportPricePerKm", ["transportPricePerKm", 50] call _transportSetting];
|
||||||
private _vehiclePrefix = _x getVariable ["transportVehiclePrefix", format ["%1_vehicle", _transportPrefix]];
|
private _vehiclePrefix = _x getVariable ["transportVehiclePrefix", format ["%1_vehicle", _transportPrefix]];
|
||||||
private _arrivalPrefix = _x getVariable ["transportArrivalPrefix", format ["%1_arrival", _transportPrefix]];
|
private _arrivalPrefix = _x getVariable ["transportArrivalPrefix", format ["%1_arrival", _transportPrefix]];
|
||||||
private _nodeNames = [_transportPrefix];
|
private _nodeNames = [_transportPrefix];
|
||||||
|
|||||||
@ -151,10 +151,21 @@ GVAR(MissionSetupRepositoryBaseClass) = compileFinal createHashMapFromArray [
|
|||||||
private _paramOrDefault = {
|
private _paramOrDefault = {
|
||||||
params ["_varName", "_default"];
|
params ["_varName", "_default"];
|
||||||
|
|
||||||
private _value = missionNamespace getVariable [_varName, _default];
|
private _paramValue = [_varName, _default] call BIS_fnc_getParamValue;
|
||||||
|
private _value = missionNamespace getVariable [_varName, _paramValue];
|
||||||
if (_value isEqualType "") exitWith { parseNumber _value };
|
if (_value isEqualType "") exitWith { parseNumber _value };
|
||||||
_value
|
_value
|
||||||
};
|
};
|
||||||
|
private _serviceDefault = {
|
||||||
|
params ["_varName", "_default"];
|
||||||
|
|
||||||
|
private _serviceConfig = _missionConfig >> "ServicePricing";
|
||||||
|
if (isNumber (_serviceConfig >> _varName)) exitWith {
|
||||||
|
getNumber (_serviceConfig >> _varName)
|
||||||
|
};
|
||||||
|
|
||||||
|
_default
|
||||||
|
};
|
||||||
|
|
||||||
private _factions = [];
|
private _factions = [];
|
||||||
{
|
{
|
||||||
@ -197,6 +208,13 @@ GVAR(MissionSetupRepositoryBaseClass) = compileFinal createHashMapFromArray [
|
|||||||
["penaltyMax", ["penaltyMax", -25] call _paramOrDefault],
|
["penaltyMax", ["penaltyMax", -25] call _paramOrDefault],
|
||||||
["timeLimitMin", ["timeLimitMin", 600] call _paramOrDefault],
|
["timeLimitMin", ["timeLimitMin", 600] call _paramOrDefault],
|
||||||
["timeLimitMax", ["timeLimitMax", 900] call _paramOrDefault],
|
["timeLimitMax", ["timeLimitMax", 900] call _paramOrDefault],
|
||||||
|
["medicalSpawnCost", ["medicalSpawnCost", ["medicalSpawnCost", 100] call _serviceDefault] call _paramOrDefault],
|
||||||
|
["medicalHealCost", ["medicalHealCost", ["medicalHealCost", 100] call _serviceDefault] call _paramOrDefault],
|
||||||
|
["serviceRepairCost", ["serviceRepairCost", ["serviceRepairCost", 500] call _serviceDefault] call _paramOrDefault],
|
||||||
|
["serviceRearmCost", ["serviceRearmCost", ["serviceRearmCost", 500] call _serviceDefault] call _paramOrDefault],
|
||||||
|
["fuelCost", ["fuelCost", ["fuelCost", 5] call _serviceDefault] call _paramOrDefault],
|
||||||
|
["transportBaseFare", ["transportBaseFare", ["transportBaseFare", 100] call _serviceDefault] call _paramOrDefault],
|
||||||
|
["transportPricePerKm", ["transportPricePerKm", ["transportPricePerKm", 50] call _serviceDefault] call _paramOrDefault],
|
||||||
["generatorProvider", GETMVAR(forge_server_task_generatorProvider,"builtin")]
|
["generatorProvider", GETMVAR(forge_server_task_generatorProvider,"builtin")]
|
||||||
]]
|
]]
|
||||||
]
|
]
|
||||||
|
|||||||
@ -54,8 +54,8 @@ button {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.titlebar {
|
.titlebar {
|
||||||
min-height: 2.75rem;
|
min-height: 2.5rem;
|
||||||
padding: 0 1.35rem;
|
padding: 0 1.1rem;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
@ -98,18 +98,19 @@ option {
|
|||||||
|
|
||||||
.content {
|
.content {
|
||||||
min-height: 0;
|
min-height: 0;
|
||||||
padding: 1rem 1.25rem;
|
padding: 0.75rem 1rem;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.grid {
|
.grid {
|
||||||
max-width: 78rem;
|
width: min(94rem, 100%);
|
||||||
|
max-width: 94rem;
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: 1.1fr 0.9fr;
|
grid-template-columns: minmax(28rem, 1.35fr) minmax(18rem, 0.8fr) minmax(20rem, 0.85fr);
|
||||||
gap: 1rem;
|
gap: 0.75rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.panel {
|
.panel {
|
||||||
@ -120,22 +121,26 @@ option {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.panel-head {
|
.panel-head {
|
||||||
padding: 0.85rem 1rem;
|
padding: 0.65rem 0.85rem;
|
||||||
border-bottom: 1px solid var(--border);
|
border-bottom: 1px solid var(--border);
|
||||||
}
|
}
|
||||||
|
|
||||||
.panel-head h1,
|
.panel-head h1,
|
||||||
.panel-head h2 {
|
.panel-head h2 {
|
||||||
margin: 0.2rem 0 0;
|
margin: 0.2rem 0 0;
|
||||||
font-size: 1.18rem;
|
font-size: 1.02rem;
|
||||||
letter-spacing: 0;
|
letter-spacing: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.form {
|
.form {
|
||||||
padding: 0.9rem 1rem 1rem;
|
padding: 0.7rem 0.85rem 0.85rem;
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: 1fr 1fr;
|
grid-template-columns: 1fr 1fr;
|
||||||
gap: 0.68rem;
|
gap: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form.compact {
|
||||||
|
gap: 0.55rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.field {
|
.field {
|
||||||
@ -149,7 +154,7 @@ option {
|
|||||||
|
|
||||||
label {
|
label {
|
||||||
color: var(--text-subtle);
|
color: var(--text-subtle);
|
||||||
font-size: 0.68rem;
|
font-size: 0.62rem;
|
||||||
font-weight: 800;
|
font-weight: 800;
|
||||||
letter-spacing: 0.08em;
|
letter-spacing: 0.08em;
|
||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
@ -172,8 +177,8 @@ label {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.provider-toggle {
|
.provider-toggle {
|
||||||
min-height: 2.25rem;
|
min-height: 2rem;
|
||||||
padding: 0 0.75rem;
|
padding: 0 0.65rem;
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: auto 1fr;
|
grid-template-columns: auto 1fr;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
@ -249,8 +254,8 @@ label {
|
|||||||
input,
|
input,
|
||||||
select {
|
select {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
min-height: 2.25rem;
|
min-height: 2rem;
|
||||||
padding: 0 0.75rem;
|
padding: 0 0.65rem;
|
||||||
border: 1px solid var(--border);
|
border: 1px solid var(--border);
|
||||||
background: rgba(24, 31, 40, 0.9);
|
background: rgba(24, 31, 40, 0.9);
|
||||||
color: var(--text-main);
|
color: var(--text-main);
|
||||||
@ -264,16 +269,16 @@ button:focus-visible {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.summary {
|
.summary {
|
||||||
padding: 0.9rem 1rem 1rem;
|
padding: 0.7rem 0.85rem 0.85rem;
|
||||||
display: grid;
|
display: grid;
|
||||||
gap: 0.55rem;
|
gap: 0.42rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.summary-row {
|
.summary-row {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
gap: 1rem;
|
gap: 1rem;
|
||||||
padding-bottom: 0.55rem;
|
padding-bottom: 0.42rem;
|
||||||
border-bottom: 1px solid var(--border);
|
border-bottom: 1px solid var(--border);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -294,7 +299,7 @@ button:focus-visible {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.actions {
|
.actions {
|
||||||
padding: 0.75rem 1.25rem;
|
padding: 0.6rem 1rem;
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: flex-end;
|
justify-content: flex-end;
|
||||||
gap: 0.75rem;
|
gap: 0.75rem;
|
||||||
@ -303,7 +308,7 @@ button:focus-visible {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.btn {
|
.btn {
|
||||||
min-height: 2.25rem;
|
min-height: 2rem;
|
||||||
padding: 0.55rem 0.9rem;
|
padding: 0.55rem 0.9rem;
|
||||||
border: 1px solid var(--border-strong);
|
border: 1px solid var(--border-strong);
|
||||||
background: rgba(24, 31, 40, 0.9);
|
background: rgba(24, 31, 40, 0.9);
|
||||||
|
|||||||
@ -14,6 +14,13 @@
|
|||||||
penaltyMax: -25,
|
penaltyMax: -25,
|
||||||
timeLimitMin: 600,
|
timeLimitMin: 600,
|
||||||
timeLimitMax: 900,
|
timeLimitMax: 900,
|
||||||
|
medicalSpawnCost: 100,
|
||||||
|
medicalHealCost: 100,
|
||||||
|
serviceRepairCost: 500,
|
||||||
|
serviceRearmCost: 500,
|
||||||
|
fuelCost: 5,
|
||||||
|
transportBaseFare: 100,
|
||||||
|
transportPricePerKm: 50,
|
||||||
generatorProvider: "builtin",
|
generatorProvider: "builtin",
|
||||||
},
|
},
|
||||||
error: "",
|
error: "",
|
||||||
@ -47,6 +54,13 @@
|
|||||||
penaltyMax: fieldNumber("penaltyMax"),
|
penaltyMax: fieldNumber("penaltyMax"),
|
||||||
timeLimitMin: fieldNumber("timeLimitMin"),
|
timeLimitMin: fieldNumber("timeLimitMin"),
|
||||||
timeLimitMax: fieldNumber("timeLimitMax"),
|
timeLimitMax: fieldNumber("timeLimitMax"),
|
||||||
|
medicalSpawnCost: fieldNumber("medicalSpawnCost"),
|
||||||
|
medicalHealCost: fieldNumber("medicalHealCost"),
|
||||||
|
serviceRepairCost: fieldNumber("serviceRepairCost"),
|
||||||
|
serviceRearmCost: fieldNumber("serviceRearmCost"),
|
||||||
|
fuelCost: fieldNumber("fuelCost"),
|
||||||
|
transportBaseFare: fieldNumber("transportBaseFare"),
|
||||||
|
transportPricePerKm: fieldNumber("transportPricePerKm"),
|
||||||
generatorProvider: document.getElementById("generatorProviderCustom")?.checked ? "custom" : "builtin",
|
generatorProvider: document.getElementById("generatorProviderCustom")?.checked ? "custom" : "builtin",
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -86,6 +100,21 @@
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const costFields = [
|
||||||
|
settings.medicalSpawnCost,
|
||||||
|
settings.medicalHealCost,
|
||||||
|
settings.serviceRepairCost,
|
||||||
|
settings.serviceRearmCost,
|
||||||
|
settings.fuelCost,
|
||||||
|
settings.transportBaseFare,
|
||||||
|
settings.transportPricePerKm,
|
||||||
|
];
|
||||||
|
if (costFields.some((value) => value < 0)) {
|
||||||
|
state.error = "Service pricing cannot use negative values.";
|
||||||
|
render();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
state.error = "";
|
state.error = "";
|
||||||
send("missionSetup::apply", settings);
|
send("missionSetup::apply", settings);
|
||||||
}
|
}
|
||||||
@ -186,6 +215,43 @@
|
|||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
<aside class="panel">
|
||||||
|
<div class="panel-head">
|
||||||
|
<span class="kicker">Service Pricing</span>
|
||||||
|
<h2>Economy Settings</h2>
|
||||||
|
</div>
|
||||||
|
<div class="form compact">
|
||||||
|
<div class="field">
|
||||||
|
<label for="medicalSpawnCost">Medical Spawn</label>
|
||||||
|
<input id="medicalSpawnCost" type="number" min="0" step="50" value="${settings.medicalSpawnCost}" />
|
||||||
|
</div>
|
||||||
|
<div class="field">
|
||||||
|
<label for="medicalHealCost">Medical Heal</label>
|
||||||
|
<input id="medicalHealCost" type="number" min="0" step="50" value="${settings.medicalHealCost}" />
|
||||||
|
</div>
|
||||||
|
<div class="field">
|
||||||
|
<label for="serviceRepairCost">Repair</label>
|
||||||
|
<input id="serviceRepairCost" type="number" min="0" step="50" value="${settings.serviceRepairCost}" />
|
||||||
|
</div>
|
||||||
|
<div class="field">
|
||||||
|
<label for="serviceRearmCost">Rearm</label>
|
||||||
|
<input id="serviceRearmCost" type="number" min="0" step="50" value="${settings.serviceRearmCost}" />
|
||||||
|
</div>
|
||||||
|
<div class="field">
|
||||||
|
<label for="fuelCost">Fuel / Liter</label>
|
||||||
|
<input id="fuelCost" type="number" min="0" step="1" value="${settings.fuelCost}" />
|
||||||
|
</div>
|
||||||
|
<div class="field">
|
||||||
|
<label for="transportBaseFare">Transport Base</label>
|
||||||
|
<input id="transportBaseFare" type="number" min="0" step="25" value="${settings.transportBaseFare}" />
|
||||||
|
</div>
|
||||||
|
<div class="field wide">
|
||||||
|
<label for="transportPricePerKm">Transport / KM</label>
|
||||||
|
<input id="transportPricePerKm" type="number" min="0" step="25" value="${settings.transportPricePerKm}" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</aside>
|
||||||
|
|
||||||
<aside class="panel">
|
<aside class="panel">
|
||||||
<div class="panel-head">
|
<div class="panel-head">
|
||||||
<span class="kicker">Current Selection</span>
|
<span class="kicker">Current Selection</span>
|
||||||
@ -201,6 +267,9 @@
|
|||||||
<div class="summary-row"><span>Reputation</span><strong>${settings.reputationMin} - ${settings.reputationMax}</strong></div>
|
<div class="summary-row"><span>Reputation</span><strong>${settings.reputationMin} - ${settings.reputationMax}</strong></div>
|
||||||
<div class="summary-row"><span>Reputation Hit</span><strong>${settings.penaltyMin} to ${settings.penaltyMax}</strong></div>
|
<div class="summary-row"><span>Reputation Hit</span><strong>${settings.penaltyMin} to ${settings.penaltyMax}</strong></div>
|
||||||
<div class="summary-row"><span>Time Limit</span><strong>${settings.timeLimitMin}s - ${settings.timeLimitMax}s</strong></div>
|
<div class="summary-row"><span>Time Limit</span><strong>${settings.timeLimitMin}s - ${settings.timeLimitMax}s</strong></div>
|
||||||
|
<div class="summary-row"><span>Repair / Rearm</span><strong>$${Number(settings.serviceRepairCost).toLocaleString()} / $${Number(settings.serviceRearmCost).toLocaleString()}</strong></div>
|
||||||
|
<div class="summary-row"><span>Fuel</span><strong>$${Number(settings.fuelCost).toLocaleString()} / L</strong></div>
|
||||||
|
<div class="summary-row"><span>Medical</span><strong>$${Number(settings.medicalSpawnCost).toLocaleString()} spawn / $${Number(settings.medicalHealCost).toLocaleString()} heal</strong></div>
|
||||||
${state.error ? `<div class="notice">${state.error}</div>` : ""}
|
${state.error ? `<div class="notice">${state.error}</div>` : ""}
|
||||||
</div>
|
</div>
|
||||||
</aside>
|
</aside>
|
||||||
|
|||||||
@ -25,13 +25,38 @@ life state, phone number, email, organization, and holster state.
|
|||||||
|
|
||||||
## Runtime Behavior
|
## Runtime Behavior
|
||||||
- Missing persistent actors can be created from live player snapshots.
|
- Missing persistent actors can be created from live player snapshots.
|
||||||
- Newly created actors receive a Field Commander job orientation email, two
|
- Newly created actors receive their starting loadout from mission
|
||||||
|
`CfgStartingEquipment`, plus a Field Commander job orientation email, two
|
||||||
Field Commander text messages, and a `$2,000` starting credit in their bank
|
Field Commander text messages, and a `$2,000` starting credit in their bank
|
||||||
account.
|
account.
|
||||||
- Hot actor reads are migrated and hydrated before use.
|
- Hot actor reads are migrated and hydrated before use.
|
||||||
- `saveHotState` in the main addon snapshots and saves actor state on player
|
- `saveHotState` in the main addon snapshots and saves actor state on player
|
||||||
disconnect and mission end.
|
disconnect and mission end.
|
||||||
|
|
||||||
|
## Starting Equipment
|
||||||
|
Missions can include `CfgStartingEquipment.hpp` from `description.ext` to
|
||||||
|
override starter actor gear without recompiling the addon or extension.
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
class CfgStartingEquipment {
|
||||||
|
loadout[] = {
|
||||||
|
{},
|
||||||
|
{},
|
||||||
|
{},
|
||||||
|
{"U_BG_Guerrilla_6_1", {{"FirstAidKit", 2}}},
|
||||||
|
{},
|
||||||
|
{},
|
||||||
|
"H_Cap_blk_ION",
|
||||||
|
"",
|
||||||
|
{},
|
||||||
|
{"ItemMap", "ItemGPS", "ItemRadio", "ItemCompass", "ItemWatch", ""}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
The Rust actor model no longer hardcodes a starter loadout. SQF supplies the
|
||||||
|
mission-configured loadout when it creates a missing actor record.
|
||||||
|
|
||||||
## Event Surface
|
## Event Surface
|
||||||
The addon handles server events for actor init, get, set, multi-set, save, and
|
The addon handles server events for actor init, get, set, multi-set, save, and
|
||||||
remove requests, then replies to the requesting player through client actor RPCs.
|
remove requests, then replies to the requesting player through client actor RPCs.
|
||||||
|
|||||||
@ -4,7 +4,7 @@
|
|||||||
* File: fnc_initActorStore.sqf
|
* File: fnc_initActorStore.sqf
|
||||||
* Author: IDSolutions
|
* Author: IDSolutions
|
||||||
* Date: 2025-12-17
|
* Date: 2025-12-17
|
||||||
* Last Update: 2026-05-16
|
* Last Update: 2026-06-03
|
||||||
* Public: Yes
|
* Public: Yes
|
||||||
*
|
*
|
||||||
* Description:
|
* Description:
|
||||||
@ -25,12 +25,23 @@
|
|||||||
#pragma hemtt ignore_variables ["_self"]
|
#pragma hemtt ignore_variables ["_self"]
|
||||||
GVAR(ActorModel) = compileFinal createHashMapObject [[
|
GVAR(ActorModel) = compileFinal createHashMapObject [[
|
||||||
["#type", "ActorModel"],
|
["#type", "ActorModel"],
|
||||||
|
["getStartingConfig", compileFinal {
|
||||||
|
missionConfigFile >> "CfgStartingEquipment"
|
||||||
|
}],
|
||||||
|
["getDefaultLoadout", compileFinal {
|
||||||
|
private _config = _self call ["getStartingConfig", []];
|
||||||
|
private _loadoutConfig = _config >> "loadout";
|
||||||
|
|
||||||
|
if (isArray _loadoutConfig) exitWith { getArray _loadoutConfig };
|
||||||
|
|
||||||
|
[[],[],[],["U_BG_Guerrilla_6_1",[["FirstAidKit", 2]]],[],[],"H_Cap_blk_ION","",[],["ItemMap","ItemGPS","ItemRadio","ItemCompass","ItemWatch",""]]
|
||||||
|
}],
|
||||||
["defaults", compileFinal {
|
["defaults", compileFinal {
|
||||||
private _actor = createHashMap;
|
private _actor = createHashMap;
|
||||||
|
|
||||||
_actor set ["uid", ""];
|
_actor set ["uid", ""];
|
||||||
_actor set ["name", ""];
|
_actor set ["name", ""];
|
||||||
_actor set ["loadout", [[],[],[],["U_BG_Guerrilla_6_1",[["FirstAidKit", 2]]],[],[],"H_Cap_blk_ION","",[],["ItemMap","ItemGPS","ItemRadio","ItemCompass","ItemWatch",""]]];
|
_actor set ["loadout", _self call ["getDefaultLoadout", []]];
|
||||||
_actor set ["position", [0,0,0]];
|
_actor set ["position", [0,0,0]];
|
||||||
_actor set ["direction", 0];
|
_actor set ["direction", 0];
|
||||||
_actor set ["stance", "STAND"];
|
_actor set ["stance", "STAND"];
|
||||||
|
|||||||
@ -9,6 +9,21 @@ inventory handling.
|
|||||||
Current stores cover fuel tracking, medical service behavior, and service
|
Current stores cover fuel tracking, medical service behavior, and service
|
||||||
charges such as repairs and rearming.
|
charges such as repairs and rearming.
|
||||||
|
|
||||||
|
## Configurable Prices
|
||||||
|
Service prices are read dynamically from mission namespace values so the
|
||||||
|
framework mission setup UI can override them at startup. If the UI is cancelled
|
||||||
|
or unavailable, mission `Params` with matching names are used as the backup;
|
||||||
|
if no param is defined, `CfgMissions >> ServicePricing` provides the fallback.
|
||||||
|
|
||||||
|
Supported setting names:
|
||||||
|
- `medicalSpawnCost` - best-effort medical respawn charge; default `100`
|
||||||
|
- `medicalHealCost` - heal charge; default `100`
|
||||||
|
- `serviceRepairCost` - default repair service charge; default `500`
|
||||||
|
- `serviceRearmCost` - default rearm service charge; default `500`
|
||||||
|
- `fuelCost` - refuel price per liter; default `5`
|
||||||
|
- `transportBaseFare` - transport fare base price; default `100`
|
||||||
|
- `transportPricePerKm` - transport distance price; default `50`
|
||||||
|
|
||||||
## Dependencies
|
## Dependencies
|
||||||
- `forge_server_main`
|
- `forge_server_main`
|
||||||
- `forge_server_common` for logging, formatting, and player lookup
|
- `forge_server_common` for logging, formatting, and player lookup
|
||||||
@ -23,7 +38,8 @@ Note: Bank and Org are runtime-only dependencies (not compile-time requiredAddon
|
|||||||
totals, charges the player's organization through `OrgStore`, syncs the org
|
totals, charges the player's organization through `OrgStore`, syncs the org
|
||||||
patch, and rolls fuel back to the starting level when organization funds
|
patch, and rolls fuel back to the starting level when organization funds
|
||||||
cannot cover the refuel.
|
cannot cover the refuel.
|
||||||
- `fnc_initMEconomyStore.sqf` manages medical spawn occupancy, healing charges,
|
- `fnc_initMEconomyStore.sqf` manages medical spawn occupancy, medical spawn
|
||||||
|
billing, healing charges,
|
||||||
respawn placement, death inventory handling, and body-bag transfer. Medical
|
respawn placement, death inventory handling, and body-bag transfer. Medical
|
||||||
charges use player bank/cash first, then organization funds with repayable
|
charges use player bank/cash first, then organization funds with repayable
|
||||||
member debt only when the player cannot cover the service.
|
member debt only when the player cannot cover the service.
|
||||||
|
|||||||
@ -32,6 +32,23 @@ GVAR(FEconomyStore) = createHashMapObject [[
|
|||||||
|
|
||||||
["INFO", "Fuel Store Initialized!", nil, nil] call EFUNC(common,log);
|
["INFO", "Fuel Store Initialized!", nil, nil] call EFUNC(common,log);
|
||||||
}],
|
}],
|
||||||
|
["numberSetting", {
|
||||||
|
params [["_name", "", [""]], ["_default", 0, [0]]];
|
||||||
|
|
||||||
|
private _configDefault = _default;
|
||||||
|
private _missionConfig = missionConfigFile >> "CfgMissions";
|
||||||
|
if !(isClass _missionConfig) then { _missionConfig = configFile >> "CfgMissions"; };
|
||||||
|
private _serviceConfig = _missionConfig >> "ServicePricing";
|
||||||
|
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
|
||||||
|
}],
|
||||||
["start", {
|
["start", {
|
||||||
params ["_source", "_target", "_unit"];
|
params ["_source", "_target", "_unit"];
|
||||||
|
|
||||||
@ -100,7 +117,7 @@ GVAR(FEconomyStore) = createHashMapObject [[
|
|||||||
if (_fuelCapacity <= 0) then { _fuelCapacity = 100; };
|
if (_fuelCapacity <= 0) then { _fuelCapacity = 100; };
|
||||||
|
|
||||||
private _totalLiters = _missingFuel * _fuelCapacity;
|
private _totalLiters = _missingFuel * _fuelCapacity;
|
||||||
private _totalCost = _totalLiters * GVAR(FuelCost);
|
private _totalCost = _totalLiters * (_self call ["numberSetting", ["fuelCost", GVAR(FuelCost)]]);
|
||||||
private _chargeResult = GVAR(SEconomyStore) call ["chargeOrg", [_unit, _totalCost, "Refueling"]];
|
private _chargeResult = GVAR(SEconomyStore) call ["chargeOrg", [_unit, _totalCost, "Refueling"]];
|
||||||
if !(_chargeResult getOrDefault ["success", false]) exitWith {
|
if !(_chargeResult getOrDefault ["success", false]) exitWith {
|
||||||
_self call ["notify", [_unit, "danger", "Refueling", _chargeResult getOrDefault ["message", "Organization funds cannot cover this refuel. Refueling was not completed."]]];
|
_self call ["notify", [_unit, "danger", "Refueling", _chargeResult getOrDefault ["message", "Organization funds cannot cover this refuel. Refueling was not completed."]]];
|
||||||
@ -130,7 +147,7 @@ GVAR(FEconomyStore) = createHashMapObject [[
|
|||||||
private _player = [_uid] call EFUNC(common,getPlayer);
|
private _player = [_uid] call EFUNC(common,getPlayer);
|
||||||
|
|
||||||
private _totalLiters = GETVAR(_target,liters,0);
|
private _totalLiters = GETVAR(_target,liters,0);
|
||||||
private _totalCost = _totalLiters * GVAR(FuelCost);
|
private _totalCost = _totalLiters * (_self call ["numberSetting", ["fuelCost", GVAR(FuelCost)]]);
|
||||||
private _formattedTotalCost = [_totalCost] call EFUNC(common,formatNumber);
|
private _formattedTotalCost = [_totalCost] call EFUNC(common,formatNumber);
|
||||||
private _formattedTotalLiters = _totalLiters toFixed 2;
|
private _formattedTotalLiters = _totalLiters toFixed 2;
|
||||||
|
|
||||||
|
|||||||
@ -4,7 +4,7 @@
|
|||||||
* File: fnc_initMEconomyStore.sqf
|
* File: fnc_initMEconomyStore.sqf
|
||||||
* Author: IDSolutions
|
* Author: IDSolutions
|
||||||
* Date: 2025-12-20
|
* Date: 2025-12-20
|
||||||
* Last Update: 2026-05-15
|
* Last Update: 2026-06-03
|
||||||
* Public: No
|
* Public: No
|
||||||
*
|
*
|
||||||
* Description:
|
* Description:
|
||||||
@ -30,8 +30,26 @@ GVAR(MEconomyStore) = createHashMapObject [[
|
|||||||
_self set ["mSpawns", createHashMap];
|
_self set ["mSpawns", createHashMap];
|
||||||
|
|
||||||
GVAR(occupancyTriggers) = [];
|
GVAR(occupancyTriggers) = [];
|
||||||
|
GVAR(SpawnCost) = 100;
|
||||||
["INFO", "Medical Store Initialized!", nil, nil] call EFUNC(common,log);
|
["INFO", "Medical Store Initialized!", nil, nil] call EFUNC(common,log);
|
||||||
}],
|
}],
|
||||||
|
["numberSetting", {
|
||||||
|
params [["_name", "", [""]], ["_default", 0, [0]]];
|
||||||
|
|
||||||
|
private _configDefault = _default;
|
||||||
|
private _missionConfig = missionConfigFile >> "CfgMissions";
|
||||||
|
if !(isClass _missionConfig) then { _missionConfig = configFile >> "CfgMissions"; };
|
||||||
|
private _serviceConfig = _missionConfig >> "ServicePricing";
|
||||||
|
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", {
|
["init", {
|
||||||
private _mSpawns = (_self get "mSpawns");
|
private _mSpawns = (_self get "mSpawns");
|
||||||
private _prefix = "med_spawn";
|
private _prefix = "med_spawn";
|
||||||
@ -166,40 +184,61 @@ GVAR(MEconomyStore) = createHashMapObject [[
|
|||||||
_result set ["message", ""];
|
_result set ["message", ""];
|
||||||
_result
|
_result
|
||||||
}],
|
}],
|
||||||
["onHealed", {
|
["chargeMedicalService", {
|
||||||
params [["_unit", objNull, [objNull]]];
|
params [
|
||||||
|
["_unit", objNull, [objNull]],
|
||||||
if (isNull _unit) exitWith { ["WARNING", format ["Invalid unit provided: %1", (name _unit)], nil, nil] call EFUNC(common,log); };
|
["_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;
|
private _uid = getPlayerUID _unit;
|
||||||
if (_uid isEqualTo "") exitWith { ["WARNING", "Unable to charge medical service for unit without UID.", nil, nil] call EFUNC(common,log); };
|
if (_uid isEqualTo "") exitWith {
|
||||||
|
["WARNING", "Unable to charge medical service for unit without UID.", nil, nil] call EFUNC(common,log);
|
||||||
|
!_requirePayment
|
||||||
|
};
|
||||||
|
|
||||||
private _healCost = 100;
|
if (_amount <= 0) exitWith { true };
|
||||||
|
|
||||||
private _personalCharge = _self call ["chargePlayer", [_uid, _healCost]];
|
private _personalCharge = _self call ["chargePlayer", [_uid, _amount]];
|
||||||
if (_personalCharge getOrDefault ["success", false]) exitWith {
|
if (_personalCharge getOrDefault ["success", false]) exitWith {
|
||||||
private _sourceLabel = ["cash", "bank"] select ((_personalCharge getOrDefault ["source", "bank"]) isEqualTo "bank");
|
private _sourceLabel = ["cash", "bank"] select ((_personalCharge getOrDefault ["source", "bank"]) isEqualTo "bank");
|
||||||
_self call ["notify", [_unit, "info", "Medical Billing", format ["Medical service charged $%1 from your %2.", [_healCost] call EFUNC(common,formatNumber), _sourceLabel]]];
|
_self call ["notify", [_unit, "info", "Medical Billing", format ["%1 charged $%2 from your %3.", _serviceLabel, [_amount] call EFUNC(common,formatNumber), _sourceLabel]]];
|
||||||
[CRPC(actor,onActorHealed), [], _unit] call CFUNC(targetEvent);
|
true
|
||||||
};
|
};
|
||||||
|
|
||||||
if !(_personalCharge getOrDefault ["fallbackEligible", false]) exitWith {
|
if !(_personalCharge getOrDefault ["fallbackEligible", false]) exitWith {
|
||||||
private _message = _personalCharge getOrDefault ["message", "Personal funds could not be charged for medical service."];
|
private _message = _personalCharge getOrDefault ["message", "Personal funds could not be charged for medical service."];
|
||||||
_self call ["notify", [_unit, "danger", "Medical Billing", _message]];
|
_self call ["notify", [_unit, "danger", "Medical Billing", _message]];
|
||||||
|
!_requirePayment
|
||||||
};
|
};
|
||||||
|
|
||||||
if (isNil QGVAR(SEconomyStore)) exitWith {
|
if (isNil QGVAR(SEconomyStore)) exitWith {
|
||||||
["ERROR", "Service economy store unavailable for medical organization fallback charge.", nil, nil] call EFUNC(common,log);
|
["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."]];
|
_self call ["notify", [_unit, "danger", "Medical Billing", "Organization billing is unavailable. Medical service cannot complete."]];
|
||||||
|
!_requirePayment
|
||||||
};
|
};
|
||||||
|
|
||||||
private _chargeResult = GVAR(SEconomyStore) call ["chargeOrg", [_unit, _healCost, "Medical", true]];
|
private _chargeResult = GVAR(SEconomyStore) call ["chargeOrg", [_unit, _amount, "Medical", true]];
|
||||||
if !(_chargeResult getOrDefault ["success", false]) exitWith {
|
if !(_chargeResult getOrDefault ["success", false]) exitWith {
|
||||||
private _message = _chargeResult getOrDefault ["message", "Organization funds cannot cover this medical service."];
|
private _message = _chargeResult getOrDefault ["message", "Organization funds cannot cover this medical service."];
|
||||||
_self call ["notify", [_unit, "danger", "Medical Billing", _message]];
|
_self call ["notify", [_unit, "danger", "Medical Billing", _message]];
|
||||||
|
!_requirePayment
|
||||||
};
|
};
|
||||||
|
|
||||||
_self call ["notify", [_unit, "info", "Medical Billing", format ["Personal funds could not cover medical service. Organization charged $%1; repay it through your organization credit line.", [_healCost] call EFUNC(common,formatNumber)]]];
|
_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);
|
[CRPC(actor,onActorHealed), [], _unit] call CFUNC(targetEvent);
|
||||||
}],
|
}],
|
||||||
["onRespawn", {
|
["onRespawn", {
|
||||||
@ -214,6 +253,8 @@ GVAR(MEconomyStore) = createHashMapObject [[
|
|||||||
deleteVehicle _corpse;
|
deleteVehicle _corpse;
|
||||||
|
|
||||||
private _player = [_uid] call EFUNC(common,getPlayer);
|
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);
|
[CRPC(actor,onActorRespawn), [_loadout, _medSpawnPos, _medSpawnDir], _player] call CFUNC(targetEvent);
|
||||||
}],
|
}],
|
||||||
["onKilled", {
|
["onKilled", {
|
||||||
|
|||||||
@ -30,6 +30,23 @@ GVAR(SEconomyStore) = createHashMapObject [[
|
|||||||
GVAR(ServiceRearmCost) = 500;
|
GVAR(ServiceRearmCost) = 500;
|
||||||
["INFO", "Service Store Initialized!", nil, nil] call EFUNC(common,log);
|
["INFO", "Service Store Initialized!", nil, nil] call EFUNC(common,log);
|
||||||
}],
|
}],
|
||||||
|
["numberSetting", {
|
||||||
|
params [["_name", "", [""]], ["_default", 0, [0]]];
|
||||||
|
|
||||||
|
private _configDefault = _default;
|
||||||
|
private _missionConfig = missionConfigFile >> "CfgMissions";
|
||||||
|
if !(isClass _missionConfig) then { _missionConfig = configFile >> "CfgMissions"; };
|
||||||
|
private _serviceConfig = _missionConfig >> "ServicePricing";
|
||||||
|
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
|
||||||
|
}],
|
||||||
["notify", {
|
["notify", {
|
||||||
params [["_unit", objNull, [objNull]], ["_type", "info", [""]], ["_title", "Service", [""]], ["_message", "", [""]]];
|
params [["_unit", objNull, [objNull]], ["_type", "info", [""]], ["_title", "Service", [""]], ["_message", "", [""]]];
|
||||||
|
|
||||||
@ -148,7 +165,7 @@ GVAR(SEconomyStore) = createHashMapObject [[
|
|||||||
|
|
||||||
if (isNull _target || { isNull _unit }) exitWith { false };
|
if (isNull _target || { isNull _unit }) exitWith { false };
|
||||||
|
|
||||||
private _repairCost = [_cost, GVAR(ServiceRepairCost)] select (_cost < 0);
|
private _repairCost = [_cost, _self call ["numberSetting", ["serviceRepairCost", GVAR(ServiceRepairCost)]]] select (_cost < 0);
|
||||||
private _charge = _self call ["chargeOrg", [_unit, _repairCost, "Repair"]];
|
private _charge = _self call ["chargeOrg", [_unit, _repairCost, "Repair"]];
|
||||||
if !(_charge getOrDefault ["success", false]) exitWith {
|
if !(_charge getOrDefault ["success", false]) exitWith {
|
||||||
_self call ["notify", [_unit, "danger", "Repair", _charge getOrDefault ["message", "Organization funds cannot cover this repair."]]];
|
_self call ["notify", [_unit, "danger", "Repair", _charge getOrDefault ["message", "Organization funds cannot cover this repair."]]];
|
||||||
@ -164,7 +181,7 @@ GVAR(SEconomyStore) = createHashMapObject [[
|
|||||||
|
|
||||||
if (isNull _target || { isNull _unit }) exitWith { false };
|
if (isNull _target || { isNull _unit }) exitWith { false };
|
||||||
|
|
||||||
private _rearmCost = [_cost, GVAR(ServiceRearmCost)] select (_cost < 0);
|
private _rearmCost = [_cost, _self call ["numberSetting", ["serviceRearmCost", GVAR(ServiceRearmCost)]]] select (_cost < 0);
|
||||||
private _charge = _self call ["chargeOrg", [_unit, _rearmCost, "Rearm"]];
|
private _charge = _self call ["chargeOrg", [_unit, _rearmCost, "Rearm"]];
|
||||||
if !(_charge getOrDefault ["success", false]) exitWith {
|
if !(_charge getOrDefault ["success", false]) exitWith {
|
||||||
_self call ["notify", [_unit, "danger", "Rearm", _charge getOrDefault ["message", "Organization funds cannot cover this rearm."]]];
|
_self call ["notify", [_unit, "danger", "Rearm", _charge getOrDefault ["message", "Organization funds cannot cover this rearm."]]];
|
||||||
|
|||||||
@ -34,3 +34,26 @@ Garage listens for sync events through the event bus:
|
|||||||
- `notification.requested` - storage and vehicle modification alerts
|
- `notification.requested` - storage and vehicle modification alerts
|
||||||
|
|
||||||
The store module emits these events when granting vehicles; garage applies the changes to player state.
|
The store module emits these events when granting vehicles; garage applies the changes to player state.
|
||||||
|
|
||||||
|
## Starting Unlocks
|
||||||
|
Missions can include `CfgStartingEquipment.hpp` from `description.ext` to
|
||||||
|
configure initial virtual garage unlocks for new players.
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
class CfgStartingEquipment {
|
||||||
|
class Unlocks {
|
||||||
|
class Garage {
|
||||||
|
cars[] = {"B_Quadbike_01_F"};
|
||||||
|
armor[] = {};
|
||||||
|
helis[] = {};
|
||||||
|
planes[] = {};
|
||||||
|
naval[] = {};
|
||||||
|
other[] = {};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
The extension virtual garage default is intentionally empty. The server addon
|
||||||
|
seeds `CfgStartingEquipment` unlocks only when a player does not already have a
|
||||||
|
persistent owner-scoped garage record.
|
||||||
|
|||||||
@ -24,15 +24,28 @@
|
|||||||
#pragma hemtt ignore_variables ["_self"]
|
#pragma hemtt ignore_variables ["_self"]
|
||||||
GVAR(VGarageModel) = compileFinal createHashMapObject [[
|
GVAR(VGarageModel) = compileFinal createHashMapObject [[
|
||||||
["#type", "VGarageModel"],
|
["#type", "VGarageModel"],
|
||||||
|
["getStartingUnlocksConfig", compileFinal {
|
||||||
|
missionConfigFile >> "CfgStartingEquipment" >> "Unlocks" >> "Garage"
|
||||||
|
}],
|
||||||
|
["getStartingUnlocks", compileFinal {
|
||||||
|
params [["_category", "", [""]], ["_fallback", [], [[]]]];
|
||||||
|
|
||||||
|
private _config = _self call ["getStartingUnlocksConfig", []];
|
||||||
|
private _categoryConfig = _config >> _category;
|
||||||
|
|
||||||
|
if (isArray _categoryConfig) exitWith { getArray _categoryConfig };
|
||||||
|
|
||||||
|
+_fallback
|
||||||
|
}],
|
||||||
["defaults", compileFinal {
|
["defaults", compileFinal {
|
||||||
private _vGarage = createHashMap;
|
private _vGarage = createHashMap;
|
||||||
|
|
||||||
_vGarage set ["armor", []];
|
_vGarage set ["armor", _self call ["getStartingUnlocks", ["armor", []]]];
|
||||||
_vGarage set ["cars", ["B_Quadbike_01_F"]];
|
_vGarage set ["cars", _self call ["getStartingUnlocks", ["cars", ["B_Quadbike_01_F"]]]];
|
||||||
_vGarage set ["helis", []];
|
_vGarage set ["helis", _self call ["getStartingUnlocks", ["helis", []]]];
|
||||||
_vGarage set ["naval", []];
|
_vGarage set ["naval", _self call ["getStartingUnlocks", ["naval", []]]];
|
||||||
_vGarage set ["other", []];
|
_vGarage set ["other", _self call ["getStartingUnlocks", ["other", []]]];
|
||||||
_vGarage set ["planes", []];
|
_vGarage set ["planes", _self call ["getStartingUnlocks", ["planes", []]]];
|
||||||
|
|
||||||
_vGarage
|
_vGarage
|
||||||
}]
|
}]
|
||||||
@ -71,17 +84,46 @@ GVAR(VGBaseStore) = compileFinal ([
|
|||||||
private _command = ["owned:garage:hot:fetch", "owned:garage:hot:init"] select _initialize;
|
private _command = ["owned:garage:hot:fetch", "owned:garage:hot:init"] select _initialize;
|
||||||
_self call ["callHotVGarage", [_command, [_uid]]]
|
_self call ["callHotVGarage", [_command, [_uid]]]
|
||||||
}],
|
}],
|
||||||
|
["isPersistentVGarageInitialized", compileFinal {
|
||||||
|
params [["_uid", "", [""]]];
|
||||||
|
|
||||||
|
if (_uid isEqualTo "") exitWith { false };
|
||||||
|
|
||||||
|
["owned:garage:exists", [_uid]] call EFUNC(extension,extCall) params ["_result", "_isSuccess"];
|
||||||
|
_isSuccess && { _result isEqualTo "true" }
|
||||||
|
}],
|
||||||
|
["seedStartingUnlocks", compileFinal {
|
||||||
|
params [["_uid", "", [""]], ["_garage", createHashMap, [createHashMap]]];
|
||||||
|
|
||||||
|
if (_uid isEqualTo "" || { _garage isEqualTo createHashMap }) exitWith { _garage };
|
||||||
|
|
||||||
|
private _defaults = GVAR(VGarageModel) call ["defaults", []];
|
||||||
|
private _seeded = +_garage;
|
||||||
|
{
|
||||||
|
_seeded set [_x, +_y];
|
||||||
|
} forEach _defaults;
|
||||||
|
|
||||||
|
private _updated = _self call ["callHotVGarage", ["owned:garage:hot:override", [_uid, toJSON _seeded]]];
|
||||||
|
if (_updated isEqualTo createHashMap) exitWith { _seeded };
|
||||||
|
|
||||||
|
_self call ["callHotVGarage", ["owned:garage:hot:save", [_uid]]];
|
||||||
|
_updated
|
||||||
|
}],
|
||||||
["init", compileFinal {
|
["init", compileFinal {
|
||||||
params [["_uid", "", [""]]];
|
params [["_uid", "", [""]]];
|
||||||
|
|
||||||
private _player = [_uid] call EFUNC(common,getPlayer);
|
private _player = [_uid] call EFUNC(common,getPlayer);
|
||||||
if (isNull _player) exitWith { createHashMap };
|
if (isNull _player) exitWith { createHashMap };
|
||||||
|
|
||||||
|
private _hasPersistentGarage = _self call ["isPersistentVGarageInitialized", [_uid]];
|
||||||
private _garage = _self call ["loadHotVGarage", [_uid, true]];
|
private _garage = _self call ["loadHotVGarage", [_uid, true]];
|
||||||
if (_garage isEqualTo createHashMap) then {
|
if (_garage isEqualTo createHashMap) then {
|
||||||
_garage = GVAR(VGarageModel) call ["defaults", []];
|
_garage = GVAR(VGarageModel) call ["defaults", []];
|
||||||
["ERROR", format ["Failed to initialize virtual garage for %1! Using fallback virtual garage.", _uid]] call EFUNC(common,log);
|
["ERROR", format ["Failed to initialize virtual garage for %1! Using fallback virtual garage.", _uid]] call EFUNC(common,log);
|
||||||
};
|
};
|
||||||
|
if !(_hasPersistentGarage) then {
|
||||||
|
_garage = _self call ["seedStartingUnlocks", [_uid, _garage]];
|
||||||
|
};
|
||||||
|
|
||||||
[CRPC(garage,responseInitVG), [_garage], _player] call CFUNC(targetEvent);
|
[CRPC(garage,responseInitVG), [_garage], _player] call CFUNC(targetEvent);
|
||||||
_garage
|
_garage
|
||||||
|
|||||||
@ -35,3 +35,24 @@ Locker listens for sync events through the event bus:
|
|||||||
- `notification.requested` - storage and item modification alerts
|
- `notification.requested` - storage and item modification alerts
|
||||||
|
|
||||||
The store module emits these events when granting items; locker applies the changes to player state.
|
The store module emits these events when granting items; locker applies the changes to player state.
|
||||||
|
|
||||||
|
## Starting Unlocks
|
||||||
|
Missions can include `CfgStartingEquipment.hpp` from `description.ext` to
|
||||||
|
configure initial virtual arsenal unlocks for new players.
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
class CfgStartingEquipment {
|
||||||
|
class Unlocks {
|
||||||
|
class Locker {
|
||||||
|
items[] = {"FirstAidKit", "ItemMap", "ItemCompass"};
|
||||||
|
weapons[] = {"hgun_P07_F"};
|
||||||
|
magazines[] = {"16Rnd_9x21_Mag"};
|
||||||
|
backpacks[] = {};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
The extension virtual locker default is intentionally empty. The server addon
|
||||||
|
seeds `CfgStartingEquipment` unlocks only when a player does not already have a
|
||||||
|
persistent owner-scoped locker record.
|
||||||
|
|||||||
@ -24,13 +24,26 @@
|
|||||||
#pragma hemtt ignore_variables ["_self"]
|
#pragma hemtt ignore_variables ["_self"]
|
||||||
GVAR(VArsenalModel) = compileFinal createHashMapObject [[
|
GVAR(VArsenalModel) = compileFinal createHashMapObject [[
|
||||||
["#type", "VArsenalModel"],
|
["#type", "VArsenalModel"],
|
||||||
|
["getStartingUnlocksConfig", compileFinal {
|
||||||
|
missionConfigFile >> "CfgStartingEquipment" >> "Unlocks" >> "Locker"
|
||||||
|
}],
|
||||||
|
["getStartingUnlocks", compileFinal {
|
||||||
|
params [["_category", "", [""]], ["_fallback", [], [[]]]];
|
||||||
|
|
||||||
|
private _config = _self call ["getStartingUnlocksConfig", []];
|
||||||
|
private _categoryConfig = _config >> _category;
|
||||||
|
|
||||||
|
if (isArray _categoryConfig) exitWith { getArray _categoryConfig };
|
||||||
|
|
||||||
|
+_fallback
|
||||||
|
}],
|
||||||
["defaults", compileFinal {
|
["defaults", compileFinal {
|
||||||
private _vArsenal = createHashMap;
|
private _vArsenal = createHashMap;
|
||||||
|
|
||||||
_vArsenal set ["backpacks", ["B_AssaultPack_rgr"]];
|
_vArsenal set ["backpacks", _self call ["getStartingUnlocks", ["backpacks", ["B_AssaultPack_rgr"]]]];
|
||||||
_vArsenal set ["items", ["FirstAidKit", "G_Combat", "H_Cap_blk_ION", "H_HelmetB", "ItemCompass", "ItemGPS", "ItemMap", "ItemRadio", "ItemWatch", "U_BG_Guerrilla_6_1", "V_TacVest_oli", "ACE_EarPlugs"]];
|
_vArsenal set ["items", _self call ["getStartingUnlocks", ["items", ["FirstAidKit", "G_Combat", "H_Cap_blk_ION", "H_HelmetB", "ItemCompass", "ItemGPS", "ItemMap", "ItemRadio", "ItemWatch", "U_BG_Guerrilla_6_1", "V_TacVest_oli", "ACE_EarPlugs"]]]];
|
||||||
_vArsenal set ["magazines", ["16Rnd_9x21_Mag", "30Rnd_65x39_caseless_black_mag", "Chemlight_blue", "Chemlight_green", "Chemlight_red", "Chemlight_yellow", "HandGrenade", "SmokeShell", "SmokeShellBlue", "SmokeShellGreen", "SmokeShellOrange", "SmokeShellPurple", "SmokeShellRed", "SmokeShellYellow"]];
|
_vArsenal set ["magazines", _self call ["getStartingUnlocks", ["magazines", ["16Rnd_9x21_Mag", "30Rnd_65x39_caseless_black_mag", "Chemlight_blue", "Chemlight_green", "Chemlight_red", "Chemlight_yellow", "HandGrenade", "SmokeShell", "SmokeShellBlue", "SmokeShellGreen", "SmokeShellOrange", "SmokeShellPurple", "SmokeShellRed", "SmokeShellYellow"]]]];
|
||||||
_vArsenal set ["weapons", ["arifle_MX_F", "hgun_P07_F"]];
|
_vArsenal set ["weapons", _self call ["getStartingUnlocks", ["weapons", ["arifle_MX_F", "hgun_P07_F"]]]];
|
||||||
|
|
||||||
_vArsenal
|
_vArsenal
|
||||||
}]
|
}]
|
||||||
@ -69,17 +82,46 @@ GVAR(VABaseStore) = compileFinal ([
|
|||||||
private _command = ["owned:locker:hot:fetch", "owned:locker:hot:init"] select _initialize;
|
private _command = ["owned:locker:hot:fetch", "owned:locker:hot:init"] select _initialize;
|
||||||
_self call ["callHotVArsenal", [_command, [_uid]]]
|
_self call ["callHotVArsenal", [_command, [_uid]]]
|
||||||
}],
|
}],
|
||||||
|
["isPersistentVArsenalInitialized", compileFinal {
|
||||||
|
params [["_uid", "", [""]]];
|
||||||
|
|
||||||
|
if (_uid isEqualTo "") exitWith { false };
|
||||||
|
|
||||||
|
["owned:locker:exists", [_uid]] call EFUNC(extension,extCall) params ["_result", "_isSuccess"];
|
||||||
|
_isSuccess && { _result isEqualTo "true" }
|
||||||
|
}],
|
||||||
|
["seedStartingUnlocks", compileFinal {
|
||||||
|
params [["_uid", "", [""]], ["_arsenal", createHashMap, [createHashMap]]];
|
||||||
|
|
||||||
|
if (_uid isEqualTo "" || { _arsenal isEqualTo createHashMap }) exitWith { _arsenal };
|
||||||
|
|
||||||
|
private _defaults = GVAR(VArsenalModel) call ["defaults", []];
|
||||||
|
private _seeded = +_arsenal;
|
||||||
|
{
|
||||||
|
_seeded set [_x, +_y];
|
||||||
|
} forEach _defaults;
|
||||||
|
|
||||||
|
private _updated = _self call ["callHotVArsenal", ["owned:locker:hot:override", [_uid, toJSON _seeded]]];
|
||||||
|
if (_updated isEqualTo createHashMap) exitWith { _seeded };
|
||||||
|
|
||||||
|
_self call ["callHotVArsenal", ["owned:locker:hot:save", [_uid]]];
|
||||||
|
_updated
|
||||||
|
}],
|
||||||
["init", compileFinal {
|
["init", compileFinal {
|
||||||
params [["_uid", "", [""]]];
|
params [["_uid", "", [""]]];
|
||||||
|
|
||||||
private _player = [_uid] call EFUNC(common,getPlayer);
|
private _player = [_uid] call EFUNC(common,getPlayer);
|
||||||
if (isNull _player) exitWith { createHashMap };
|
if (isNull _player) exitWith { createHashMap };
|
||||||
|
|
||||||
|
private _hasPersistentArsenal = _self call ["isPersistentVArsenalInitialized", [_uid]];
|
||||||
private _arsenal = _self call ["loadHotVArsenal", [_uid, true]];
|
private _arsenal = _self call ["loadHotVArsenal", [_uid, true]];
|
||||||
if (_arsenal isEqualTo createHashMap) then {
|
if (_arsenal isEqualTo createHashMap) then {
|
||||||
_arsenal = GVAR(VArsenalModel) call ["defaults", []];
|
_arsenal = GVAR(VArsenalModel) call ["defaults", []];
|
||||||
["ERROR", format ["Failed to initialize virtual arsenal for %1! Using fallback virtual arsenal.", _uid]] call EFUNC(common,log);
|
["ERROR", format ["Failed to initialize virtual arsenal for %1! Using fallback virtual arsenal.", _uid]] call EFUNC(common,log);
|
||||||
};
|
};
|
||||||
|
if !(_hasPersistentArsenal) then {
|
||||||
|
_arsenal = _self call ["seedStartingUnlocks", [_uid, _arsenal]];
|
||||||
|
};
|
||||||
|
|
||||||
[CRPC(locker,responseInitVA), [_arsenal], _player] call CFUNC(targetEvent);
|
[CRPC(locker,responseInitVA), [_arsenal], _player] call CFUNC(targetEvent);
|
||||||
_arsenal
|
_arsenal
|
||||||
|
|||||||
@ -34,6 +34,22 @@ generated catalog without changing the addon.
|
|||||||
```cpp
|
```cpp
|
||||||
class CfgStore {
|
class CfgStore {
|
||||||
mode = "allowlist"; // dynamic, allowlist, or denylist
|
mode = "allowlist"; // dynamic, allowlist, or denylist
|
||||||
|
modMode = "dynamic"; // dynamic, allowlist, or denylist
|
||||||
|
mods[] = {}; // ModSources class names used when modMode is not dynamic
|
||||||
|
|
||||||
|
class ModSources {
|
||||||
|
class rhs {
|
||||||
|
patches[] = {"rhs_main", "rhsusf_main"};
|
||||||
|
addons[] = {"rhs_", "rhsusf_", "rhsgref_", "rhsafrf_"};
|
||||||
|
prefixes[] = {"rhs_", "rhsusf_", "rhsgref_", "rhsafrf_"};
|
||||||
|
};
|
||||||
|
|
||||||
|
class ace3 {
|
||||||
|
patches[] = {"ace_main"};
|
||||||
|
addons[] = {"ace_"};
|
||||||
|
prefixes[] = {"ace_"};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
class Categories {
|
class Categories {
|
||||||
primary[] = {"arifle_MX_F", "arifle_MXC_F"};
|
primary[] = {"arifle_MX_F", "arifle_MXC_F"};
|
||||||
@ -56,6 +72,13 @@ listed for the requested category. `denylist` removes listed classnames from the
|
|||||||
generated category. Overrides are applied server-side, so checkout validation
|
generated category. Overrides are applied server-side, so checkout validation
|
||||||
uses the same prices and descriptions the UI displays.
|
uses the same prices and descriptions the UI displays.
|
||||||
|
|
||||||
|
`modMode` applies before category filtering. `allowlist` only keeps generated
|
||||||
|
entries that match one of the configured `mods[]`; `denylist` removes matching
|
||||||
|
entries. Each `ModSources` child can define `patches[]` to detect whether the
|
||||||
|
mod is loaded, `addons[]` for config source addon/source mod names or classname
|
||||||
|
prefixes, and `prefixes[]` for classname prefixes. If a mod source defines no
|
||||||
|
patches, it is treated as available and only the source/prefix checks are used.
|
||||||
|
|
||||||
`units[]` follows the same `dynamic`, `allowlist`, and `denylist` behavior as
|
`units[]` follows the same `dynamic`, `allowlist`, and `denylist` behavior as
|
||||||
item and vehicle categories. Unit purchases are immediate spawn grants, not
|
item and vehicle categories. Unit purchases are immediate spawn grants, not
|
||||||
durable virtual garage unlocks.
|
durable virtual garage unlocks.
|
||||||
|
|||||||
@ -28,6 +28,132 @@ GVAR(StoreCatalogServiceBaseClass) = compileFinal createHashMapFromArray [
|
|||||||
|
|
||||||
_mode
|
_mode
|
||||||
}],
|
}],
|
||||||
|
["getMissionStoreModMode", compileFinal {
|
||||||
|
private _storeConfig = _self call ["getMissionStoreConfig", []];
|
||||||
|
private _mode = toLowerANSI getText (_storeConfig >> "modMode");
|
||||||
|
|
||||||
|
if !(_mode in ["allowlist", "denylist", "dynamic"]) then { _mode = "dynamic"; };
|
||||||
|
|
||||||
|
_mode
|
||||||
|
}],
|
||||||
|
["getMissionStoreModList", compileFinal {
|
||||||
|
private _storeConfig = _self call ["getMissionStoreConfig", []];
|
||||||
|
private _mods = [];
|
||||||
|
|
||||||
|
if (isArray (_storeConfig >> "mods")) then {
|
||||||
|
_mods = getArray (_storeConfig >> "mods");
|
||||||
|
};
|
||||||
|
|
||||||
|
_mods apply {
|
||||||
|
private _modID = "";
|
||||||
|
if (_x isEqualType "") then {
|
||||||
|
_modID = _x;
|
||||||
|
} else {
|
||||||
|
_modID = str _x;
|
||||||
|
};
|
||||||
|
|
||||||
|
toLowerANSI _modID
|
||||||
|
}
|
||||||
|
}],
|
||||||
|
["getMissionStoreModSourceValues", compileFinal {
|
||||||
|
params [["_modID", "", [""]], ["_key", "", [""]]];
|
||||||
|
|
||||||
|
private _storeConfig = _self call ["getMissionStoreConfig", []];
|
||||||
|
private _sourceConfig = _storeConfig >> "ModSources" >> _modID;
|
||||||
|
private _values = [];
|
||||||
|
|
||||||
|
if (isArray (_sourceConfig >> _key)) then {
|
||||||
|
_values = getArray (_sourceConfig >> _key);
|
||||||
|
};
|
||||||
|
|
||||||
|
_values apply {
|
||||||
|
if (_x isEqualType "") then {
|
||||||
|
_x
|
||||||
|
} else {
|
||||||
|
str _x
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}],
|
||||||
|
["isMissionStoreModLoaded", compileFinal {
|
||||||
|
params [["_modID", "", [""]]];
|
||||||
|
|
||||||
|
private _patches = _self call ["getMissionStoreModSourceValues", [_modID, "patches"]];
|
||||||
|
if (_patches isEqualTo []) exitWith { true };
|
||||||
|
|
||||||
|
private _loaded = false;
|
||||||
|
{
|
||||||
|
if (isClass (configFile >> "CfgPatches" >> _x)) exitWith { _loaded = true; };
|
||||||
|
} forEach _patches;
|
||||||
|
|
||||||
|
_loaded
|
||||||
|
}],
|
||||||
|
["doesValueMatchAnyPrefix", compileFinal {
|
||||||
|
params [["_value", "", [""]], ["_prefixes", [], [[]]]];
|
||||||
|
|
||||||
|
private _normalizedValue = toLowerANSI _value;
|
||||||
|
private _matches = false;
|
||||||
|
{
|
||||||
|
private _prefix = toLowerANSI _x;
|
||||||
|
if (_prefix isEqualTo "") then { continue; };
|
||||||
|
if ((_normalizedValue select [0, count _prefix]) isEqualTo _prefix) exitWith { _matches = true; };
|
||||||
|
} forEach _prefixes;
|
||||||
|
|
||||||
|
_matches
|
||||||
|
}],
|
||||||
|
["doesItemMatchMissionStoreMod", compileFinal {
|
||||||
|
params [["_item", createHashMap, [createHashMap]], ["_modID", "", [""]]];
|
||||||
|
|
||||||
|
if (_item isEqualTo createHashMap || { _modID isEqualTo "" }) exitWith { false };
|
||||||
|
if !(_self call ["isMissionStoreModLoaded", [_modID]]) exitWith { false };
|
||||||
|
|
||||||
|
private _className = _item getOrDefault ["className", ""];
|
||||||
|
private _sourceAddons = (_item getOrDefault ["sourceAddons", []]) apply { toLowerANSI _x };
|
||||||
|
private _sourceMod = _item getOrDefault ["sourceMod", ""];
|
||||||
|
private _addons = (_self call ["getMissionStoreModSourceValues", [_modID, "addons"]]) apply { toLowerANSI _x };
|
||||||
|
private _prefixes = (_self call ["getMissionStoreModSourceValues", [_modID, "prefixes"]]) apply { toLowerANSI _x };
|
||||||
|
private _sourceModLower = toLowerANSI _sourceMod;
|
||||||
|
|
||||||
|
if (_sourceModLower in _addons) exitWith { true };
|
||||||
|
private _sourceAddonMatched = false;
|
||||||
|
{
|
||||||
|
if (_x in _addons) exitWith { _sourceAddonMatched = true; };
|
||||||
|
if (_self call ["doesValueMatchAnyPrefix", [_x, _addons]]) exitWith { _sourceAddonMatched = true; };
|
||||||
|
} forEach _sourceAddons;
|
||||||
|
if (_sourceAddonMatched) exitWith { true };
|
||||||
|
if (_self call ["doesValueMatchAnyPrefix", [_className, _addons + _prefixes]]) exitWith { true };
|
||||||
|
if (_self call ["doesValueMatchAnyPrefix", [_sourceMod, _addons]]) exitWith { true };
|
||||||
|
|
||||||
|
false
|
||||||
|
}],
|
||||||
|
["doesItemMatchMissionStoreMods", compileFinal {
|
||||||
|
params [["_item", createHashMap, [createHashMap]], ["_mods", [], [[]]]];
|
||||||
|
|
||||||
|
private _matches = false;
|
||||||
|
{
|
||||||
|
if (_self call ["doesItemMatchMissionStoreMod", [_item, _x]]) exitWith { _matches = true; };
|
||||||
|
} forEach _mods;
|
||||||
|
|
||||||
|
_matches
|
||||||
|
}],
|
||||||
|
["applyMissionStoreModFilter", compileFinal {
|
||||||
|
params [["_items", [], [[]]]];
|
||||||
|
|
||||||
|
private _mode = _self call ["getMissionStoreModMode", []];
|
||||||
|
private _mods = _self call ["getMissionStoreModList", []];
|
||||||
|
if (_mode isEqualTo "dynamic" || { _mods isEqualTo [] }) exitWith { +_items };
|
||||||
|
|
||||||
|
switch (_mode) do {
|
||||||
|
case "allowlist": {
|
||||||
|
_items select { _self call ["doesItemMatchMissionStoreMods", [_x, _mods]] }
|
||||||
|
};
|
||||||
|
case "denylist": {
|
||||||
|
_items select { !(_self call ["doesItemMatchMissionStoreMods", [_x, _mods]]) }
|
||||||
|
};
|
||||||
|
default {
|
||||||
|
+_items
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}],
|
||||||
["getMissionStoreCategoryList", compileFinal {
|
["getMissionStoreCategoryList", compileFinal {
|
||||||
params [["_category", "", [""]]];
|
params [["_category", "", [""]]];
|
||||||
|
|
||||||
@ -93,16 +219,16 @@ GVAR(StoreCatalogServiceBaseClass) = compileFinal createHashMapFromArray [
|
|||||||
|
|
||||||
private _mode = _self call ["getMissionStoreMode", []];
|
private _mode = _self call ["getMissionStoreMode", []];
|
||||||
private _classNames = _self call ["getMissionStoreCategoryList", [_category]];
|
private _classNames = _self call ["getMissionStoreCategoryList", [_category]];
|
||||||
private _filteredItems = +_items;
|
private _filteredItems = _self call ["applyMissionStoreModFilter", [_items]];
|
||||||
|
|
||||||
switch (_mode) do {
|
switch (_mode) do {
|
||||||
case "allowlist": {
|
case "allowlist": {
|
||||||
_filteredItems = _items select {
|
_filteredItems = _filteredItems select {
|
||||||
(toLowerANSI (_x getOrDefault ["className", ""])) in _classNames
|
(toLowerANSI (_x getOrDefault ["className", ""])) in _classNames
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
case "denylist": {
|
case "denylist": {
|
||||||
_filteredItems = _items select {
|
_filteredItems = _filteredItems select {
|
||||||
!((toLowerANSI (_x getOrDefault ["className", ""])) in _classNames)
|
!((toLowerANSI (_x getOrDefault ["className", ""])) in _classNames)
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
@ -175,6 +301,8 @@ GVAR(StoreCatalogServiceBaseClass) = compileFinal createHashMapFromArray [
|
|||||||
|
|
||||||
private _className = configName _cfg;
|
private _className = configName _cfg;
|
||||||
private _displayName = getText (_cfg >> "displayName");
|
private _displayName = getText (_cfg >> "displayName");
|
||||||
|
private _sourceAddons = configSourceAddonList _cfg;
|
||||||
|
private _sourceMod = configSourceMod _cfg;
|
||||||
private _picture = getText (_cfg >> _imageField);
|
private _picture = getText (_cfg >> _imageField);
|
||||||
if (_picture isEqualTo "" && { _imageField isNotEqualTo "picture" }) then {
|
if (_picture isEqualTo "" && { _imageField isNotEqualTo "picture" }) then {
|
||||||
_picture = getText (_cfg >> "picture");
|
_picture = getText (_cfg >> "picture");
|
||||||
@ -190,7 +318,9 @@ GVAR(StoreCatalogServiceBaseClass) = compileFinal createHashMapFromArray [
|
|||||||
["price", _self call ["formatCurrency", [_priceValue]]],
|
["price", _self call ["formatCurrency", [_priceValue]]],
|
||||||
["priceValue", _priceValue],
|
["priceValue", _priceValue],
|
||||||
["image", _picture],
|
["image", _picture],
|
||||||
["type", _typeLabel]
|
["type", _typeLabel],
|
||||||
|
["sourceAddons", _sourceAddons],
|
||||||
|
["sourceMod", _sourceMod]
|
||||||
]
|
]
|
||||||
}],
|
}],
|
||||||
["appendCfgWeaponsByItemInfoType", compileFinal {
|
["appendCfgWeaponsByItemInfoType", compileFinal {
|
||||||
|
|||||||
@ -12,6 +12,9 @@
|
|||||||
* Generator behavior:
|
* Generator behavior:
|
||||||
* - maxConcurrentMissions and missionInterval are copied into
|
* - maxConcurrentMissions and missionInterval are copied into
|
||||||
* forge_server_task_missionSetup_settings by the framework mission setup service.
|
* forge_server_task_missionSetup_settings by the framework mission setup service.
|
||||||
|
* - ServicePricing values are copied to missionNamespace by the framework
|
||||||
|
* mission setup service so economy and transport stores can read UI or
|
||||||
|
* mission-param overrides at runtime.
|
||||||
* - Reward, reputation, penalty, and timeLimit ranges are read through
|
* - Reward, reputation, penalty, and timeLimit ranges are read through
|
||||||
* forge_server_task_fnc_getMissionSettingRange so UI overrides and config fallbacks
|
* forge_server_task_fnc_getMissionSettingRange so UI overrides and config fallbacks
|
||||||
* use the same path.
|
* use the same path.
|
||||||
@ -26,6 +29,18 @@ class CfgMissions {
|
|||||||
// Seconds before a generated mission location can be reused.
|
// Seconds before a generated mission location can be reused.
|
||||||
locationReuseCooldown = 900;
|
locationReuseCooldown = 900;
|
||||||
|
|
||||||
|
// Economy and service defaults. Mission Params with matching names override
|
||||||
|
// these values before the setup UI opens; submitted UI values override both.
|
||||||
|
class ServicePricing {
|
||||||
|
medicalSpawnCost = 100;
|
||||||
|
medicalHealCost = 100;
|
||||||
|
serviceRepairCost = 500;
|
||||||
|
serviceRearmCost = 500;
|
||||||
|
fuelCost = 5;
|
||||||
|
transportBaseFare = 100;
|
||||||
|
transportPricePerKm = 50;
|
||||||
|
};
|
||||||
|
|
||||||
// Enemy faction selection is ultimately exported to ENEMY_FACTION_STR and
|
// Enemy faction selection is ultimately exported to ENEMY_FACTION_STR and
|
||||||
// ENEMY_SIDE for server-side generators.
|
// ENEMY_SIDE for server-side generators.
|
||||||
class EnemyFactionConfig {
|
class EnemyFactionConfig {
|
||||||
|
|||||||
@ -80,7 +80,18 @@ GVAR(MissionSetupServiceBaseClass) = compileFinal createHashMapFromArray [
|
|||||||
_overrides getOrDefault [_varName, _default]
|
_overrides getOrDefault [_varName, _default]
|
||||||
};
|
};
|
||||||
|
|
||||||
missionNamespace getVariable [_varName, _default]
|
private _paramValue = [_varName, _default] call BIS_fnc_getParamValue;
|
||||||
|
missionNamespace getVariable [_varName, _paramValue]
|
||||||
|
};
|
||||||
|
private _serviceDefault = {
|
||||||
|
params ["_varName", "_default"];
|
||||||
|
|
||||||
|
private _serviceConfig = _missionConfig >> "ServicePricing";
|
||||||
|
if (isNumber (_serviceConfig >> _varName)) exitWith {
|
||||||
|
getNumber (_serviceConfig >> _varName)
|
||||||
|
};
|
||||||
|
|
||||||
|
_default
|
||||||
};
|
};
|
||||||
|
|
||||||
private _maxConcurrent = [
|
private _maxConcurrent = [
|
||||||
@ -104,6 +115,13 @@ GVAR(MissionSetupServiceBaseClass) = compileFinal createHashMapFromArray [
|
|||||||
private _penMax = [["penaltyMax", -25, _overrides] call _paramOrDefault, -25] call (_self get "numberOrDefault");
|
private _penMax = [["penaltyMax", -25, _overrides] call _paramOrDefault, -25] call (_self get "numberOrDefault");
|
||||||
private _timeMin = [["timeLimitMin", 600, _overrides] call _paramOrDefault, 600] call (_self get "numberOrDefault");
|
private _timeMin = [["timeLimitMin", 600, _overrides] call _paramOrDefault, 600] call (_self get "numberOrDefault");
|
||||||
private _timeMax = [["timeLimitMax", 900, _overrides] call _paramOrDefault, 900] call (_self get "numberOrDefault");
|
private _timeMax = [["timeLimitMax", 900, _overrides] call _paramOrDefault, 900] call (_self get "numberOrDefault");
|
||||||
|
private _medicalSpawnCost = [["medicalSpawnCost", ["medicalSpawnCost", 100] call _serviceDefault, _overrides] call _paramOrDefault, 100] call (_self get "numberOrDefault");
|
||||||
|
private _medicalHealCost = [["medicalHealCost", ["medicalHealCost", 100] call _serviceDefault, _overrides] call _paramOrDefault, 100] call (_self get "numberOrDefault");
|
||||||
|
private _serviceRepairCost = [["serviceRepairCost", ["serviceRepairCost", 500] call _serviceDefault, _overrides] call _paramOrDefault, 500] call (_self get "numberOrDefault");
|
||||||
|
private _serviceRearmCost = [["serviceRearmCost", ["serviceRearmCost", 500] call _serviceDefault, _overrides] call _paramOrDefault, 500] call (_self get "numberOrDefault");
|
||||||
|
private _fuelCost = [["fuelCost", ["fuelCost", 5] call _serviceDefault, _overrides] call _paramOrDefault, 5] call (_self get "numberOrDefault");
|
||||||
|
private _transportBaseFare = [["transportBaseFare", ["transportBaseFare", 100] call _serviceDefault, _overrides] call _paramOrDefault, 100] call (_self get "numberOrDefault");
|
||||||
|
private _transportPricePerKm = [["transportPricePerKm", ["transportPricePerKm", 50] call _serviceDefault, _overrides] call _paramOrDefault, 50] call (_self get "numberOrDefault");
|
||||||
private _generatorProvider = _overrides getOrDefault ["generatorProvider", GETGVAR(generatorProvider,"builtin")];
|
private _generatorProvider = _overrides getOrDefault ["generatorProvider", GETGVAR(generatorProvider,"builtin")];
|
||||||
if !(_generatorProvider isEqualType "") then { _generatorProvider = str _generatorProvider; };
|
if !(_generatorProvider isEqualType "") then { _generatorProvider = str _generatorProvider; };
|
||||||
_generatorProvider = toLowerANSI _generatorProvider;
|
_generatorProvider = toLowerANSI _generatorProvider;
|
||||||
@ -131,6 +149,13 @@ GVAR(MissionSetupServiceBaseClass) = compileFinal createHashMapFromArray [
|
|||||||
|
|
||||||
_timeMin = _timeMin max 1;
|
_timeMin = _timeMin max 1;
|
||||||
_timeMax = _timeMax max _timeMin;
|
_timeMax = _timeMax max _timeMin;
|
||||||
|
_medicalSpawnCost = _medicalSpawnCost max 0;
|
||||||
|
_medicalHealCost = _medicalHealCost max 0;
|
||||||
|
_serviceRepairCost = _serviceRepairCost max 0;
|
||||||
|
_serviceRearmCost = _serviceRearmCost max 0;
|
||||||
|
_fuelCost = _fuelCost max 0;
|
||||||
|
_transportBaseFare = _transportBaseFare max 0;
|
||||||
|
_transportPricePerKm = _transportPricePerKm max 0;
|
||||||
|
|
||||||
private _settings = createHashMapFromArray [
|
private _settings = createHashMapFromArray [
|
||||||
["useMenuSettings", true],
|
["useMenuSettings", true],
|
||||||
@ -145,6 +170,13 @@ GVAR(MissionSetupServiceBaseClass) = compileFinal createHashMapFromArray [
|
|||||||
["penaltyMax", _penMax],
|
["penaltyMax", _penMax],
|
||||||
["timeLimitMin", _timeMin],
|
["timeLimitMin", _timeMin],
|
||||||
["timeLimitMax", _timeMax],
|
["timeLimitMax", _timeMax],
|
||||||
|
["medicalSpawnCost", _medicalSpawnCost],
|
||||||
|
["medicalHealCost", _medicalHealCost],
|
||||||
|
["serviceRepairCost", _serviceRepairCost],
|
||||||
|
["serviceRearmCost", _serviceRearmCost],
|
||||||
|
["fuelCost", _fuelCost],
|
||||||
|
["transportBaseFare", _transportBaseFare],
|
||||||
|
["transportPricePerKm", _transportPricePerKm],
|
||||||
["enemyFaction", _enemyFaction],
|
["enemyFaction", _enemyFaction],
|
||||||
["generatorProvider", _generatorProvider]
|
["generatorProvider", _generatorProvider]
|
||||||
];
|
];
|
||||||
@ -152,6 +184,17 @@ GVAR(MissionSetupServiceBaseClass) = compileFinal createHashMapFromArray [
|
|||||||
SETMPVAR(GVAR(missionSetup_settings),_settings);
|
SETMPVAR(GVAR(missionSetup_settings),_settings);
|
||||||
SETMPVAR(GVAR(missionSetup_settingsApplied),true);
|
SETMPVAR(GVAR(missionSetup_settingsApplied),true);
|
||||||
SETMPVAR(GVAR(generatorProvider),_generatorProvider);
|
SETMPVAR(GVAR(generatorProvider),_generatorProvider);
|
||||||
|
{
|
||||||
|
missionNamespace setVariable [_x, _settings getOrDefault [_x, 0], true];
|
||||||
|
} forEach [
|
||||||
|
"medicalSpawnCost",
|
||||||
|
"medicalHealCost",
|
||||||
|
"serviceRepairCost",
|
||||||
|
"serviceRearmCost",
|
||||||
|
"fuelCost",
|
||||||
|
"transportBaseFare",
|
||||||
|
"transportPricePerKm"
|
||||||
|
];
|
||||||
|
|
||||||
private _side = _self call ["resolveFactionSide", [_enemyFaction, east]];
|
private _side = _self call ["resolveFactionSide", [_enemyFaction, east]];
|
||||||
ENEMY_SIDE = _side;
|
ENEMY_SIDE = _side;
|
||||||
|
|||||||
@ -56,6 +56,9 @@ GVAR(TaskStore) = createHashMapObject [[
|
|||||||
["isTaskCompleted", compileFinal {
|
["isTaskCompleted", compileFinal {
|
||||||
GVAR(TaskCatalogStore) call ["isTaskCompleted", _this]
|
GVAR(TaskCatalogStore) call ["isTaskCompleted", _this]
|
||||||
}],
|
}],
|
||||||
|
["isTerminalStatus", compileFinal {
|
||||||
|
GVAR(TaskCatalogStore) call ["isTerminalStatus", _this]
|
||||||
|
}],
|
||||||
["areTaskPrerequisitesSatisfied", compileFinal {
|
["areTaskPrerequisitesSatisfied", compileFinal {
|
||||||
GVAR(TaskCatalogStore) call ["areTaskPrerequisitesSatisfied", _this]
|
GVAR(TaskCatalogStore) call ["areTaskPrerequisitesSatisfied", _this]
|
||||||
}],
|
}],
|
||||||
|
|||||||
@ -96,10 +96,10 @@ GVAR(AttackTaskBaseClass) merge [createHashMapFromArray [
|
|||||||
|
|
||||||
waitUntil {
|
waitUntil {
|
||||||
sleep 1;
|
sleep 1;
|
||||||
GVAR(TaskStore) call ["isTaskAccepted", [_taskID]]
|
!(_self call ["isTaskStoreOpen", []]) || { GVAR(TaskStore) call ["isTaskAccepted", [_taskID]] }
|
||||||
};
|
};
|
||||||
|
|
||||||
true
|
_self call ["isTaskStoreOpen", []]
|
||||||
}],
|
}],
|
||||||
["tick", compileFinal {
|
["tick", compileFinal {
|
||||||
private _startedAt = _self getOrDefault ["startedAt", -1];
|
private _startedAt = _self getOrDefault ["startedAt", -1];
|
||||||
@ -139,7 +139,7 @@ GVAR(AttackTaskBaseClass) merge [createHashMapFromArray [
|
|||||||
_self call ["refreshTargetsFromStore", []];
|
_self call ["refreshTargetsFromStore", []];
|
||||||
private _targets = _self getOrDefault ["targets", []];
|
private _targets = _self getOrDefault ["targets", []];
|
||||||
GVAR(TaskStore) call ["trackParticipants", [_taskID, _targets, "", 300]];
|
GVAR(TaskStore) call ["trackParticipants", [_taskID, _targets, "", 300]];
|
||||||
count _targets > 0
|
!(_self call ["isTaskStoreOpen", []]) || { count _targets > 0 }
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
waitUntil {
|
waitUntil {
|
||||||
@ -148,10 +148,20 @@ GVAR(AttackTaskBaseClass) merge [createHashMapFromArray [
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
_self call ["waitForAssignment", []];
|
if !(_self call ["isTaskStoreOpen", []]) exitWith {
|
||||||
|
_self call ["markAborted", ["Task reached terminal status before targets registered."]];
|
||||||
|
_self call ["cleanup", []];
|
||||||
|
false
|
||||||
|
};
|
||||||
|
|
||||||
|
if !(_self call ["waitForAssignment", []]) exitWith {
|
||||||
|
_self call ["markAborted", ["Task reached terminal status before assignment."]];
|
||||||
|
_self call ["cleanup", []];
|
||||||
|
false
|
||||||
|
};
|
||||||
_self call ["markActive", []];
|
_self call ["markActive", []];
|
||||||
|
|
||||||
while { (_self call ["getStatus", []]) isEqualTo "active" } do {
|
while { _self call ["isTaskLoopActive", []] } do {
|
||||||
private _targets = _self getOrDefault ["targets", []];
|
private _targets = _self getOrDefault ["targets", []];
|
||||||
|
|
||||||
if (_useTaskStore) then {
|
if (_useTaskStore) then {
|
||||||
@ -186,10 +196,8 @@ GVAR(AttackTaskBaseClass) merge [createHashMapFromArray [
|
|||||||
sleep 1;
|
sleep 1;
|
||||||
};
|
};
|
||||||
|
|
||||||
if ((_self call ["getStatus", []]) isEqualTo "failed") then {
|
private _finalStatus = _self call ["getStatus", []];
|
||||||
private _targets = _self getOrDefault ["targets", []];
|
if (_finalStatus isEqualTo "failed") then {
|
||||||
{ deleteVehicle _x } forEach _targets;
|
|
||||||
|
|
||||||
if (_useTaskStore) then {
|
if (_useTaskStore) then {
|
||||||
[_taskID, "FAILED"] call BFUNC(taskSetState);
|
[_taskID, "FAILED"] call BFUNC(taskSetState);
|
||||||
GVAR(TaskStore) call ["setTaskStatus", [_taskID, "failed"]];
|
GVAR(TaskStore) call ["setTaskStatus", [_taskID, "failed"]];
|
||||||
@ -202,10 +210,9 @@ GVAR(AttackTaskBaseClass) merge [createHashMapFromArray [
|
|||||||
};
|
};
|
||||||
|
|
||||||
if (_endFail) then { "EveryoneLost" call BFUNC(endMissionServer); };
|
if (_endFail) then { "EveryoneLost" call BFUNC(endMissionServer); };
|
||||||
} else {
|
};
|
||||||
private _targets = _self getOrDefault ["targets", []];
|
|
||||||
{ deleteVehicle _x } forEach _targets;
|
|
||||||
|
|
||||||
|
if (_finalStatus isEqualTo "succeeded") then {
|
||||||
if (_useTaskStore) then {
|
if (_useTaskStore) then {
|
||||||
[_taskID, "SUCCEEDED"] call BFUNC(taskSetState);
|
[_taskID, "SUCCEEDED"] call BFUNC(taskSetState);
|
||||||
GVAR(TaskStore) call ["setTaskStatus", [_taskID, "succeeded"]];
|
GVAR(TaskStore) call ["setTaskStatus", [_taskID, "succeeded"]];
|
||||||
|
|||||||
@ -38,6 +38,8 @@ GVAR(CargoEntityController) merge [createHashMapFromArray [
|
|||||||
|
|
||||||
private _taskID = _unit getVariable ["assignedTask", _unit getVariable [QGVAR(assignedTask), ""]];
|
private _taskID = _unit getVariable ["assignedTask", _unit getVariable [QGVAR(assignedTask), ""]];
|
||||||
if (_taskID isEqualTo "") exitWith {};
|
if (_taskID isEqualTo "") exitWith {};
|
||||||
|
private _taskStatus = GVAR(TaskStore) call ["getTaskStatus", [_taskID]];
|
||||||
|
if (GVAR(TaskStore) call ["isTerminalStatus", [_taskStatus]]) exitWith {};
|
||||||
if (_unit getVariable [QGVAR(cargoDamageWarned), false]) exitWith {};
|
if (_unit getVariable [QGVAR(cargoDamageWarned), false]) exitWith {};
|
||||||
|
|
||||||
_unit setVariable [QGVAR(cargoDamageWarned), true];
|
_unit setVariable [QGVAR(cargoDamageWarned), true];
|
||||||
@ -70,7 +72,13 @@ GVAR(CargoEntityController) merge [createHashMapFromArray [
|
|||||||
waitUntil {
|
waitUntil {
|
||||||
sleep 1;
|
sleep 1;
|
||||||
private _entity = _self getOrDefault ["entity", objNull];
|
private _entity = _self getOrDefault ["entity", objNull];
|
||||||
isNull _entity || { !alive _entity } || { damage _entity >= (_self getOrDefault ["damageThreshold", 0.7]) }
|
!(_self call ["isAssignedTaskOpen", []]) || { isNull _entity } || { !alive _entity } || { damage _entity >= (_self getOrDefault ["damageThreshold", 0.7]) }
|
||||||
|
};
|
||||||
|
|
||||||
|
if !(_self call ["isAssignedTaskOpen", []]) exitWith {
|
||||||
|
_self call ["markAborted", []];
|
||||||
|
_self call ["cleanup", []];
|
||||||
|
false
|
||||||
};
|
};
|
||||||
|
|
||||||
_self call ["markFinished", []];
|
_self call ["markFinished", []];
|
||||||
|
|||||||
@ -51,10 +51,10 @@ GVAR(DefendTaskBaseClass) merge [createHashMapFromArray [
|
|||||||
|
|
||||||
waitUntil {
|
waitUntil {
|
||||||
sleep 1;
|
sleep 1;
|
||||||
GVAR(TaskStore) call ["isTaskAccepted", [_taskID]]
|
!(_self call ["isTaskStoreOpen", []]) || { GVAR(TaskStore) call ["isTaskAccepted", [_taskID]] }
|
||||||
};
|
};
|
||||||
|
|
||||||
true
|
_self call ["isTaskStoreOpen", []]
|
||||||
}],
|
}],
|
||||||
["countBluforInZone", compileFinal {
|
["countBluforInZone", compileFinal {
|
||||||
private _defenseZone = _self getOrDefault ["defenseZone", ""];
|
private _defenseZone = _self getOrDefault ["defenseZone", ""];
|
||||||
@ -68,6 +68,7 @@ GVAR(DefendTaskBaseClass) merge [createHashMapFromArray [
|
|||||||
waitUntil {
|
waitUntil {
|
||||||
sleep 1;
|
sleep 1;
|
||||||
_self call ["trackParticipants", []];
|
_self call ["trackParticipants", []];
|
||||||
|
if !(_self call ["isTaskStoreOpen", []]) exitWith { true };
|
||||||
|
|
||||||
private _ready = (_self call ["countBluforInZone", []]) >= _minBlufor;
|
private _ready = (_self call ["countBluforInZone", []]) >= _minBlufor;
|
||||||
if (_ready) then {
|
if (_ready) then {
|
||||||
@ -82,7 +83,7 @@ GVAR(DefendTaskBaseClass) merge [createHashMapFromArray [
|
|||||||
_ready
|
_ready
|
||||||
};
|
};
|
||||||
|
|
||||||
true
|
_self call ["isTaskStoreOpen", []]
|
||||||
}],
|
}],
|
||||||
["tick", compileFinal {
|
["tick", compileFinal {
|
||||||
private _taskID = _self getOrDefault ["taskID", ""];
|
private _taskID = _self getOrDefault ["taskID", ""];
|
||||||
@ -186,10 +187,18 @@ GVAR(DefendTaskBaseClass) merge [createHashMapFromArray [
|
|||||||
false
|
false
|
||||||
};
|
};
|
||||||
|
|
||||||
_self call ["waitForAssignment", []];
|
if !(_self call ["waitForAssignment", []]) exitWith {
|
||||||
_self call ["waitForDefenseStart", []];
|
_self call ["markAborted", ["Task reached terminal status before assignment."]];
|
||||||
|
_self call ["cleanup", []];
|
||||||
|
false
|
||||||
|
};
|
||||||
|
if !(_self call ["waitForDefenseStart", []]) exitWith {
|
||||||
|
_self call ["markAborted", ["Task reached terminal status before defense started."]];
|
||||||
|
_self call ["cleanup", []];
|
||||||
|
false
|
||||||
|
};
|
||||||
|
|
||||||
while { (_self call ["getStatus", []]) isEqualTo "active" } do {
|
while { _self call ["isTaskLoopActive", []] } do {
|
||||||
_self call ["trackParticipants", []];
|
_self call ["trackParticipants", []];
|
||||||
private _snapshot = _self call ["tick", []];
|
private _snapshot = _self call ["tick", []];
|
||||||
|
|
||||||
@ -204,9 +213,12 @@ GVAR(DefendTaskBaseClass) merge [createHashMapFromArray [
|
|||||||
sleep 1;
|
sleep 1;
|
||||||
};
|
};
|
||||||
|
|
||||||
if ((_self call ["getStatus", []]) isEqualTo "failed") then {
|
private _finalStatus = _self call ["getStatus", []];
|
||||||
|
if (_finalStatus isEqualTo "failed") then {
|
||||||
_self call ["handleFailureOutcome", []];
|
_self call ["handleFailureOutcome", []];
|
||||||
} else {
|
};
|
||||||
|
|
||||||
|
if (_finalStatus isEqualTo "succeeded") then {
|
||||||
_self call ["handleSuccessOutcome", []];
|
_self call ["handleSuccessOutcome", []];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -42,7 +42,13 @@ GVAR(DefenseEnemyController) merge [createHashMapFromArray [
|
|||||||
_self call ["markActive", []];
|
_self call ["markActive", []];
|
||||||
waitUntil {
|
waitUntil {
|
||||||
sleep 1;
|
sleep 1;
|
||||||
!(_self call ["isEntityUsable", []])
|
!(_self call ["isAssignedTaskOpen", []]) || { !(_self call ["isEntityUsable", []]) }
|
||||||
|
};
|
||||||
|
|
||||||
|
if !(_self call ["isAssignedTaskOpen", []]) exitWith {
|
||||||
|
_self call ["markAborted", []];
|
||||||
|
_self call ["cleanup", []];
|
||||||
|
false
|
||||||
};
|
};
|
||||||
|
|
||||||
_self call ["markFinished", []];
|
_self call ["markFinished", []];
|
||||||
|
|||||||
@ -103,7 +103,7 @@ GVAR(DefuseTaskBaseClass) merge [createHashMapFromArray [
|
|||||||
waitUntil {
|
waitUntil {
|
||||||
sleep 1;
|
sleep 1;
|
||||||
_self call ["refreshEntitiesFromStore", []];
|
_self call ["refreshEntitiesFromStore", []];
|
||||||
count (_self getOrDefault ["ieds", []]) > 0
|
!(_self call ["isTaskStoreOpen", []]) || { count (_self getOrDefault ["ieds", []]) > 0 }
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
waitUntil {
|
waitUntil {
|
||||||
@ -112,6 +112,8 @@ GVAR(DefuseTaskBaseClass) merge [createHashMapFromArray [
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if !(_self call ["isTaskStoreOpen", []]) exitWith { false };
|
||||||
|
|
||||||
true
|
true
|
||||||
}],
|
}],
|
||||||
["waitForAssignment", compileFinal {
|
["waitForAssignment", compileFinal {
|
||||||
@ -121,10 +123,10 @@ GVAR(DefuseTaskBaseClass) merge [createHashMapFromArray [
|
|||||||
|
|
||||||
waitUntil {
|
waitUntil {
|
||||||
sleep 1;
|
sleep 1;
|
||||||
GVAR(TaskStore) call ["isTaskAccepted", [_taskID]]
|
!(_self call ["isTaskStoreOpen", []]) || { GVAR(TaskStore) call ["isTaskAccepted", [_taskID]] }
|
||||||
};
|
};
|
||||||
|
|
||||||
true
|
_self call ["isTaskStoreOpen", []]
|
||||||
}],
|
}],
|
||||||
["startIedControllers", compileFinal {
|
["startIedControllers", compileFinal {
|
||||||
if ((_self getOrDefault ["iedControllers", []]) isNotEqualTo []) exitWith { true };
|
if ((_self getOrDefault ["iedControllers", []]) isNotEqualTo []) exitWith { true };
|
||||||
@ -194,15 +196,10 @@ GVAR(DefuseTaskBaseClass) merge [createHashMapFromArray [
|
|||||||
}],
|
}],
|
||||||
["handleFailureOutcome", compileFinal {
|
["handleFailureOutcome", compileFinal {
|
||||||
private _taskID = _self getOrDefault ["taskID", ""];
|
private _taskID = _self getOrDefault ["taskID", ""];
|
||||||
private _ieds = _self getOrDefault ["ieds", []];
|
|
||||||
private _protected = _self getOrDefault ["protected", []];
|
|
||||||
private _rewardData = _self getOrDefault ["rewardData", createHashMap];
|
private _rewardData = _self getOrDefault ["rewardData", createHashMap];
|
||||||
private _ratingFail = _rewardData getOrDefault ["ratingFail", 0];
|
private _ratingFail = _rewardData getOrDefault ["ratingFail", 0];
|
||||||
private _endFail = (_self getOrDefault ["taskParams", createHashMap]) getOrDefault ["endFail", false];
|
private _endFail = (_self getOrDefault ["taskParams", createHashMap]) getOrDefault ["endFail", false];
|
||||||
|
|
||||||
{ deleteVehicle _x } forEach _ieds;
|
|
||||||
{ deleteVehicle _x } forEach _protected;
|
|
||||||
|
|
||||||
if (_self getOrDefault ["useTaskStore", false]) then {
|
if (_self getOrDefault ["useTaskStore", false]) then {
|
||||||
[_taskID, "FAILED"] call BFUNC(taskSetState);
|
[_taskID, "FAILED"] call BFUNC(taskSetState);
|
||||||
GVAR(TaskStore) call ["setTaskStatus", [_taskID, "failed"]];
|
GVAR(TaskStore) call ["setTaskStatus", [_taskID, "failed"]];
|
||||||
@ -219,16 +216,11 @@ GVAR(DefuseTaskBaseClass) merge [createHashMapFromArray [
|
|||||||
}],
|
}],
|
||||||
["handleSuccessOutcome", compileFinal {
|
["handleSuccessOutcome", compileFinal {
|
||||||
private _taskID = _self getOrDefault ["taskID", ""];
|
private _taskID = _self getOrDefault ["taskID", ""];
|
||||||
private _ieds = _self getOrDefault ["ieds", []];
|
|
||||||
private _protected = _self getOrDefault ["protected", []];
|
|
||||||
private _rewardData = _self getOrDefault ["rewardData", createHashMap];
|
private _rewardData = _self getOrDefault ["rewardData", createHashMap];
|
||||||
private _ratingSuccess = _rewardData getOrDefault ["ratingSuccess", 0];
|
private _ratingSuccess = _rewardData getOrDefault ["ratingSuccess", 0];
|
||||||
private _funds = _rewardData getOrDefault ["funds", 0];
|
private _funds = _rewardData getOrDefault ["funds", 0];
|
||||||
private _endSuccess = (_self getOrDefault ["taskParams", createHashMap]) getOrDefault ["endSuccess", false];
|
private _endSuccess = (_self getOrDefault ["taskParams", createHashMap]) getOrDefault ["endSuccess", false];
|
||||||
|
|
||||||
{ deleteVehicle _x } forEach _ieds;
|
|
||||||
{ deleteVehicle _x } forEach _protected;
|
|
||||||
|
|
||||||
if (_self getOrDefault ["useTaskStore", false]) then {
|
if (_self getOrDefault ["useTaskStore", false]) then {
|
||||||
[_taskID, "SUCCEEDED"] call BFUNC(taskSetState);
|
[_taskID, "SUCCEEDED"] call BFUNC(taskSetState);
|
||||||
GVAR(TaskStore) call ["setTaskStatus", [_taskID, "succeeded"]];
|
GVAR(TaskStore) call ["setTaskStatus", [_taskID, "succeeded"]];
|
||||||
@ -245,12 +237,20 @@ GVAR(DefuseTaskBaseClass) merge [createHashMapFromArray [
|
|||||||
true
|
true
|
||||||
}],
|
}],
|
||||||
["runLoop", compileFinal {
|
["runLoop", compileFinal {
|
||||||
_self call ["waitForRequiredEntities", []];
|
if !(_self call ["waitForRequiredEntities", []]) exitWith {
|
||||||
_self call ["waitForAssignment", []];
|
_self call ["markAborted", ["Task reached terminal status before required entities registered."]];
|
||||||
|
_self call ["cleanup", []];
|
||||||
|
false
|
||||||
|
};
|
||||||
|
if !(_self call ["waitForAssignment", []]) exitWith {
|
||||||
|
_self call ["markAborted", ["Task reached terminal status before assignment."]];
|
||||||
|
_self call ["cleanup", []];
|
||||||
|
false
|
||||||
|
};
|
||||||
_self call ["startIedControllers", []];
|
_self call ["startIedControllers", []];
|
||||||
_self call ["markActive", []];
|
_self call ["markActive", []];
|
||||||
|
|
||||||
while { (_self call ["getStatus", []]) isEqualTo "active" } do {
|
while { _self call ["isTaskLoopActive", []] } do {
|
||||||
_self call ["trackParticipants", []];
|
_self call ["trackParticipants", []];
|
||||||
private _snapshot = _self call ["tick", []];
|
private _snapshot = _self call ["tick", []];
|
||||||
|
|
||||||
@ -265,9 +265,12 @@ GVAR(DefuseTaskBaseClass) merge [createHashMapFromArray [
|
|||||||
sleep 1;
|
sleep 1;
|
||||||
};
|
};
|
||||||
|
|
||||||
if ((_self call ["getStatus", []]) isEqualTo "failed") then {
|
private _finalStatus = _self call ["getStatus", []];
|
||||||
|
if (_finalStatus isEqualTo "failed") then {
|
||||||
_self call ["handleFailureOutcome", []];
|
_self call ["handleFailureOutcome", []];
|
||||||
} else {
|
};
|
||||||
|
|
||||||
|
if (_finalStatus isEqualTo "succeeded") then {
|
||||||
_self call ["handleSuccessOutcome", []];
|
_self call ["handleSuccessOutcome", []];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -57,7 +57,7 @@ GVAR(DeliveryTaskBaseClass) merge [createHashMapFromArray [
|
|||||||
sleep 1;
|
sleep 1;
|
||||||
_self call ["refreshEntitiesFromStore", []];
|
_self call ["refreshEntitiesFromStore", []];
|
||||||
_self call ["trackParticipants", []];
|
_self call ["trackParticipants", []];
|
||||||
count (_self getOrDefault ["cargo", []]) > 0
|
!(_self call ["isTaskStoreOpen", []]) || { count (_self getOrDefault ["cargo", []]) > 0 }
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
waitUntil {
|
waitUntil {
|
||||||
@ -66,6 +66,8 @@ GVAR(DeliveryTaskBaseClass) merge [createHashMapFromArray [
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if !(_self call ["isTaskStoreOpen", []]) exitWith { false };
|
||||||
|
|
||||||
private _cargo = _self getOrDefault ["cargo", []];
|
private _cargo = _self getOrDefault ["cargo", []];
|
||||||
private _taskParams = _self getOrDefault ["taskParams", createHashMap];
|
private _taskParams = _self getOrDefault ["taskParams", createHashMap];
|
||||||
private _requiredDelivered = _taskParams getOrDefault ["limitSuccess", -1];
|
private _requiredDelivered = _taskParams getOrDefault ["limitSuccess", -1];
|
||||||
@ -85,10 +87,10 @@ GVAR(DeliveryTaskBaseClass) merge [createHashMapFromArray [
|
|||||||
|
|
||||||
waitUntil {
|
waitUntil {
|
||||||
sleep 1;
|
sleep 1;
|
||||||
GVAR(TaskStore) call ["isTaskAccepted", [_taskID]]
|
!(_self call ["isTaskStoreOpen", []]) || { GVAR(TaskStore) call ["isTaskAccepted", [_taskID]] }
|
||||||
};
|
};
|
||||||
|
|
||||||
true
|
_self call ["isTaskStoreOpen", []]
|
||||||
}],
|
}],
|
||||||
["countDeliveredCargo", compileFinal {
|
["countDeliveredCargo", compileFinal {
|
||||||
private _deliveryZone = _self getOrDefault ["deliveryZone", ""];
|
private _deliveryZone = _self getOrDefault ["deliveryZone", ""];
|
||||||
@ -126,13 +128,10 @@ GVAR(DeliveryTaskBaseClass) merge [createHashMapFromArray [
|
|||||||
}],
|
}],
|
||||||
["handleFailureOutcome", compileFinal {
|
["handleFailureOutcome", compileFinal {
|
||||||
private _taskID = _self getOrDefault ["taskID", ""];
|
private _taskID = _self getOrDefault ["taskID", ""];
|
||||||
private _cargo = _self getOrDefault ["cargo", []];
|
|
||||||
private _rewardData = _self getOrDefault ["rewardData", createHashMap];
|
private _rewardData = _self getOrDefault ["rewardData", createHashMap];
|
||||||
private _ratingFail = _rewardData getOrDefault ["ratingFail", 0];
|
private _ratingFail = _rewardData getOrDefault ["ratingFail", 0];
|
||||||
private _endFail = (_self getOrDefault ["taskParams", createHashMap]) getOrDefault ["endFail", false];
|
private _endFail = (_self getOrDefault ["taskParams", createHashMap]) getOrDefault ["endFail", false];
|
||||||
|
|
||||||
{ deleteVehicle _x } forEach _cargo;
|
|
||||||
|
|
||||||
if (_self getOrDefault ["useTaskStore", false]) then {
|
if (_self getOrDefault ["useTaskStore", false]) then {
|
||||||
[_taskID, "FAILED"] call BFUNC(taskSetState);
|
[_taskID, "FAILED"] call BFUNC(taskSetState);
|
||||||
GVAR(TaskStore) call ["setTaskStatus", [_taskID, "failed"]];
|
GVAR(TaskStore) call ["setTaskStatus", [_taskID, "failed"]];
|
||||||
@ -149,14 +148,11 @@ GVAR(DeliveryTaskBaseClass) merge [createHashMapFromArray [
|
|||||||
}],
|
}],
|
||||||
["handleSuccessOutcome", compileFinal {
|
["handleSuccessOutcome", compileFinal {
|
||||||
private _taskID = _self getOrDefault ["taskID", ""];
|
private _taskID = _self getOrDefault ["taskID", ""];
|
||||||
private _cargo = _self getOrDefault ["cargo", []];
|
|
||||||
private _rewardData = _self getOrDefault ["rewardData", createHashMap];
|
private _rewardData = _self getOrDefault ["rewardData", createHashMap];
|
||||||
private _ratingSuccess = _rewardData getOrDefault ["ratingSuccess", 0];
|
private _ratingSuccess = _rewardData getOrDefault ["ratingSuccess", 0];
|
||||||
private _funds = _rewardData getOrDefault ["funds", 0];
|
private _funds = _rewardData getOrDefault ["funds", 0];
|
||||||
private _endSuccess = (_self getOrDefault ["taskParams", createHashMap]) getOrDefault ["endSuccess", false];
|
private _endSuccess = (_self getOrDefault ["taskParams", createHashMap]) getOrDefault ["endSuccess", false];
|
||||||
|
|
||||||
{ deleteVehicle _x } forEach _cargo;
|
|
||||||
|
|
||||||
if (_self getOrDefault ["useTaskStore", false]) then {
|
if (_self getOrDefault ["useTaskStore", false]) then {
|
||||||
[_taskID, "SUCCEEDED"] call BFUNC(taskSetState);
|
[_taskID, "SUCCEEDED"] call BFUNC(taskSetState);
|
||||||
GVAR(TaskStore) call ["setTaskStatus", [_taskID, "succeeded"]];
|
GVAR(TaskStore) call ["setTaskStatus", [_taskID, "succeeded"]];
|
||||||
@ -173,11 +169,19 @@ GVAR(DeliveryTaskBaseClass) merge [createHashMapFromArray [
|
|||||||
true
|
true
|
||||||
}],
|
}],
|
||||||
["runLoop", compileFinal {
|
["runLoop", compileFinal {
|
||||||
_self call ["waitForRequiredEntities", []];
|
if !(_self call ["waitForRequiredEntities", []]) exitWith {
|
||||||
_self call ["waitForAssignment", []];
|
_self call ["markAborted", ["Task reached terminal status before required entities registered."]];
|
||||||
|
_self call ["cleanup", []];
|
||||||
|
false
|
||||||
|
};
|
||||||
|
if !(_self call ["waitForAssignment", []]) exitWith {
|
||||||
|
_self call ["markAborted", ["Task reached terminal status before assignment."]];
|
||||||
|
_self call ["cleanup", []];
|
||||||
|
false
|
||||||
|
};
|
||||||
_self call ["markActive", []];
|
_self call ["markActive", []];
|
||||||
|
|
||||||
while { (_self call ["getStatus", []]) isEqualTo "active" } do {
|
while { _self call ["isTaskLoopActive", []] } do {
|
||||||
_self call ["trackParticipants", []];
|
_self call ["trackParticipants", []];
|
||||||
private _snapshot = _self call ["tick", []];
|
private _snapshot = _self call ["tick", []];
|
||||||
|
|
||||||
@ -192,9 +196,12 @@ GVAR(DeliveryTaskBaseClass) merge [createHashMapFromArray [
|
|||||||
sleep 1;
|
sleep 1;
|
||||||
};
|
};
|
||||||
|
|
||||||
if ((_self call ["getStatus", []]) isEqualTo "failed") then {
|
private _finalStatus = _self call ["getStatus", []];
|
||||||
|
if (_finalStatus isEqualTo "failed") then {
|
||||||
_self call ["handleFailureOutcome", []];
|
_self call ["handleFailureOutcome", []];
|
||||||
} else {
|
};
|
||||||
|
|
||||||
|
if (_finalStatus isEqualTo "succeeded") then {
|
||||||
_self call ["handleSuccessOutcome", []];
|
_self call ["handleSuccessOutcome", []];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -52,7 +52,7 @@ GVAR(DestroyTaskBaseClass) merge [createHashMapFromArray [
|
|||||||
sleep 1;
|
sleep 1;
|
||||||
_self call ["refreshEntitiesFromStore", []];
|
_self call ["refreshEntitiesFromStore", []];
|
||||||
_self call ["trackParticipants", []];
|
_self call ["trackParticipants", []];
|
||||||
count (_self getOrDefault ["targets", []]) > 0
|
!(_self call ["isTaskStoreOpen", []]) || { count (_self getOrDefault ["targets", []]) > 0 }
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
waitUntil {
|
waitUntil {
|
||||||
@ -61,6 +61,8 @@ GVAR(DestroyTaskBaseClass) merge [createHashMapFromArray [
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if !(_self call ["isTaskStoreOpen", []]) exitWith { false };
|
||||||
|
|
||||||
private _targets = _self getOrDefault ["targets", []];
|
private _targets = _self getOrDefault ["targets", []];
|
||||||
private _taskParams = _self getOrDefault ["taskParams", createHashMap];
|
private _taskParams = _self getOrDefault ["taskParams", createHashMap];
|
||||||
private _requiredDestroyed = _taskParams getOrDefault ["limitSuccess", -1];
|
private _requiredDestroyed = _taskParams getOrDefault ["limitSuccess", -1];
|
||||||
@ -76,10 +78,10 @@ GVAR(DestroyTaskBaseClass) merge [createHashMapFromArray [
|
|||||||
|
|
||||||
waitUntil {
|
waitUntil {
|
||||||
sleep 1;
|
sleep 1;
|
||||||
GVAR(TaskStore) call ["isTaskAccepted", [_taskID]]
|
!(_self call ["isTaskStoreOpen", []]) || { GVAR(TaskStore) call ["isTaskAccepted", [_taskID]] }
|
||||||
};
|
};
|
||||||
|
|
||||||
true
|
_self call ["isTaskStoreOpen", []]
|
||||||
}],
|
}],
|
||||||
["countDestroyedTargets", compileFinal {
|
["countDestroyedTargets", compileFinal {
|
||||||
private _targets = _self getOrDefault ["targets", []];
|
private _targets = _self getOrDefault ["targets", []];
|
||||||
@ -106,13 +108,10 @@ GVAR(DestroyTaskBaseClass) merge [createHashMapFromArray [
|
|||||||
}],
|
}],
|
||||||
["handleFailureOutcome", compileFinal {
|
["handleFailureOutcome", compileFinal {
|
||||||
private _taskID = _self getOrDefault ["taskID", ""];
|
private _taskID = _self getOrDefault ["taskID", ""];
|
||||||
private _targets = _self getOrDefault ["targets", []];
|
|
||||||
private _rewardData = _self getOrDefault ["rewardData", createHashMap];
|
private _rewardData = _self getOrDefault ["rewardData", createHashMap];
|
||||||
private _ratingFail = _rewardData getOrDefault ["ratingFail", 0];
|
private _ratingFail = _rewardData getOrDefault ["ratingFail", 0];
|
||||||
private _endFail = (_self getOrDefault ["taskParams", createHashMap]) getOrDefault ["endFail", false];
|
private _endFail = (_self getOrDefault ["taskParams", createHashMap]) getOrDefault ["endFail", false];
|
||||||
|
|
||||||
{ deleteVehicle _x } forEach _targets;
|
|
||||||
|
|
||||||
if (_self getOrDefault ["useTaskStore", false]) then {
|
if (_self getOrDefault ["useTaskStore", false]) then {
|
||||||
[_taskID, "FAILED"] call BFUNC(taskSetState);
|
[_taskID, "FAILED"] call BFUNC(taskSetState);
|
||||||
GVAR(TaskStore) call ["setTaskStatus", [_taskID, "failed"]];
|
GVAR(TaskStore) call ["setTaskStatus", [_taskID, "failed"]];
|
||||||
@ -129,14 +128,11 @@ GVAR(DestroyTaskBaseClass) merge [createHashMapFromArray [
|
|||||||
}],
|
}],
|
||||||
["handleSuccessOutcome", compileFinal {
|
["handleSuccessOutcome", compileFinal {
|
||||||
private _taskID = _self getOrDefault ["taskID", ""];
|
private _taskID = _self getOrDefault ["taskID", ""];
|
||||||
private _targets = _self getOrDefault ["targets", []];
|
|
||||||
private _rewardData = _self getOrDefault ["rewardData", createHashMap];
|
private _rewardData = _self getOrDefault ["rewardData", createHashMap];
|
||||||
private _ratingSuccess = _rewardData getOrDefault ["ratingSuccess", 0];
|
private _ratingSuccess = _rewardData getOrDefault ["ratingSuccess", 0];
|
||||||
private _funds = _rewardData getOrDefault ["funds", 0];
|
private _funds = _rewardData getOrDefault ["funds", 0];
|
||||||
private _endSuccess = (_self getOrDefault ["taskParams", createHashMap]) getOrDefault ["endSuccess", false];
|
private _endSuccess = (_self getOrDefault ["taskParams", createHashMap]) getOrDefault ["endSuccess", false];
|
||||||
|
|
||||||
{ deleteVehicle _x } forEach _targets;
|
|
||||||
|
|
||||||
if (_self getOrDefault ["useTaskStore", false]) then {
|
if (_self getOrDefault ["useTaskStore", false]) then {
|
||||||
[_taskID, "SUCCEEDED"] call BFUNC(taskSetState);
|
[_taskID, "SUCCEEDED"] call BFUNC(taskSetState);
|
||||||
GVAR(TaskStore) call ["setTaskStatus", [_taskID, "succeeded"]];
|
GVAR(TaskStore) call ["setTaskStatus", [_taskID, "succeeded"]];
|
||||||
@ -153,11 +149,19 @@ GVAR(DestroyTaskBaseClass) merge [createHashMapFromArray [
|
|||||||
true
|
true
|
||||||
}],
|
}],
|
||||||
["runLoop", compileFinal {
|
["runLoop", compileFinal {
|
||||||
_self call ["waitForRequiredEntities", []];
|
if !(_self call ["waitForRequiredEntities", []]) exitWith {
|
||||||
_self call ["waitForAssignment", []];
|
_self call ["markAborted", ["Task reached terminal status before required entities registered."]];
|
||||||
|
_self call ["cleanup", []];
|
||||||
|
false
|
||||||
|
};
|
||||||
|
if !(_self call ["waitForAssignment", []]) exitWith {
|
||||||
|
_self call ["markAborted", ["Task reached terminal status before assignment."]];
|
||||||
|
_self call ["cleanup", []];
|
||||||
|
false
|
||||||
|
};
|
||||||
_self call ["markActive", []];
|
_self call ["markActive", []];
|
||||||
|
|
||||||
while { (_self call ["getStatus", []]) isEqualTo "active" } do {
|
while { _self call ["isTaskLoopActive", []] } do {
|
||||||
_self call ["trackParticipants", []];
|
_self call ["trackParticipants", []];
|
||||||
private _snapshot = _self call ["tick", []];
|
private _snapshot = _self call ["tick", []];
|
||||||
|
|
||||||
@ -172,9 +176,12 @@ GVAR(DestroyTaskBaseClass) merge [createHashMapFromArray [
|
|||||||
sleep 1;
|
sleep 1;
|
||||||
};
|
};
|
||||||
|
|
||||||
if ((_self call ["getStatus", []]) isEqualTo "failed") then {
|
private _finalStatus = _self call ["getStatus", []];
|
||||||
|
if (_finalStatus isEqualTo "failed") then {
|
||||||
_self call ["handleFailureOutcome", []];
|
_self call ["handleFailureOutcome", []];
|
||||||
} else {
|
};
|
||||||
|
|
||||||
|
if (_finalStatus isEqualTo "succeeded") then {
|
||||||
_self call ["handleSuccessOutcome", []];
|
_self call ["handleSuccessOutcome", []];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -76,6 +76,20 @@ GVAR(EntityControllerBaseClass) = createHashMapFromArray [
|
|||||||
private _entity = _self getOrDefault ["entity", objNull];
|
private _entity = _self getOrDefault ["entity", objNull];
|
||||||
!isNull _entity && { alive _entity }
|
!isNull _entity && { alive _entity }
|
||||||
}],
|
}],
|
||||||
|
["isTerminalStatus", compileFinal {
|
||||||
|
params [["_status", "", [""]]];
|
||||||
|
|
||||||
|
(toLowerANSI _status) in ["failed", "succeeded"]
|
||||||
|
}],
|
||||||
|
["isAssignedTaskOpen", compileFinal {
|
||||||
|
private _taskID = _self getOrDefault ["taskID", ""];
|
||||||
|
if (_taskID isEqualTo "" || { isNil QGVAR(TaskStore) }) exitWith { true };
|
||||||
|
|
||||||
|
private _status = GVAR(TaskStore) call ["getTaskStatus", [_taskID]];
|
||||||
|
if (_status isEqualTo "") exitWith { true };
|
||||||
|
|
||||||
|
!(_self call ["isTerminalStatus", [_status]])
|
||||||
|
}],
|
||||||
["assignTaskVariable", compileFinal {
|
["assignTaskVariable", compileFinal {
|
||||||
private _entity = _self getOrDefault ["entity", objNull];
|
private _entity = _self getOrDefault ["entity", objNull];
|
||||||
private _taskID = _self getOrDefault ["taskID", ""];
|
private _taskID = _self getOrDefault ["taskID", ""];
|
||||||
|
|||||||
@ -52,12 +52,19 @@ GVAR(HVTEntityController) merge [createHashMapFromArray [
|
|||||||
private _capturer = objNull;
|
private _capturer = objNull;
|
||||||
waitUntil {
|
waitUntil {
|
||||||
sleep 1;
|
sleep 1;
|
||||||
|
if !(_self call ["isAssignedTaskOpen", []]) exitWith { true };
|
||||||
if !(_self call ["isEntityUsable", []]) exitWith { true };
|
if !(_self call ["isEntityUsable", []]) exitWith { true };
|
||||||
|
|
||||||
_capturer = _self call ["findNearbyCapturer", []];
|
_capturer = _self call ["findNearbyCapturer", []];
|
||||||
!isNull _capturer
|
!isNull _capturer
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if !(_self call ["isAssignedTaskOpen", []]) exitWith {
|
||||||
|
_self call ["markAborted", []];
|
||||||
|
_self call ["cleanup", []];
|
||||||
|
false
|
||||||
|
};
|
||||||
|
|
||||||
if !(_self call ["isEntityUsable", []]) exitWith {
|
if !(_self call ["isEntityUsable", []]) exitWith {
|
||||||
_self call ["markAborted", []];
|
_self call ["markAborted", []];
|
||||||
_self call ["cleanup", []];
|
_self call ["cleanup", []];
|
||||||
|
|||||||
@ -70,7 +70,7 @@ GVAR(HVTTaskBaseClass) merge [createHashMapFromArray [
|
|||||||
sleep 1;
|
sleep 1;
|
||||||
_self call ["refreshEntitiesFromStore", []];
|
_self call ["refreshEntitiesFromStore", []];
|
||||||
_self call ["trackParticipants", []];
|
_self call ["trackParticipants", []];
|
||||||
count (_self getOrDefault ["hvts", []]) > 0
|
!(_self call ["isTaskStoreOpen", []]) || { count (_self getOrDefault ["hvts", []]) > 0 }
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
waitUntil {
|
waitUntil {
|
||||||
@ -79,6 +79,8 @@ GVAR(HVTTaskBaseClass) merge [createHashMapFromArray [
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if !(_self call ["isTaskStoreOpen", []]) exitWith { false };
|
||||||
|
|
||||||
private _hvts = _self getOrDefault ["hvts", []];
|
private _hvts = _self getOrDefault ["hvts", []];
|
||||||
private _taskParams = _self getOrDefault ["taskParams", createHashMap];
|
private _taskParams = _self getOrDefault ["taskParams", createHashMap];
|
||||||
private _required = _taskParams getOrDefault ["limitSuccess", -1];
|
private _required = _taskParams getOrDefault ["limitSuccess", -1];
|
||||||
@ -122,10 +124,10 @@ GVAR(HVTTaskBaseClass) merge [createHashMapFromArray [
|
|||||||
|
|
||||||
waitUntil {
|
waitUntil {
|
||||||
sleep 1;
|
sleep 1;
|
||||||
GVAR(TaskStore) call ["isTaskAccepted", [_taskID]]
|
!(_self call ["isTaskStoreOpen", []]) || { GVAR(TaskStore) call ["isTaskAccepted", [_taskID]] }
|
||||||
};
|
};
|
||||||
|
|
||||||
true
|
_self call ["isTaskStoreOpen", []]
|
||||||
}],
|
}],
|
||||||
["tick", compileFinal {
|
["tick", compileFinal {
|
||||||
private _startedAt = _self getOrDefault ["startedAt", -1];
|
private _startedAt = _self getOrDefault ["startedAt", -1];
|
||||||
@ -161,13 +163,10 @@ GVAR(HVTTaskBaseClass) merge [createHashMapFromArray [
|
|||||||
}],
|
}],
|
||||||
["handleFailureOutcome", compileFinal {
|
["handleFailureOutcome", compileFinal {
|
||||||
private _taskID = _self getOrDefault ["taskID", ""];
|
private _taskID = _self getOrDefault ["taskID", ""];
|
||||||
private _hvts = _self getOrDefault ["hvts", []];
|
|
||||||
private _rewardData = _self getOrDefault ["rewardData", createHashMap];
|
private _rewardData = _self getOrDefault ["rewardData", createHashMap];
|
||||||
private _ratingFail = _rewardData getOrDefault ["ratingFail", 0];
|
private _ratingFail = _rewardData getOrDefault ["ratingFail", 0];
|
||||||
private _endFail = (_self getOrDefault ["taskParams", createHashMap]) getOrDefault ["endFail", false];
|
private _endFail = (_self getOrDefault ["taskParams", createHashMap]) getOrDefault ["endFail", false];
|
||||||
|
|
||||||
{ deleteVehicle _x } forEach _hvts;
|
|
||||||
|
|
||||||
if (_self getOrDefault ["useTaskStore", false]) then {
|
if (_self getOrDefault ["useTaskStore", false]) then {
|
||||||
[_taskID, "FAILED"] call BFUNC(taskSetState);
|
[_taskID, "FAILED"] call BFUNC(taskSetState);
|
||||||
GVAR(TaskStore) call ["setTaskStatus", [_taskID, "failed"]];
|
GVAR(TaskStore) call ["setTaskStatus", [_taskID, "failed"]];
|
||||||
@ -184,14 +183,11 @@ GVAR(HVTTaskBaseClass) merge [createHashMapFromArray [
|
|||||||
}],
|
}],
|
||||||
["handleSuccessOutcome", compileFinal {
|
["handleSuccessOutcome", compileFinal {
|
||||||
private _taskID = _self getOrDefault ["taskID", ""];
|
private _taskID = _self getOrDefault ["taskID", ""];
|
||||||
private _hvts = _self getOrDefault ["hvts", []];
|
|
||||||
private _rewardData = _self getOrDefault ["rewardData", createHashMap];
|
private _rewardData = _self getOrDefault ["rewardData", createHashMap];
|
||||||
private _ratingSuccess = _rewardData getOrDefault ["ratingSuccess", 0];
|
private _ratingSuccess = _rewardData getOrDefault ["ratingSuccess", 0];
|
||||||
private _funds = _rewardData getOrDefault ["funds", 0];
|
private _funds = _rewardData getOrDefault ["funds", 0];
|
||||||
private _endSuccess = (_self getOrDefault ["taskParams", createHashMap]) getOrDefault ["endSuccess", false];
|
private _endSuccess = (_self getOrDefault ["taskParams", createHashMap]) getOrDefault ["endSuccess", false];
|
||||||
|
|
||||||
{ deleteVehicle _x } forEach _hvts;
|
|
||||||
|
|
||||||
if (_self getOrDefault ["useTaskStore", false]) then {
|
if (_self getOrDefault ["useTaskStore", false]) then {
|
||||||
[_taskID, "SUCCEEDED"] call BFUNC(taskSetState);
|
[_taskID, "SUCCEEDED"] call BFUNC(taskSetState);
|
||||||
GVAR(TaskStore) call ["setTaskStatus", [_taskID, "succeeded"]];
|
GVAR(TaskStore) call ["setTaskStatus", [_taskID, "succeeded"]];
|
||||||
@ -208,12 +204,20 @@ GVAR(HVTTaskBaseClass) merge [createHashMapFromArray [
|
|||||||
true
|
true
|
||||||
}],
|
}],
|
||||||
["runLoop", compileFinal {
|
["runLoop", compileFinal {
|
||||||
_self call ["waitForRequiredEntities", []];
|
if !(_self call ["waitForRequiredEntities", []]) exitWith {
|
||||||
_self call ["waitForAssignment", []];
|
_self call ["markAborted", ["Task reached terminal status before required entities registered."]];
|
||||||
|
_self call ["cleanup", []];
|
||||||
|
false
|
||||||
|
};
|
||||||
|
if !(_self call ["waitForAssignment", []]) exitWith {
|
||||||
|
_self call ["markAborted", ["Task reached terminal status before assignment."]];
|
||||||
|
_self call ["cleanup", []];
|
||||||
|
false
|
||||||
|
};
|
||||||
_self call ["startHvtControllers", []];
|
_self call ["startHvtControllers", []];
|
||||||
_self call ["markActive", []];
|
_self call ["markActive", []];
|
||||||
|
|
||||||
while { (_self call ["getStatus", []]) isEqualTo "active" } do {
|
while { _self call ["isTaskLoopActive", []] } do {
|
||||||
_self call ["trackParticipants", []];
|
_self call ["trackParticipants", []];
|
||||||
private _snapshot = _self call ["tick", []];
|
private _snapshot = _self call ["tick", []];
|
||||||
|
|
||||||
@ -228,9 +232,12 @@ GVAR(HVTTaskBaseClass) merge [createHashMapFromArray [
|
|||||||
sleep 1;
|
sleep 1;
|
||||||
};
|
};
|
||||||
|
|
||||||
if ((_self call ["getStatus", []]) isEqualTo "failed") then {
|
private _finalStatus = _self call ["getStatus", []];
|
||||||
|
if (_finalStatus isEqualTo "failed") then {
|
||||||
_self call ["handleFailureOutcome", []];
|
_self call ["handleFailureOutcome", []];
|
||||||
} else {
|
};
|
||||||
|
|
||||||
|
if (_finalStatus isEqualTo "succeeded") then {
|
||||||
_self call ["handleSuccessOutcome", []];
|
_self call ["handleSuccessOutcome", []];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -103,12 +103,19 @@ GVAR(HostageEntityController) merge [createHashMapFromArray [
|
|||||||
waitUntil {
|
waitUntil {
|
||||||
sleep 1;
|
sleep 1;
|
||||||
|
|
||||||
|
if !(_self call ["isAssignedTaskOpen", []]) exitWith { true };
|
||||||
if (isNull _entity || { !alive _entity }) exitWith { true };
|
if (isNull _entity || { !alive _entity }) exitWith { true };
|
||||||
|
|
||||||
_rescuer = _self call ["findNearbyRescuer", []];
|
_rescuer = _self call ["findNearbyRescuer", []];
|
||||||
!isNull _rescuer
|
!isNull _rescuer
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if !(_self call ["isAssignedTaskOpen", []]) exitWith {
|
||||||
|
_self call ["markAborted", []];
|
||||||
|
_self call ["cleanup", []];
|
||||||
|
false
|
||||||
|
};
|
||||||
|
|
||||||
if (isNull _entity || { !alive _entity }) exitWith {
|
if (isNull _entity || { !alive _entity }) exitWith {
|
||||||
_self call ["markAborted", []];
|
_self call ["markAborted", []];
|
||||||
_self call ["cleanup", []];
|
_self call ["cleanup", []];
|
||||||
|
|||||||
@ -150,14 +150,15 @@ GVAR(HostageTaskBaseClass) merge [createHashMapFromArray [
|
|||||||
waitUntil {
|
waitUntil {
|
||||||
sleep 1;
|
sleep 1;
|
||||||
_self call ["refreshEntitiesFromStore", []];
|
_self call ["refreshEntitiesFromStore", []];
|
||||||
count (_self getOrDefault ["hostages", []]) > 0
|
!(_self call ["isTaskStoreOpen", []]) || { count (_self getOrDefault ["hostages", []]) > 0 }
|
||||||
};
|
};
|
||||||
|
if !(_self call ["isTaskStoreOpen", []]) exitWith { false };
|
||||||
|
|
||||||
waitUntil {
|
waitUntil {
|
||||||
sleep 1;
|
sleep 1;
|
||||||
_self call ["refreshEntitiesFromStore", []];
|
_self call ["refreshEntitiesFromStore", []];
|
||||||
_self call ["trackParticipants", []];
|
_self call ["trackParticipants", []];
|
||||||
count (_self getOrDefault ["shooters", []]) > 0
|
!(_self call ["isTaskStoreOpen", []]) || { count (_self getOrDefault ["shooters", []]) > 0 }
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
waitUntil {
|
waitUntil {
|
||||||
@ -171,6 +172,8 @@ GVAR(HostageTaskBaseClass) merge [createHashMapFromArray [
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if !(_self call ["isTaskStoreOpen", []]) exitWith { false };
|
||||||
|
|
||||||
private _hostages = _self getOrDefault ["hostages", []];
|
private _hostages = _self getOrDefault ["hostages", []];
|
||||||
private _taskParams = _self getOrDefault ["taskParams", createHashMap];
|
private _taskParams = _self getOrDefault ["taskParams", createHashMap];
|
||||||
private _requiredRescues = _taskParams getOrDefault ["limitSuccess", -1];
|
private _requiredRescues = _taskParams getOrDefault ["limitSuccess", -1];
|
||||||
@ -190,10 +193,10 @@ GVAR(HostageTaskBaseClass) merge [createHashMapFromArray [
|
|||||||
|
|
||||||
waitUntil {
|
waitUntil {
|
||||||
sleep 1;
|
sleep 1;
|
||||||
GVAR(TaskStore) call ["isTaskAccepted", [_taskID]]
|
!(_self call ["isTaskStoreOpen", []]) || { GVAR(TaskStore) call ["isTaskAccepted", [_taskID]] }
|
||||||
};
|
};
|
||||||
|
|
||||||
true
|
_self call ["isTaskStoreOpen", []]
|
||||||
}],
|
}],
|
||||||
["countFreedHostages", compileFinal {
|
["countFreedHostages", compileFinal {
|
||||||
private _playerGroups = allPlayers apply { group _x };
|
private _playerGroups = allPlayers apply { group _x };
|
||||||
@ -290,11 +293,9 @@ GVAR(HostageTaskBaseClass) merge [createHashMapFromArray [
|
|||||||
sleep 5;
|
sleep 5;
|
||||||
};
|
};
|
||||||
|
|
||||||
{ deleteVehicle _x } forEach _hostages;
|
|
||||||
{ deleteVehicle _x } forEach _shooters;
|
|
||||||
|
|
||||||
if (_useTaskStore) then {
|
if (_useTaskStore) then {
|
||||||
[_taskID, "FAILED"] call BFUNC(taskSetState);
|
[_taskID, "FAILED"] call BFUNC(taskSetState);
|
||||||
|
GVAR(TaskStore) call ["setTaskStatus", [_taskID, "failed"]];
|
||||||
|
|
||||||
sleep 1;
|
sleep 1;
|
||||||
|
|
||||||
@ -308,17 +309,12 @@ GVAR(HostageTaskBaseClass) merge [createHashMapFromArray [
|
|||||||
}],
|
}],
|
||||||
["handleSuccessOutcome", compileFinal {
|
["handleSuccessOutcome", compileFinal {
|
||||||
private _taskID = _self getOrDefault ["taskID", ""];
|
private _taskID = _self getOrDefault ["taskID", ""];
|
||||||
private _hostages = _self getOrDefault ["hostages", []];
|
|
||||||
private _shooters = _self getOrDefault ["shooters", []];
|
|
||||||
private _rewardData = _self getOrDefault ["rewardData", createHashMap];
|
private _rewardData = _self getOrDefault ["rewardData", createHashMap];
|
||||||
private _ratingSuccess = _rewardData getOrDefault ["ratingSuccess", 0];
|
private _ratingSuccess = _rewardData getOrDefault ["ratingSuccess", 0];
|
||||||
private _funds = _rewardData getOrDefault ["funds", 0];
|
private _funds = _rewardData getOrDefault ["funds", 0];
|
||||||
private _endSuccess = (_self getOrDefault ["taskParams", createHashMap]) getOrDefault ["endSuccess", false];
|
private _endSuccess = (_self getOrDefault ["taskParams", createHashMap]) getOrDefault ["endSuccess", false];
|
||||||
private _useTaskStore = _self getOrDefault ["useTaskStore", false];
|
private _useTaskStore = _self getOrDefault ["useTaskStore", false];
|
||||||
|
|
||||||
{ deleteVehicle _x } forEach _hostages;
|
|
||||||
{ deleteVehicle _x } forEach _shooters;
|
|
||||||
|
|
||||||
if (_useTaskStore) then {
|
if (_useTaskStore) then {
|
||||||
[_taskID, "SUCCEEDED"] call BFUNC(taskSetState);
|
[_taskID, "SUCCEEDED"] call BFUNC(taskSetState);
|
||||||
GVAR(TaskStore) call ["setTaskStatus", [_taskID, "succeeded"]];
|
GVAR(TaskStore) call ["setTaskStatus", [_taskID, "succeeded"]];
|
||||||
@ -335,12 +331,20 @@ GVAR(HostageTaskBaseClass) merge [createHashMapFromArray [
|
|||||||
true
|
true
|
||||||
}],
|
}],
|
||||||
["runLoop", compileFinal {
|
["runLoop", compileFinal {
|
||||||
_self call ["waitForRequiredEntities", []];
|
if !(_self call ["waitForRequiredEntities", []]) exitWith {
|
||||||
_self call ["waitForAssignment", []];
|
_self call ["markAborted", ["Task reached terminal status before required entities registered."]];
|
||||||
|
_self call ["cleanup", []];
|
||||||
|
false
|
||||||
|
};
|
||||||
|
if !(_self call ["waitForAssignment", []]) exitWith {
|
||||||
|
_self call ["markAborted", ["Task reached terminal status before assignment."]];
|
||||||
|
_self call ["cleanup", []];
|
||||||
|
false
|
||||||
|
};
|
||||||
_self call ["startHostageControllers", []];
|
_self call ["startHostageControllers", []];
|
||||||
_self call ["markActive", []];
|
_self call ["markActive", []];
|
||||||
|
|
||||||
while { (_self call ["getStatus", []]) isEqualTo "active" } do {
|
while { _self call ["isTaskLoopActive", []] } do {
|
||||||
_self call ["trackParticipants", []];
|
_self call ["trackParticipants", []];
|
||||||
private _snapshot = _self call ["tick", []];
|
private _snapshot = _self call ["tick", []];
|
||||||
|
|
||||||
@ -355,9 +359,12 @@ GVAR(HostageTaskBaseClass) merge [createHashMapFromArray [
|
|||||||
sleep 1;
|
sleep 1;
|
||||||
};
|
};
|
||||||
|
|
||||||
if ((_self call ["getStatus", []]) isEqualTo "failed") then {
|
private _finalStatus = _self call ["getStatus", []];
|
||||||
|
if (_finalStatus isEqualTo "failed") then {
|
||||||
_self call ["handleFailureOutcome", []];
|
_self call ["handleFailureOutcome", []];
|
||||||
} else {
|
};
|
||||||
|
|
||||||
|
if (_finalStatus isEqualTo "succeeded") then {
|
||||||
_self call ["handleSuccessOutcome", []];
|
_self call ["handleSuccessOutcome", []];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -29,10 +29,10 @@ GVAR(IEDEntityController) merge [createHashMapFromArray [
|
|||||||
|
|
||||||
waitUntil {
|
waitUntil {
|
||||||
sleep 1;
|
sleep 1;
|
||||||
GVAR(TaskStore) call ["isTaskAccepted", [_taskID]]
|
!(_self call ["isAssignedTaskOpen", []]) || { GVAR(TaskStore) call ["isTaskAccepted", [_taskID]] }
|
||||||
};
|
};
|
||||||
|
|
||||||
true
|
_self call ["isAssignedTaskOpen", []]
|
||||||
}],
|
}],
|
||||||
["playCountdownSound", compileFinal {
|
["playCountdownSound", compileFinal {
|
||||||
params [["_timeRemaining", 0, [0]]];
|
params [["_timeRemaining", 0, [0]]];
|
||||||
@ -67,20 +67,35 @@ GVAR(IEDEntityController) merge [createHashMapFromArray [
|
|||||||
false
|
false
|
||||||
};
|
};
|
||||||
|
|
||||||
_self call ["waitForAssignment", []];
|
if !(_self call ["waitForAssignment", []]) exitWith {
|
||||||
|
_self call ["markAborted", []];
|
||||||
|
_self call ["cleanup", []];
|
||||||
|
false
|
||||||
|
};
|
||||||
|
if !(_self call ["isAssignedTaskOpen", []]) exitWith {
|
||||||
|
_self call ["markAborted", []];
|
||||||
|
_self call ["cleanup", []];
|
||||||
|
false
|
||||||
|
};
|
||||||
_self call ["markActive", []];
|
_self call ["markActive", []];
|
||||||
|
|
||||||
while { (_self call ["isEntityUsable", []]) && { _countdown > 0 } } do {
|
while { (_self call ["isAssignedTaskOpen", []]) && { (_self call ["isEntityUsable", []]) && { _countdown > 0 } } } do {
|
||||||
_self call ["playCountdownSound", [_countdown]];
|
_self call ["playCountdownSound", [_countdown]];
|
||||||
_countdown = _countdown - 1;
|
_countdown = _countdown - 1;
|
||||||
_self set ["countdown", _countdown];
|
_self set ["countdown", _countdown];
|
||||||
sleep 1;
|
sleep 1;
|
||||||
};
|
};
|
||||||
|
|
||||||
if ((_self call ["isEntityUsable", []]) && { _countdown <= 0 }) then {
|
if ((_self call ["isAssignedTaskOpen", []]) && { (_self call ["isEntityUsable", []]) && { _countdown <= 0 } }) then {
|
||||||
_self call ["detonate", []];
|
_self call ["detonate", []];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if !(_self call ["isAssignedTaskOpen", []]) exitWith {
|
||||||
|
_self call ["markAborted", []];
|
||||||
|
_self call ["cleanup", []];
|
||||||
|
false
|
||||||
|
};
|
||||||
|
|
||||||
_self call ["markFinished", []];
|
_self call ["markFinished", []];
|
||||||
_self call ["cleanup", []];
|
_self call ["cleanup", []];
|
||||||
true
|
true
|
||||||
|
|||||||
@ -31,7 +31,13 @@ GVAR(ProtectedEntityController) merge [createHashMapFromArray [
|
|||||||
_self call ["markActive", []];
|
_self call ["markActive", []];
|
||||||
waitUntil {
|
waitUntil {
|
||||||
sleep 1;
|
sleep 1;
|
||||||
!(_self call ["isEntityUsable", []])
|
!(_self call ["isAssignedTaskOpen", []]) || { !(_self call ["isEntityUsable", []]) }
|
||||||
|
};
|
||||||
|
|
||||||
|
if !(_self call ["isAssignedTaskOpen", []]) exitWith {
|
||||||
|
_self call ["markAborted", []];
|
||||||
|
_self call ["cleanup", []];
|
||||||
|
false
|
||||||
};
|
};
|
||||||
|
|
||||||
_self call ["markFinished", []];
|
_self call ["markFinished", []];
|
||||||
|
|||||||
@ -31,7 +31,13 @@ GVAR(ShooterEntityController) merge [createHashMapFromArray [
|
|||||||
_self call ["markActive", []];
|
_self call ["markActive", []];
|
||||||
waitUntil {
|
waitUntil {
|
||||||
sleep 1;
|
sleep 1;
|
||||||
!(_self call ["isEntityUsable", []])
|
!(_self call ["isAssignedTaskOpen", []]) || { !(_self call ["isEntityUsable", []]) }
|
||||||
|
};
|
||||||
|
|
||||||
|
if !(_self call ["isAssignedTaskOpen", []]) exitWith {
|
||||||
|
_self call ["markAborted", []];
|
||||||
|
_self call ["cleanup", []];
|
||||||
|
false
|
||||||
};
|
};
|
||||||
|
|
||||||
_self call ["markFinished", []];
|
_self call ["markFinished", []];
|
||||||
|
|||||||
@ -31,7 +31,13 @@ GVAR(TargetEntityController) merge [createHashMapFromArray [
|
|||||||
_self call ["markActive", []];
|
_self call ["markActive", []];
|
||||||
waitUntil {
|
waitUntil {
|
||||||
sleep 1;
|
sleep 1;
|
||||||
!(_self call ["isEntityUsable", []])
|
!(_self call ["isAssignedTaskOpen", []]) || { !(_self call ["isEntityUsable", []]) }
|
||||||
|
};
|
||||||
|
|
||||||
|
if !(_self call ["isAssignedTaskOpen", []]) exitWith {
|
||||||
|
_self call ["markAborted", []];
|
||||||
|
_self call ["cleanup", []];
|
||||||
|
false
|
||||||
};
|
};
|
||||||
|
|
||||||
_self call ["markFinished", []];
|
_self call ["markFinished", []];
|
||||||
|
|||||||
@ -123,6 +123,11 @@ GVAR(TaskCatalogStore) = createHashMapObject [[
|
|||||||
|
|
||||||
(_self call ["getTaskStatus", [_taskID]]) isEqualTo "succeeded"
|
(_self call ["getTaskStatus", [_taskID]]) isEqualTo "succeeded"
|
||||||
}],
|
}],
|
||||||
|
["isTerminalStatus", compileFinal {
|
||||||
|
params [["_status", "", [""]]];
|
||||||
|
|
||||||
|
(toLowerANSI _status) in ["failed", "succeeded"]
|
||||||
|
}],
|
||||||
["areTaskPrerequisitesSatisfied", compileFinal {
|
["areTaskPrerequisitesSatisfied", compileFinal {
|
||||||
params [["_taskID", "", [""]], ["_entry", createHashMap, [createHashMap]]];
|
params [["_taskID", "", [""]], ["_entry", createHashMap, [createHashMap]]];
|
||||||
|
|
||||||
@ -359,6 +364,28 @@ GVAR(TaskCatalogStore) = createHashMapObject [[
|
|||||||
if (_taskID isEqualTo "" || { _status isEqualTo "" }) exitWith { false };
|
if (_taskID isEqualTo "" || { _status isEqualTo "" }) exitWith { false };
|
||||||
|
|
||||||
private _normalizedStatus = toLowerANSI _status;
|
private _normalizedStatus = toLowerANSI _status;
|
||||||
|
private _currentStatus = toLowerANSI (_self call ["getTaskStatus", [_taskID]]);
|
||||||
|
private _currentIsTerminal = _self call ["isTerminalStatus", [_currentStatus]];
|
||||||
|
private _nextIsTerminal = _self call ["isTerminalStatus", [_normalizedStatus]];
|
||||||
|
|
||||||
|
if (_currentIsTerminal && { _currentStatus isNotEqualTo _normalizedStatus }) exitWith {
|
||||||
|
["WARNING", format [
|
||||||
|
"Task status transition blocked for %1: terminal status %2 cannot be changed to %3 without clearing task state first.",
|
||||||
|
_taskID,
|
||||||
|
_currentStatus,
|
||||||
|
_normalizedStatus
|
||||||
|
]] call EFUNC(common,log);
|
||||||
|
false
|
||||||
|
};
|
||||||
|
|
||||||
|
if (_currentIsTerminal && { _nextIsTerminal }) exitWith {
|
||||||
|
if (_normalizedStatus isEqualTo "succeeded") then {
|
||||||
|
_self call ["markTaskCompleted", [_taskID]];
|
||||||
|
_self call ["unlockDependentTasks", [_taskID]];
|
||||||
|
};
|
||||||
|
true
|
||||||
|
};
|
||||||
|
|
||||||
private _runtimeCatalogRegistry = _self getOrDefault ["runtimeCatalogRegistry", createHashMap];
|
private _runtimeCatalogRegistry = _self getOrDefault ["runtimeCatalogRegistry", createHashMap];
|
||||||
private _runtimeEntry = +(_runtimeCatalogRegistry getOrDefault [_taskID, createHashMap]);
|
private _runtimeEntry = +(_runtimeCatalogRegistry getOrDefault [_taskID, createHashMap]);
|
||||||
if (_runtimeEntry isNotEqualTo createHashMap) then {
|
if (_runtimeEntry isNotEqualTo createHashMap) then {
|
||||||
|
|||||||
@ -83,6 +83,50 @@ GVAR(TaskInstanceBaseClass) = createHashMapFromArray [
|
|||||||
["getStatus", compileFinal {
|
["getStatus", compileFinal {
|
||||||
_self getOrDefault ["status", "created"]
|
_self getOrDefault ["status", "created"]
|
||||||
}],
|
}],
|
||||||
|
["isTerminalStatus", compileFinal {
|
||||||
|
params [["_status", "", [""]]];
|
||||||
|
|
||||||
|
(toLowerANSI _status) in ["failed", "succeeded"]
|
||||||
|
}],
|
||||||
|
["getStoreStatus", compileFinal {
|
||||||
|
private _taskID = _self getOrDefault ["taskID", ""];
|
||||||
|
if (_taskID isEqualTo "" || { !(_self getOrDefault ["useTaskStore", false]) } || { isNil QGVAR(TaskStore) }) exitWith { "" };
|
||||||
|
|
||||||
|
GVAR(TaskStore) call ["getTaskStatus", [_taskID]]
|
||||||
|
}],
|
||||||
|
["canTransitionToTerminal", compileFinal {
|
||||||
|
params [["_nextStatus", "", [""]]];
|
||||||
|
|
||||||
|
private _normalizedNext = toLowerANSI _nextStatus;
|
||||||
|
if !(_self call ["isTerminalStatus", [_normalizedNext]]) exitWith { true };
|
||||||
|
|
||||||
|
private _currentStatus = toLowerANSI (_self getOrDefault ["status", "created"]);
|
||||||
|
if ((_self call ["isTerminalStatus", [_currentStatus]]) && { _currentStatus isNotEqualTo _normalizedNext }) exitWith { false };
|
||||||
|
|
||||||
|
private _storeStatus = toLowerANSI (_self call ["getStoreStatus", []]);
|
||||||
|
if ((_self call ["isTerminalStatus", [_storeStatus]]) && { _storeStatus isNotEqualTo _normalizedNext }) exitWith { false };
|
||||||
|
|
||||||
|
true
|
||||||
|
}],
|
||||||
|
["isTaskLoopActive", compileFinal {
|
||||||
|
if ((_self call ["getStatus", []]) isNotEqualTo "active") exitWith { false };
|
||||||
|
|
||||||
|
private _storeStatus = toLowerANSI (_self call ["getStoreStatus", []]);
|
||||||
|
if (_storeStatus isEqualTo "") exitWith { true };
|
||||||
|
|
||||||
|
if (_self call ["isTerminalStatus", [_storeStatus]]) exitWith {
|
||||||
|
_self call ["markAborted", [format ["Task store reached terminal status '%1'.", _storeStatus]]];
|
||||||
|
false
|
||||||
|
};
|
||||||
|
|
||||||
|
true
|
||||||
|
}],
|
||||||
|
["isTaskStoreOpen", compileFinal {
|
||||||
|
private _storeStatus = toLowerANSI (_self call ["getStoreStatus", []]);
|
||||||
|
if (_storeStatus isEqualTo "") exitWith { true };
|
||||||
|
|
||||||
|
!(_self call ["isTerminalStatus", [_storeStatus]])
|
||||||
|
}],
|
||||||
["getRewardData", compileFinal {
|
["getRewardData", compileFinal {
|
||||||
_self getOrDefault ["rewardData", createHashMap]
|
_self getOrDefault ["rewardData", createHashMap]
|
||||||
}],
|
}],
|
||||||
@ -162,6 +206,8 @@ GVAR(TaskInstanceBaseClass) = createHashMapFromArray [
|
|||||||
["markSucceeded", compileFinal {
|
["markSucceeded", compileFinal {
|
||||||
params [["_resultSnapshot", createHashMap, [createHashMap]]];
|
params [["_resultSnapshot", createHashMap, [createHashMap]]];
|
||||||
|
|
||||||
|
if !(_self call ["canTransitionToTerminal", ["succeeded"]]) exitWith { false };
|
||||||
|
|
||||||
_self set ["status", "succeeded"];
|
_self set ["status", "succeeded"];
|
||||||
_self set ["finishedAt", serverTime];
|
_self set ["finishedAt", serverTime];
|
||||||
_self set ["resultSnapshot", _resultSnapshot];
|
_self set ["resultSnapshot", _resultSnapshot];
|
||||||
@ -173,6 +219,8 @@ GVAR(TaskInstanceBaseClass) = createHashMapFromArray [
|
|||||||
["markFailed", compileFinal {
|
["markFailed", compileFinal {
|
||||||
params [["_reason", "", [""]], ["_resultSnapshot", createHashMap, [createHashMap]]];
|
params [["_reason", "", [""]], ["_resultSnapshot", createHashMap, [createHashMap]]];
|
||||||
|
|
||||||
|
if !(_self call ["canTransitionToTerminal", ["failed"]]) exitWith { false };
|
||||||
|
|
||||||
_self set ["status", "failed"];
|
_self set ["status", "failed"];
|
||||||
_self set ["finishedAt", serverTime];
|
_self set ["finishedAt", serverTime];
|
||||||
_self set ["failureReason", _reason];
|
_self set ["failureReason", _reason];
|
||||||
@ -182,6 +230,14 @@ GVAR(TaskInstanceBaseClass) = createHashMapFromArray [
|
|||||||
};
|
};
|
||||||
true
|
true
|
||||||
}],
|
}],
|
||||||
|
["markAborted", compileFinal {
|
||||||
|
params [["_reason", "", [""]]];
|
||||||
|
|
||||||
|
_self set ["status", "aborted"];
|
||||||
|
_self set ["finishedAt", serverTime];
|
||||||
|
_self set ["failureReason", _reason];
|
||||||
|
true
|
||||||
|
}],
|
||||||
["cleanup", compileFinal {
|
["cleanup", compileFinal {
|
||||||
_self call ["unregisterInstance", []]
|
_self call ["unregisterInstance", []]
|
||||||
}],
|
}],
|
||||||
|
|||||||
@ -39,6 +39,23 @@ GVAR(TransportServiceBase) = compileFinal createHashMapFromArray [
|
|||||||
["INFO", "Transport Service Initialized!"] call EFUNC(common,log);
|
["INFO", "Transport Service Initialized!"] call EFUNC(common,log);
|
||||||
true
|
true
|
||||||
}],
|
}],
|
||||||
|
["numberSetting", compileFinal {
|
||||||
|
params [["_name", "", [""]], ["_default", 0, [0]]];
|
||||||
|
|
||||||
|
private _configDefault = _default;
|
||||||
|
private _missionConfig = missionConfigFile >> "CfgMissions";
|
||||||
|
if !(isClass _missionConfig) then { _missionConfig = configFile >> "CfgMissions"; };
|
||||||
|
private _serviceConfig = _missionConfig >> "ServicePricing";
|
||||||
|
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
|
||||||
|
}],
|
||||||
["notify", compileFinal {
|
["notify", compileFinal {
|
||||||
params [["_unit", objNull, [objNull]], ["_type", "info", [""]], ["_title", "Transport", [""]], ["_message", "", [""]]];
|
params [["_unit", objNull, [objNull]], ["_type", "info", [""]], ["_title", "Transport", [""]], ["_message", "", [""]]];
|
||||||
|
|
||||||
@ -120,8 +137,10 @@ GVAR(TransportServiceBase) = compileFinal createHashMapFromArray [
|
|||||||
["getCost", compileFinal {
|
["getCost", compileFinal {
|
||||||
params [["_fromNode", objNull, [objNull]], ["_toNode", objNull, [objNull]], ["_options", createHashMap, [createHashMap]]];
|
params [["_fromNode", objNull, [objNull]], ["_toNode", objNull, [objNull]], ["_options", createHashMap, [createHashMap]]];
|
||||||
|
|
||||||
private _baseFare = _options getOrDefault ["baseFare", _self getOrDefault ["baseFare", 100]];
|
private _baseFareDefault = _self call ["numberSetting", ["transportBaseFare", _self getOrDefault ["baseFare", 100]]];
|
||||||
private _pricePerKm = _options getOrDefault ["pricePerKm", _self getOrDefault ["pricePerKm", 50]];
|
private _pricePerKmDefault = _self call ["numberSetting", ["transportPricePerKm", _self getOrDefault ["pricePerKm", 50]]];
|
||||||
|
private _baseFare = _options getOrDefault ["baseFare", _baseFareDefault];
|
||||||
|
private _pricePerKm = _options getOrDefault ["pricePerKm", _pricePerKmDefault];
|
||||||
private _distanceMeters = _fromNode distance2D _toNode;
|
private _distanceMeters = _fromNode distance2D _toNode;
|
||||||
|
|
||||||
round (_baseFare + ((_distanceMeters / 1000) * _pricePerKm))
|
round (_baseFare + ((_distanceMeters / 1000) * _pricePerKm))
|
||||||
|
|||||||
@ -29,6 +29,10 @@ calculates missing fuel from the vehicle config `fuelCapacity`, charges the
|
|||||||
player's organization, and fills the vehicle only after the organization charge
|
player's organization, and fills the vehicle only after the organization charge
|
||||||
succeeds.
|
succeeds.
|
||||||
|
|
||||||
|
The refuel price per liter is controlled by `fuelCost`. The mission setup UI
|
||||||
|
can override it at startup; otherwise a mission `Params` entry named
|
||||||
|
`fuelCost` or `CfgMissions >> ServicePricing >> fuelCost` is used.
|
||||||
|
|
||||||
## Repair
|
## Repair
|
||||||
|
|
||||||
Repair is organization-funded.
|
Repair is organization-funded.
|
||||||
@ -45,6 +49,9 @@ The target is only repaired after the organization charge succeeds.
|
|||||||
The client garage UI forwards selected nearby vehicle repair requests through
|
The client garage UI forwards selected nearby vehicle repair requests through
|
||||||
the same event.
|
the same event.
|
||||||
|
|
||||||
|
The default repair charge is controlled by `serviceRepairCost`. A direct
|
||||||
|
service event can still pass a concrete `_cost` to override that request.
|
||||||
|
|
||||||
## Rearm
|
## Rearm
|
||||||
|
|
||||||
Rearm is organization-funded.
|
Rearm is organization-funded.
|
||||||
@ -63,6 +70,9 @@ turrets, so the service broadcasts the ammo reset after billing succeeds.
|
|||||||
The client garage UI forwards selected nearby vehicle rearm requests through
|
The client garage UI forwards selected nearby vehicle rearm requests through
|
||||||
the same event.
|
the same event.
|
||||||
|
|
||||||
|
The default rearm charge is controlled by `serviceRearmCost`. A direct service
|
||||||
|
event can still pass a concrete `_cost` to override that request.
|
||||||
|
|
||||||
## Medical
|
## Medical
|
||||||
|
|
||||||
Medical is player-funded first.
|
Medical is player-funded first.
|
||||||
@ -79,6 +89,15 @@ The heal only completes after one of those charges succeeds. If personal
|
|||||||
billing is unavailable, the heal does not fall back to organization funds
|
billing is unavailable, the heal does not fall back to organization funds
|
||||||
because the server cannot verify that the player is unable to cover the fee.
|
because the server cannot verify that the player is unable to cover the fee.
|
||||||
|
|
||||||
|
Medical pricing uses:
|
||||||
|
|
||||||
|
- `medicalHealCost` for heal billing.
|
||||||
|
- `medicalSpawnCost` for medical respawn billing. Respawn billing is
|
||||||
|
best-effort so a failed charge does not block the respawn flow.
|
||||||
|
|
||||||
|
Both values can be set in the mission setup UI, mission `Params`, or
|
||||||
|
`CfgMissions >> ServicePricing`.
|
||||||
|
|
||||||
## Medical Debt Repayment
|
## Medical Debt Repayment
|
||||||
|
|
||||||
Medical fallback debt uses the existing organization credit-line repayment
|
Medical fallback debt uses the existing organization credit-line repayment
|
||||||
|
|||||||
@ -755,14 +755,21 @@ CAD dispatcher-requested generation.
|
|||||||
The optional framework mission setup UI lets the setup operator choose runtime
|
The optional framework mission setup UI lets the setup operator choose runtime
|
||||||
tuning such as opposing faction, mission cap, interval, location cooldown,
|
tuning such as opposing faction, mission cap, interval, location cooldown,
|
||||||
reward ranges, reputation ranges, penalty ranges, time limits, and a generator
|
reward ranges, reputation ranges, penalty ranges, time limits, and a generator
|
||||||
provider preference. It does not enable or disable generated missions; use the
|
provider preference. It also exposes service pricing for medical spawn, heal,
|
||||||
CBA setting for that policy.
|
repair, rearm, refuel, and transport defaults. It does not enable or disable
|
||||||
|
generated missions; use the CBA setting for that policy.
|
||||||
|
|
||||||
If mission setup is enabled, the mission manager waits until the setup operator
|
If mission setup is enabled, the mission manager waits until the setup operator
|
||||||
applies settings. Cancel, X, and Escape apply default values from CBA, mission
|
applies settings. Cancel, X, and Escape apply default values from CBA, mission
|
||||||
parameters, and `CfgMissions`. There is no timeout that auto-applies defaults.
|
parameters, and `CfgMissions`. There is no timeout that auto-applies defaults.
|
||||||
After settings are applied, the setup UI cannot be reopened.
|
After settings are applied, the setup UI cannot be reopened.
|
||||||
|
|
||||||
|
Service pricing fallback values live under `CfgMissions >> ServicePricing`.
|
||||||
|
Mission `Params` with matching names, such as `medicalHealCost`,
|
||||||
|
`serviceRepairCost`, `serviceRearmCost`, `fuelCost`, `transportBaseFare`, and
|
||||||
|
`transportPricePerKm`, are read before the setup UI hydrates so mission makers
|
||||||
|
can keep a non-UI backup.
|
||||||
|
|
||||||
The setup UI stores the provider preference as `builtin` or `custom`. CAD/manual
|
The setup UI stores the provider preference as `builtin` or `custom`. CAD/manual
|
||||||
generated task requests use the task provider registry and route to the selected
|
generated task requests use the task provider registry and route to the selected
|
||||||
provider. Custom generators should register a provider or create CAD-visible
|
provider. Custom generators should register a provider or create CAD-visible
|
||||||
|
|||||||
@ -188,14 +188,21 @@ server-side.
|
|||||||
|
|
||||||
The mission setup UI does not enable or disable generated missions. It applies
|
The mission setup UI does not enable or disable generated missions. It applies
|
||||||
runtime tuning such as faction, caps, intervals, reward ranges, rating ranges,
|
runtime tuning such as faction, caps, intervals, reward ranges, rating ranges,
|
||||||
penalties, time limits, and a generator provider preference. Generator
|
penalties, time limits, service pricing, and a generator provider preference.
|
||||||
enablement remains controlled by the CBA setting above.
|
Generator enablement remains controlled by the CBA setting above.
|
||||||
|
|
||||||
When `forge_server_task_enableMissionSetup` is enabled, the mission manager
|
When `forge_server_task_enableMissionSetup` is enabled, the mission manager
|
||||||
waits for setup settings before starting. There is no timeout auto-apply.
|
waits for setup settings before starting. There is no timeout auto-apply.
|
||||||
Pressing Cancel, X, or Escape applies default values from CBA, mission
|
Pressing Cancel, X, or Escape applies default values from CBA, mission
|
||||||
parameters, and `CfgMissions`.
|
parameters, and `CfgMissions`.
|
||||||
|
|
||||||
|
Service price defaults are stored in `CfgMissions >> ServicePricing`. Mission
|
||||||
|
`Params` with matching names override those defaults before the UI opens, and
|
||||||
|
submitted UI values override both. The supported names are
|
||||||
|
`medicalSpawnCost`, `medicalHealCost`, `serviceRepairCost`,
|
||||||
|
`serviceRearmCost`, `fuelCost`, `transportBaseFare`, and
|
||||||
|
`transportPricePerKm`.
|
||||||
|
|
||||||
The setup UI stores the provider preference in
|
The setup UI stores the provider preference in
|
||||||
`forge_server_task_generatorProvider` as `builtin` or `custom`. CAD/manual
|
`forge_server_task_generatorProvider` as `builtin` or `custom`. CAD/manual
|
||||||
generated task requests use the task provider registry and route to the selected
|
generated task requests use the task provider registry and route to the selected
|
||||||
|
|||||||
@ -89,6 +89,12 @@ nearby vehicles, ships, aircraft, and player units. The scan ignores:
|
|||||||
Use `transport_vehicle*` names for the actual boat, ferry, aircraft, or set
|
Use `transport_vehicle*` names for the actual boat, ferry, aircraft, or set
|
||||||
dressing object that should not be moved as cargo.
|
dressing object that should not be moved as cargo.
|
||||||
|
|
||||||
|
## Pricing
|
||||||
|
|
||||||
|
Default transport pricing comes from the mission setup UI or matching mission
|
||||||
|
`Params` entries named `transportBaseFare` and `transportPricePerKm`. If neither
|
||||||
|
is set, `CfgMissions >> ServicePricing` provides the fallback.
|
||||||
|
|
||||||
## Optional Per-Node Overrides
|
## Optional Per-Node Overrides
|
||||||
|
|
||||||
The default naming convention should cover normal missions. If a specific
|
The default naming convention should cover normal missions. If a specific
|
||||||
@ -108,7 +114,8 @@ this setVariable ["transportCargoRadius", 25, true];
|
|||||||
this setVariable ["transportIncludeCargo", true, true];
|
this setVariable ["transportIncludeCargo", true, true];
|
||||||
```
|
```
|
||||||
|
|
||||||
Only use overrides when the default `transport*` convention is not appropriate.
|
Only use overrides when the default `transport*` convention or mission-level
|
||||||
|
pricing is not appropriate.
|
||||||
|
|
||||||
## Reference Images
|
## Reference Images
|
||||||
|
|
||||||
|
|||||||
@ -1,7 +1,4 @@
|
|||||||
use arma_rs::{
|
use arma_rs::{FromArma, IntoArma, loadout::Loadout as ArmaLoadout};
|
||||||
FromArma, IntoArma,
|
|
||||||
loadout::{AssignedItems, InventoryItem, Loadout as ArmaLoadout},
|
|
||||||
};
|
|
||||||
use forge_shared::{
|
use forge_shared::{
|
||||||
ActorValidationError, arma_value_to_json, generate_email, generate_phone_number,
|
ActorValidationError, arma_value_to_json, generate_email, generate_phone_number,
|
||||||
};
|
};
|
||||||
@ -128,26 +125,7 @@ impl Actor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn default_loadout_json() -> serde_json::Value {
|
fn default_loadout_json() -> serde_json::Value {
|
||||||
let mut loadout = ArmaLoadout::default();
|
serde_json::Value::Array(Vec::new())
|
||||||
|
|
||||||
let uniform = loadout.uniform_mut();
|
|
||||||
uniform.set_class("U_BG_Guerrilla_6_1".to_string());
|
|
||||||
|
|
||||||
let uniform_items = uniform.items_mut().unwrap();
|
|
||||||
uniform_items.push(InventoryItem::new_item("FirstAidKit".to_string(), 1));
|
|
||||||
|
|
||||||
loadout.set_headgear("H_Cap_blk_ION".to_string());
|
|
||||||
|
|
||||||
let mut items = AssignedItems::default();
|
|
||||||
items.set_map("ItemMap".to_string());
|
|
||||||
items.set_terminal("ItemGPS".to_string());
|
|
||||||
items.set_radio("ItemRadio".to_string());
|
|
||||||
items.set_compass("ItemCompass".to_string());
|
|
||||||
items.set_watch("ItemWatch".to_string());
|
|
||||||
loadout.set_assigned_items(items);
|
|
||||||
|
|
||||||
let arma_value = loadout.to_arma();
|
|
||||||
arma_value_to_json(&arma_value)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_loadout(&self) -> Result<ArmaLoadout, String> {
|
pub fn get_loadout(&self) -> Result<ArmaLoadout, String> {
|
||||||
|
|||||||
@ -23,12 +23,8 @@ pub struct VGarage {
|
|||||||
|
|
||||||
impl VGarage {
|
impl VGarage {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self::default_unlocks()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn default_unlocks() -> Self {
|
|
||||||
Self {
|
Self {
|
||||||
cars: vec!["B_Quadbike_01_F".to_string()],
|
cars: Vec::new(),
|
||||||
armor: Vec::new(),
|
armor: Vec::new(),
|
||||||
helis: Vec::new(),
|
helis: Vec::new(),
|
||||||
planes: Vec::new(),
|
planes: Vec::new(),
|
||||||
|
|||||||
@ -19,43 +19,11 @@ pub struct VLocker {
|
|||||||
|
|
||||||
impl VLocker {
|
impl VLocker {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self::default_unlocks()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn default_unlocks() -> Self {
|
|
||||||
Self {
|
Self {
|
||||||
items: vec![
|
items: Vec::new(),
|
||||||
"FirstAidKit".to_string(),
|
weapons: Vec::new(),
|
||||||
"G_Combat".to_string(),
|
magazines: Vec::new(),
|
||||||
"H_Cap_blk_ION".to_string(),
|
backpacks: Vec::new(),
|
||||||
"H_HelmetB".to_string(),
|
|
||||||
"ACE_EarPlugs".to_string(),
|
|
||||||
"ItemCompass".to_string(),
|
|
||||||
"ItemGPS".to_string(),
|
|
||||||
"ItemMap".to_string(),
|
|
||||||
"ItemRadio".to_string(),
|
|
||||||
"ItemWatch".to_string(),
|
|
||||||
"U_BG_Guerrilla_6_1".to_string(),
|
|
||||||
"V_TacVest_oli".to_string(),
|
|
||||||
],
|
|
||||||
weapons: vec!["arifle_MX_F".to_string(), "hgun_P07_F".to_string()],
|
|
||||||
magazines: vec![
|
|
||||||
"16Rnd_9x21_Mag".to_string(),
|
|
||||||
"30Rnd_65x39_caseless_black_mag".to_string(),
|
|
||||||
"Chemlight_blue".to_string(),
|
|
||||||
"Chemlight_green".to_string(),
|
|
||||||
"Chemlight_red".to_string(),
|
|
||||||
"Chemlight_yellow".to_string(),
|
|
||||||
"HandGrenade".to_string(),
|
|
||||||
"SmokeShell".to_string(),
|
|
||||||
"SmokeShellBlue".to_string(),
|
|
||||||
"SmokeShellGreen".to_string(),
|
|
||||||
"SmokeShellOrange".to_string(),
|
|
||||||
"SmokeShellPurple".to_string(),
|
|
||||||
"SmokeShellRed".to_string(),
|
|
||||||
"SmokeShellYellow".to_string(),
|
|
||||||
],
|
|
||||||
backpacks: vec!["B_AssaultPack_rgr".to_string()],
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user