Backport framework docs and store filter updates
This commit is contained in:
parent
d61cb86d3a
commit
4f54edf467
@ -152,6 +152,12 @@ option {
|
|||||||
grid-column: 1 / -1;
|
grid-column: 1 / -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.timer-row {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: minmax(0, 1.1fr) minmax(0, 0.95fr) minmax(0, 0.95fr);
|
||||||
|
gap: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
label {
|
label {
|
||||||
color: var(--text-subtle);
|
color: var(--text-subtle);
|
||||||
font-size: 0.62rem;
|
font-size: 0.62rem;
|
||||||
@ -261,6 +267,10 @@ select {
|
|||||||
color: var(--text-main);
|
color: var(--text-main);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
input:disabled {
|
||||||
|
opacity: 0.45;
|
||||||
|
}
|
||||||
|
|
||||||
input:focus,
|
input:focus,
|
||||||
select:focus,
|
select:focus,
|
||||||
button:focus-visible {
|
button:focus-visible {
|
||||||
|
|||||||
@ -12,6 +12,7 @@
|
|||||||
reputationMax: 100,
|
reputationMax: 100,
|
||||||
penaltyMin: -5,
|
penaltyMin: -5,
|
||||||
penaltyMax: -25,
|
penaltyMax: -25,
|
||||||
|
timeLimitEnabled: true,
|
||||||
timeLimitMin: 600,
|
timeLimitMin: 600,
|
||||||
timeLimitMax: 900,
|
timeLimitMax: 900,
|
||||||
medicalSpawnCost: 100,
|
medicalSpawnCost: 100,
|
||||||
@ -41,6 +42,8 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
function readSettings() {
|
function readSettings() {
|
||||||
|
const timeLimitEnabled = document.getElementById("timeLimitEnabled")?.checked !== false;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
enemyFaction: String(document.getElementById("enemyFaction")?.value || "IND_G_F"),
|
enemyFaction: String(document.getElementById("enemyFaction")?.value || "IND_G_F"),
|
||||||
maxConcurrentMissions: fieldNumber("maxConcurrentMissions"),
|
maxConcurrentMissions: fieldNumber("maxConcurrentMissions"),
|
||||||
@ -52,8 +55,9 @@
|
|||||||
reputationMax: fieldNumber("reputationMax"),
|
reputationMax: fieldNumber("reputationMax"),
|
||||||
penaltyMin: fieldNumber("penaltyMin"),
|
penaltyMin: fieldNumber("penaltyMin"),
|
||||||
penaltyMax: fieldNumber("penaltyMax"),
|
penaltyMax: fieldNumber("penaltyMax"),
|
||||||
timeLimitMin: fieldNumber("timeLimitMin"),
|
timeLimitEnabled,
|
||||||
timeLimitMax: fieldNumber("timeLimitMax"),
|
timeLimitMin: timeLimitEnabled ? fieldNumber("timeLimitMin") : 0,
|
||||||
|
timeLimitMax: timeLimitEnabled ? fieldNumber("timeLimitMax") : 0,
|
||||||
medicalSpawnCost: fieldNumber("medicalSpawnCost"),
|
medicalSpawnCost: fieldNumber("medicalSpawnCost"),
|
||||||
medicalHealCost: fieldNumber("medicalHealCost"),
|
medicalHealCost: fieldNumber("medicalHealCost"),
|
||||||
serviceRepairCost: fieldNumber("serviceRepairCost"),
|
serviceRepairCost: fieldNumber("serviceRepairCost"),
|
||||||
@ -74,6 +78,16 @@
|
|||||||
.replace(/'/g, "'");
|
.replace(/'/g, "'");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function normalizeSettings(settings) {
|
||||||
|
const next = Object.assign({}, settings);
|
||||||
|
next.timeLimitMin = Number(next.timeLimitMin || 0);
|
||||||
|
next.timeLimitMax = Number(next.timeLimitMax || 0);
|
||||||
|
if (typeof next.timeLimitEnabled !== "boolean") {
|
||||||
|
next.timeLimitEnabled = next.timeLimitMax > 0;
|
||||||
|
}
|
||||||
|
return next;
|
||||||
|
}
|
||||||
|
|
||||||
function apply() {
|
function apply() {
|
||||||
const settings = readSettings();
|
const settings = readSettings();
|
||||||
if (settings.moneyMax < settings.moneyMin) {
|
if (settings.moneyMax < settings.moneyMin) {
|
||||||
@ -94,10 +108,18 @@
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (settings.timeLimitMax < settings.timeLimitMin) {
|
if (settings.timeLimitEnabled) {
|
||||||
state.error = "Time limit max must be greater than or equal to time limit min.";
|
if (settings.timeLimitMin < 1 || settings.timeLimitMax < 1) {
|
||||||
render();
|
state.error = "Time limits must be positive seconds when task timers are enabled.";
|
||||||
return;
|
render();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (settings.timeLimitMax < settings.timeLimitMin) {
|
||||||
|
state.error = "Time limit max must be greater than or equal to time limit min.";
|
||||||
|
render();
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const costFields = [
|
const costFields = [
|
||||||
@ -134,6 +156,15 @@
|
|||||||
const factionLabel = faction ? faction.display : settings.enemyFaction;
|
const factionLabel = faction ? faction.display : settings.enemyFaction;
|
||||||
const generatorProviderLabel = settings.generatorProvider === "custom" ? "Custom" : "Built-in";
|
const generatorProviderLabel = settings.generatorProvider === "custom" ? "Custom" : "Built-in";
|
||||||
const generatorProviderChecked = settings.generatorProvider === "custom" ? " checked" : "";
|
const generatorProviderChecked = settings.generatorProvider === "custom" ? " checked" : "";
|
||||||
|
const timeLimitEnabled = settings.timeLimitEnabled !== false;
|
||||||
|
const timeLimitChecked = timeLimitEnabled ? " checked" : "";
|
||||||
|
const timeLimitDisabled = timeLimitEnabled ? "" : " disabled";
|
||||||
|
const timeLimitLabel = timeLimitEnabled ? "Enabled" : "No Limit";
|
||||||
|
const timeLimitMinValue = timeLimitEnabled ? settings.timeLimitMin : 600;
|
||||||
|
const timeLimitMaxValue = timeLimitEnabled ? settings.timeLimitMax : 900;
|
||||||
|
const timeLimitSummary = timeLimitEnabled
|
||||||
|
? `${settings.timeLimitMin}s - ${settings.timeLimitMax}s`
|
||||||
|
: "No limit";
|
||||||
|
|
||||||
document.getElementById("app").innerHTML = `
|
document.getElementById("app").innerHTML = `
|
||||||
<div class="shell">
|
<div class="shell">
|
||||||
@ -204,13 +235,26 @@
|
|||||||
<label for="penaltyMax">Max Rep Hit</label>
|
<label for="penaltyMax">Max Rep Hit</label>
|
||||||
<input id="penaltyMax" type="number" max="0" step="1" value="${settings.penaltyMax}" />
|
<input id="penaltyMax" type="number" max="0" step="1" value="${settings.penaltyMax}" />
|
||||||
</div>
|
</div>
|
||||||
<div class="field">
|
<div class="timer-row wide">
|
||||||
<label for="timeLimitMin">Min Time</label>
|
<div class="field">
|
||||||
<input id="timeLimitMin" type="number" min="1" step="60" value="${settings.timeLimitMin}" />
|
<label for="timeLimitEnabled">Task Timer</label>
|
||||||
</div>
|
<label class="provider-toggle" for="timeLimitEnabled">
|
||||||
<div class="field">
|
<input id="timeLimitEnabled" type="checkbox"${timeLimitChecked} />
|
||||||
<label for="timeLimitMax">Max Time</label>
|
<span class="switch" aria-hidden="true"></span>
|
||||||
<input id="timeLimitMax" type="number" min="1" step="60" value="${settings.timeLimitMax}" />
|
<span class="provider-copy">
|
||||||
|
<strong>${timeLimitLabel}</strong>
|
||||||
|
<small>Time Limits</small>
|
||||||
|
</span>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<div class="field">
|
||||||
|
<label for="timeLimitMin">Min Time</label>
|
||||||
|
<input id="timeLimitMin" type="number" min="1" step="60" value="${timeLimitMinValue}"${timeLimitDisabled} />
|
||||||
|
</div>
|
||||||
|
<div class="field">
|
||||||
|
<label for="timeLimitMax">Max Time</label>
|
||||||
|
<input id="timeLimitMax" type="number" min="1" step="60" value="${timeLimitMaxValue}"${timeLimitDisabled} />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
@ -222,7 +266,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="form compact">
|
<div class="form compact">
|
||||||
<div class="field">
|
<div class="field">
|
||||||
<label for="medicalSpawnCost">Medical Spawn</label>
|
<label for="medicalSpawnCost">Medical Respawn</label>
|
||||||
<input id="medicalSpawnCost" type="number" min="0" step="50" value="${settings.medicalSpawnCost}" />
|
<input id="medicalSpawnCost" type="number" min="0" step="50" value="${settings.medicalSpawnCost}" />
|
||||||
</div>
|
</div>
|
||||||
<div class="field">
|
<div class="field">
|
||||||
@ -266,10 +310,10 @@
|
|||||||
<div class="summary-row"><span>Reward Range</span><strong>$${Number(settings.moneyMin).toLocaleString()} - $${Number(settings.moneyMax).toLocaleString()}</strong></div>
|
<div class="summary-row"><span>Reward Range</span><strong>$${Number(settings.moneyMin).toLocaleString()} - $${Number(settings.moneyMax).toLocaleString()}</strong></div>
|
||||||
<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>${timeLimitSummary}</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>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>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>
|
<div class="summary-row"><span>Medical Billing</span><strong>$${Number(settings.medicalSpawnCost).toLocaleString()} respawn / $${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>
|
||||||
@ -315,7 +359,7 @@
|
|||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
state.factions = factions;
|
state.factions = factions;
|
||||||
state.settings = Object.assign({}, state.settings, payload.data?.settings || {});
|
state.settings = normalizeSettings(Object.assign({}, state.settings, payload.data?.settings || {}));
|
||||||
render();
|
render();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -34,7 +34,7 @@ GVAR(ActorModel) = compileFinal createHashMapObject [[
|
|||||||
|
|
||||||
if (isArray _loadoutConfig) exitWith { getArray _loadoutConfig };
|
if (isArray _loadoutConfig) exitWith { getArray _loadoutConfig };
|
||||||
|
|
||||||
[[],[],[],["U_BG_Guerrilla_6_1",[["FirstAidKit", 2]]],[],[],"H_Cap_blk_ION","",[],["ItemMap","ItemGPS","ItemRadio","ItemCompass","ItemWatch",""]]
|
[[],[],["hgun_P07_F","","","",["16Rnd_9x21_Mag",4,17],[],""],["U_BG_Guerrilla_6_1",[["FirstAidKit", 2],["ACE_EarPlugs",1]]],["V_Rangemaster_belt",[["16Rnd_9x21_Mag",4]]],[],"H_Cap_blk_ION","",["Binocular","","","",[],[],""],["ItemMap","ItemGPS","ItemRadio","ItemCompass","ItemWatch",""]]
|
||||||
}],
|
}],
|
||||||
["defaults", compileFinal {
|
["defaults", compileFinal {
|
||||||
private _actor = createHashMap;
|
private _actor = createHashMap;
|
||||||
@ -116,13 +116,11 @@ GVAR(ActorModel) = compileFinal createHashMapObject [[
|
|||||||
}]
|
}]
|
||||||
]];
|
]];
|
||||||
|
|
||||||
GVAR(ActorBaseStore) = compileFinal ([
|
GVAR(ActorBaseStore) = compileFinal createHashMapFromArray [
|
||||||
EGVAR(common,BaseStore),
|
["#base", EGVAR(common,BaseStore)],
|
||||||
createHashMapFromArray [
|
|
||||||
["#type", "ActorBaseStore"],
|
["#type", "ActorBaseStore"],
|
||||||
["#create", compileFinal {
|
["#create", compileFinal {
|
||||||
["INFO", "Actor Store Initialized!"] call EFUNC(common,log);
|
["INFO", "Actor Store Initialized!"] call EFUNC(common,log);
|
||||||
true
|
|
||||||
}],
|
}],
|
||||||
["cacheActor", compileFinal {
|
["cacheActor", compileFinal {
|
||||||
params [["_uid", "", [""]], ["_actor", createHashMap, [createHashMap]]];
|
params [["_uid", "", [""]], ["_actor", createHashMap, [createHashMap]]];
|
||||||
@ -574,13 +572,7 @@ GVAR(ActorBaseStore) = compileFinal ([
|
|||||||
|
|
||||||
_self call ["override", [_uid, _finalActor, false]]
|
_self call ["override", [_uid, _finalActor, false]]
|
||||||
}]
|
}]
|
||||||
]] call {
|
];
|
||||||
params ["_base", "_child"];
|
|
||||||
|
|
||||||
private _merged = +_base;
|
GVAR(ActorStore) = createHashMapObject [GVAR(ActorBaseStore)];
|
||||||
{ _merged set [_x, _y]; } forEach _child;
|
GVAR(ActorStore)
|
||||||
_merged
|
|
||||||
});
|
|
||||||
|
|
||||||
GVAR(ActorStore) = createHashMapObject [GVAR(ActorBaseStore), []];
|
|
||||||
true
|
|
||||||
|
|||||||
@ -4,6 +4,8 @@ PREP_RECOMPILE_START;
|
|||||||
#include "XEH_PREP.hpp"
|
#include "XEH_PREP.hpp"
|
||||||
PREP_RECOMPILE_END;
|
PREP_RECOMPILE_END;
|
||||||
|
|
||||||
|
if (isServer) then { "forge_server" callExtension ["surreal:reconnect", []]; };
|
||||||
|
|
||||||
GVAR(PlayerBootstrapRegistry) = createHashMap;
|
GVAR(PlayerBootstrapRegistry) = createHashMap;
|
||||||
|
|
||||||
["forge_icom_event", {
|
["forge_icom_event", {
|
||||||
|
|||||||
@ -72,12 +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
|
`modMode` applies before category filtering. `dynamic` means no mod-source
|
||||||
entries that match one of the configured `mods[]`; `denylist` removes matching
|
filtering. `allowlist` only keeps generated entries that match one of the
|
||||||
entries. Each `ModSources` child can define `patches[]` to detect whether the
|
configured `mods[]`; `denylist` removes matching entries. Each `ModSources`
|
||||||
mod is loaded, `addons[]` for config source addon/source mod names or classname
|
child can define `patches[]` to detect whether the mod is loaded, `addons[]`
|
||||||
prefixes, and `prefixes[]` for classname prefixes. If a mod source defines no
|
for exact config source addon/source mod names, and `prefixes[]` for classname,
|
||||||
patches, it is treated as available and only the source/prefix checks are used.
|
source addon, or source mod 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
|
||||||
|
|||||||
@ -111,17 +111,18 @@ GVAR(StoreCatalogServiceBaseClass) = compileFinal createHashMapFromArray [
|
|||||||
private _sourceMod = _item getOrDefault ["sourceMod", ""];
|
private _sourceMod = _item getOrDefault ["sourceMod", ""];
|
||||||
private _addons = (_self call ["getMissionStoreModSourceValues", [_modID, "addons"]]) apply { toLowerANSI _x };
|
private _addons = (_self call ["getMissionStoreModSourceValues", [_modID, "addons"]]) apply { toLowerANSI _x };
|
||||||
private _prefixes = (_self call ["getMissionStoreModSourceValues", [_modID, "prefixes"]]) apply { toLowerANSI _x };
|
private _prefixes = (_self call ["getMissionStoreModSourceValues", [_modID, "prefixes"]]) apply { toLowerANSI _x };
|
||||||
|
private _matchPrefixes = _addons + _prefixes;
|
||||||
private _sourceModLower = toLowerANSI _sourceMod;
|
private _sourceModLower = toLowerANSI _sourceMod;
|
||||||
|
|
||||||
if (_sourceModLower in _addons) exitWith { true };
|
if (_sourceModLower in _addons) exitWith { true };
|
||||||
private _sourceAddonMatched = false;
|
private _sourceAddonMatched = false;
|
||||||
{
|
{
|
||||||
if (_x in _addons) exitWith { _sourceAddonMatched = true; };
|
if (_x in _addons) exitWith { _sourceAddonMatched = true; };
|
||||||
if (_self call ["doesValueMatchAnyPrefix", [_x, _addons]]) exitWith { _sourceAddonMatched = true; };
|
if (_self call ["doesValueMatchAnyPrefix", [_x, _matchPrefixes]]) exitWith { _sourceAddonMatched = true; };
|
||||||
} forEach _sourceAddons;
|
} forEach _sourceAddons;
|
||||||
if (_sourceAddonMatched) exitWith { true };
|
if (_sourceAddonMatched) exitWith { true };
|
||||||
if (_self call ["doesValueMatchAnyPrefix", [_className, _addons + _prefixes]]) exitWith { true };
|
if (_self call ["doesValueMatchAnyPrefix", [_className, _matchPrefixes]]) exitWith { true };
|
||||||
if (_self call ["doesValueMatchAnyPrefix", [_sourceMod, _addons]]) exitWith { true };
|
if (_self call ["doesValueMatchAnyPrefix", [_sourceMod, _matchPrefixes]]) exitWith { true };
|
||||||
|
|
||||||
false
|
false
|
||||||
}],
|
}],
|
||||||
|
|||||||
@ -154,7 +154,7 @@ GVAR(MissionSetupServiceBaseClass) = compileFinal createHashMapFromArray [
|
|||||||
_penMin = _penMin min 0;
|
_penMin = _penMin min 0;
|
||||||
_penMax = _penMax min 0;
|
_penMax = _penMax min 0;
|
||||||
|
|
||||||
_timeMin = _timeMin max 1;
|
_timeMin = _timeMin max 0;
|
||||||
_timeMax = _timeMax max _timeMin;
|
_timeMax = _timeMax max _timeMin;
|
||||||
_medicalSpawnCost = _medicalSpawnCost max 0;
|
_medicalSpawnCost = _medicalSpawnCost max 0;
|
||||||
_medicalHealCost = _medicalHealCost max 0;
|
_medicalHealCost = _medicalHealCost max 0;
|
||||||
|
|||||||
@ -164,9 +164,13 @@ airports, bus stops, teleport terminals, or any other mission transport system.
|
|||||||
The framework owns the menu, billing, cargo scan, and movement logic. The
|
The framework owns the menu, billing, cargo scan, and movement logic. The
|
||||||
mission only needs placed objects and optional arrival markers.
|
mission only needs placed objects and optional arrival markers.
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
Place transport node objects with these variable names:
|
Place transport node objects with these variable names:
|
||||||
|
|
||||||
@ -188,7 +192,9 @@ transport_arrival_2
|
|||||||
transport_arrival_10
|
transport_arrival_10
|
||||||
```
|
```
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
Objects that should be excluded from the nearby cargo scan, such as the actual
|
Objects that should be excluded from the nearby cargo scan, such as the actual
|
||||||
boat or transport vehicle used as set dressing, should use:
|
boat or transport vehicle used as set dressing, should use:
|
||||||
@ -201,7 +207,9 @@ transport_vehicle_2
|
|||||||
transport_vehicle_10
|
transport_vehicle_10
|
||||||
```
|
```
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
Minimum Eden setup:
|
Minimum Eden setup:
|
||||||
|
|
||||||
@ -759,6 +767,11 @@ provider preference. It also exposes service pricing for medical spawn, heal,
|
|||||||
repair, rearm, refuel, and transport defaults. It does not enable or disable
|
repair, rearm, refuel, and transport defaults. It does not enable or disable
|
||||||
generated missions; use the CBA setting for that policy.
|
generated missions; use the CBA setting for that policy.
|
||||||
|
|
||||||
|
Task time limits can be disabled from the setup UI by turning off the task
|
||||||
|
timer. That stores `timeLimitMin = 0` and `timeLimitMax = 0`, which generated
|
||||||
|
tasks treat as no timer. Positive min/max values enable task timers and are
|
||||||
|
rolled in seconds.
|
||||||
|
|
||||||
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.
|
||||||
|
|||||||
@ -227,7 +227,7 @@ Player workflow:
|
|||||||
1. Stand near a transport point.
|
1. Stand near a transport point.
|
||||||
2. Open the actor interaction menu.
|
2. Open the actor interaction menu.
|
||||||
3. Select Transport.
|
3. Select Transport.
|
||||||
4. Select a destination from the transport submenu, or select Back to return
|
4. Select a destination from the transport submenu, or select Close to return
|
||||||
to the default interaction menu.
|
to the default interaction menu.
|
||||||
|
|
||||||

|

|
||||||
|
|||||||
@ -72,12 +72,24 @@ listed for each category. `denylist` removes listed classnames. Overrides are
|
|||||||
server-side and are used by both the UI payload and checkout validation.
|
server-side and are used by both the UI payload and checkout validation.
|
||||||
`units[]` uses the same filter behavior as every other category.
|
`units[]` uses the same filter behavior as every other category.
|
||||||
|
|
||||||
`modMode` applies before category filtering. `allowlist` only keeps generated
|
`modMode` applies before category filtering. `dynamic` means no mod-source
|
||||||
entries that match one of the configured `mods[]`; `denylist` removes matching
|
filtering. `allowlist` only keeps generated entries that match one of the
|
||||||
entries. Each `ModSources` child can define `patches[]` to detect whether the
|
configured `mods[]`; `denylist` removes matching entries. Each `ModSources`
|
||||||
mod is loaded, `addons[]` for config source addon/source mod names or classname
|
child can define `patches[]` to detect whether the mod is loaded, `addons[]`
|
||||||
prefixes, and `prefixes[]` for classname prefixes. If a mod source defines no
|
for exact config source addon/source mod names, and `prefixes[]` for classname,
|
||||||
patches, it is treated as available and only the source/prefix checks are used.
|
source addon, or source mod prefixes. If a mod source defines no patches, it is
|
||||||
|
treated as available and only the source/prefix checks are used.
|
||||||
|
|
||||||
|
For example, to show only RHS-sourced generated inventory:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
modMode = "allowlist";
|
||||||
|
mods[] = {"rhs"};
|
||||||
|
```
|
||||||
|
|
||||||
|
The matching `class rhs` must exist under `ModSources`. Category `mode` is still
|
||||||
|
applied afterward, so leave `mode = "dynamic"` if the mod filter should be the
|
||||||
|
only inventory filter.
|
||||||
|
|
||||||
The current filter is global for the mission. Revisit per-store profile support
|
The current filter is global for the mission. Revisit per-store profile support
|
||||||
if individual vendors need different inventories.
|
if individual vendors need different inventories.
|
||||||
|
|||||||
@ -631,6 +631,10 @@ Task time limits use `0` for no limit:
|
|||||||
Positive values are measured in seconds. Do not pass `-1` as a no-limit value;
|
Positive values are measured in seconds. Do not pass `-1` as a no-limit value;
|
||||||
the task runtime treats any non-zero task time limit as active.
|
the task runtime treats any non-zero task time limit as active.
|
||||||
|
|
||||||
|
The mission setup UI uses the same rule. Turning off the task timer stores
|
||||||
|
`timeLimitMin = 0` and `timeLimitMax = 0`; turning it on uses the configured
|
||||||
|
positive min/max range for generated tasks.
|
||||||
|
|
||||||
Defuse IED timers are different. `iedTimer` must be greater than `0`, because
|
Defuse IED timers are different. `iedTimer` must be greater than `0`, because
|
||||||
IEDs are expected to have an active countdown. The Eden defuse module defaults
|
IEDs are expected to have an active countdown. The Eden defuse module defaults
|
||||||
to `300` seconds.
|
to `300` seconds.
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
The transport service provides paid point-to-point travel for players and
|
The transport service provides paid point-to-point travel for players and
|
||||||
nearby vehicles or passengers. It is framework-owned: missions only need placed
|
nearby vehicles or passengers. It is framework-owned: missions only need placed
|
||||||
transport objects and arrival markers with the expected variable names.
|
transport objects and optional arrival markers with the expected variable names.
|
||||||
|
|
||||||
## Mission Contract
|
## Mission Contract
|
||||||
|
|
||||||
@ -117,9 +117,9 @@ this setVariable ["transportIncludeCargo", true, true];
|
|||||||
Only use overrides when the default `transport*` convention or mission-level
|
Only use overrides when the default `transport*` convention or mission-level
|
||||||
pricing is not appropriate.
|
pricing is not appropriate.
|
||||||
|
|
||||||
## Reference Images
|
## Image Checklist
|
||||||
|
|
||||||
These screenshots show the default transport setup and player workflow:
|
Replace these placeholder image references after screenshots are captured:
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
@ -142,3 +142,9 @@ These screenshots show the default transport setup and player workflow:
|
|||||||

|

|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
|
## Mission-Side Code Requirement
|
||||||
|
|
||||||
|
No mission-side transport service, addAction script, or server event bridge is
|
||||||
|
required. The framework handles menu discovery, destination selection, pricing,
|
||||||
|
billing, cargo movement, and EventBus notifications.
|
||||||
|
|||||||
@ -164,9 +164,13 @@ airports, bus stops, teleport terminals, or any other mission transport system.
|
|||||||
The framework owns the menu, billing, cargo scan, and movement logic. The
|
The framework owns the menu, billing, cargo scan, and movement logic. The
|
||||||
mission only needs placed objects and optional arrival markers.
|
mission only needs placed objects and optional arrival markers.
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
Place transport node objects with these variable names:
|
Place transport node objects with these variable names:
|
||||||
|
|
||||||
@ -188,7 +192,9 @@ transport_arrival_2
|
|||||||
transport_arrival_10
|
transport_arrival_10
|
||||||
```
|
```
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
Objects that should be excluded from the nearby cargo scan, such as the actual
|
Objects that should be excluded from the nearby cargo scan, such as the actual
|
||||||
boat or transport vehicle used as set dressing, should use:
|
boat or transport vehicle used as set dressing, should use:
|
||||||
@ -201,7 +207,9 @@ transport_vehicle_2
|
|||||||
transport_vehicle_10
|
transport_vehicle_10
|
||||||
```
|
```
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
Minimum Eden setup:
|
Minimum Eden setup:
|
||||||
|
|
||||||
|
|||||||
@ -226,7 +226,7 @@ Player workflow:
|
|||||||
1. Stand near a transport point.
|
1. Stand near a transport point.
|
||||||
2. Open the actor interaction menu.
|
2. Open the actor interaction menu.
|
||||||
3. Select Transport.
|
3. Select Transport.
|
||||||
4. Select a destination from the transport submenu, or select Back to return
|
4. Select a destination from the transport submenu, or select Close to return
|
||||||
to the default interaction menu.
|
to the default interaction menu.
|
||||||
|
|
||||||

|

|
||||||
|
|||||||
158
docus/content/1.getting-started/8.git-workflow.md
Normal file
158
docus/content/1.getting-started/8.git-workflow.md
Normal file
@ -0,0 +1,158 @@
|
|||||||
|
---
|
||||||
|
title: "Git Workflow"
|
||||||
|
description: "This repository uses `master` as the clean framework branch. Mission folders are kept off `master` so the framework can be versioned without bundling local test missions or playable mission copies."
|
||||||
|
---
|
||||||
|
|
||||||
|
## Workflow Helper
|
||||||
|
|
||||||
|
The repository includes a small helper for the common branch checks and branch
|
||||||
|
switching commands:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
npm run workflow -- status
|
||||||
|
npm run workflow -- doctor
|
||||||
|
npm run workflow -- switch dev
|
||||||
|
npm run workflow -- switch missions
|
||||||
|
npm run workflow -- start-feature cad-task-request
|
||||||
|
npm run workflow -- release-check
|
||||||
|
```
|
||||||
|
|
||||||
|
The helper refuses branch switches and feature branch creation when the working
|
||||||
|
tree has uncommitted changes. Use the manual Git commands below when you need
|
||||||
|
more control.
|
||||||
|
|
||||||
|
## Branch Roles
|
||||||
|
|
||||||
|
- `master`: framework source, addon code, Rust extension code, docs, tooling,
|
||||||
|
and release tags.
|
||||||
|
- `missions/local-mission-copies`: local mission folders used for testing and
|
||||||
|
mission iteration. This branch is not pushed unless intentionally needed.
|
||||||
|
- `archive/pre-v0.1-history`: read-only archive of the previous full `master`
|
||||||
|
history before the `v0.1.0` baseline cleanup.
|
||||||
|
|
||||||
|
## Daily Framework Work
|
||||||
|
|
||||||
|
Start from the clean framework branch.
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
git switch master
|
||||||
|
git pull
|
||||||
|
git status --short --branch
|
||||||
|
```
|
||||||
|
|
||||||
|
Create a short-lived feature branch for framework work.
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
git switch -c feature/garage-marker-selection
|
||||||
|
```
|
||||||
|
|
||||||
|
Make the change, validate it, then commit.
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
git status --short --branch
|
||||||
|
git add arma/client/addons/garage/functions/fnc_initContextService.sqf
|
||||||
|
git commit -m "Improve garage spawn marker selection"
|
||||||
|
```
|
||||||
|
|
||||||
|
Merge the work back into `master`. Squash merges keep future `master` history
|
||||||
|
compact.
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
git switch master
|
||||||
|
git merge --squash feature/garage-marker-selection
|
||||||
|
git commit -m "Improve garage spawn marker selection"
|
||||||
|
git push
|
||||||
|
```
|
||||||
|
|
||||||
|
Remove the local feature branch when it is no longer needed.
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
git branch -D feature/garage-marker-selection
|
||||||
|
```
|
||||||
|
|
||||||
|
## Mission Work
|
||||||
|
|
||||||
|
Switch to the local mission branch before editing mission folders.
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
git switch missions/local-mission-copies
|
||||||
|
git status --short --branch
|
||||||
|
```
|
||||||
|
|
||||||
|
Mission folders currently tracked on that branch:
|
||||||
|
|
||||||
|
```text
|
||||||
|
arma/forge_framework.Malden
|
||||||
|
arma/forge_pmc_simulator.Tanoa
|
||||||
|
arma/forge_pmc_simulator_v2.Tanoa
|
||||||
|
```
|
||||||
|
|
||||||
|
Commit mission-only changes on the mission branch.
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
git add arma/forge_pmc_simulator.Tanoa
|
||||||
|
git commit -m "Update PMC simulator mission setup"
|
||||||
|
```
|
||||||
|
|
||||||
|
Do not merge the mission branch into `master`. If a mission change becomes
|
||||||
|
framework code, copy only the reusable files or logic onto a framework feature
|
||||||
|
branch created from `master`.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
git switch master
|
||||||
|
git switch -c feature/cad-on-demand-task-request
|
||||||
|
|
||||||
|
# Bring over only the framework files needed from the mission branch.
|
||||||
|
git checkout missions/local-mission-copies -- arma/client/addons/cad/functions/fnc_initUIBridge.sqf
|
||||||
|
git checkout missions/local-mission-copies -- arma/server/addons/cad/XEH_preInit.sqf
|
||||||
|
|
||||||
|
git add arma/client/addons/cad/functions/fnc_initUIBridge.sqf arma/server/addons/cad/XEH_preInit.sqf
|
||||||
|
git commit -m "Add CAD on-demand mission task request bridge"
|
||||||
|
```
|
||||||
|
|
||||||
|
## Release Versioning
|
||||||
|
|
||||||
|
Use tags to mark framework releases.
|
||||||
|
|
||||||
|
Version guideline:
|
||||||
|
|
||||||
|
- Patch, such as `v0.1.1`: fixes and small compatible changes.
|
||||||
|
- Minor, such as `v0.2.0`: new modules or features.
|
||||||
|
- Major, such as `v1.0.0`: stable release line or breaking changes.
|
||||||
|
|
||||||
|
Create a release tag from `master`.
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
git switch master
|
||||||
|
git pull
|
||||||
|
git status --short --branch
|
||||||
|
git tag -a v0.1.1 -m "v0.1.1"
|
||||||
|
git push origin master
|
||||||
|
git push origin v0.1.1
|
||||||
|
```
|
||||||
|
|
||||||
|
## Safety Checks
|
||||||
|
|
||||||
|
Before committing on `master`, check that no mission folders are staged.
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
git status --short --branch
|
||||||
|
```
|
||||||
|
|
||||||
|
On `master`, these paths should not appear:
|
||||||
|
|
||||||
|
```text
|
||||||
|
arma/forge_framework.Malden
|
||||||
|
arma/forge_pmc_simulator.Tanoa
|
||||||
|
arma/forge_pmc_simulator_v2.Tanoa
|
||||||
|
```
|
||||||
|
|
||||||
|
If mission files appear while on `master`, stop and switch to the mission
|
||||||
|
branch before continuing.
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
git switch missions/local-mission-copies
|
||||||
|
```
|
||||||
|
|
||||||
@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
title: "Transport Service Guide"
|
title: "Transport Service Guide"
|
||||||
description: "The transport service provides paid point-to-point travel for players and nearby vehicles or passengers. It is framework-owned: missions only need placed transport objects and arrival markers with the expected variable names."
|
description: "The transport service provides paid point-to-point travel for players and nearby vehicles or passengers. It is framework-owned: missions only need placed transport objects and optional arrival markers with the expected variable names."
|
||||||
---
|
---
|
||||||
|
|
||||||
## Mission Contract
|
## Mission Contract
|
||||||
@ -109,9 +109,9 @@ this setVariable ["transportIncludeCargo", true, true];
|
|||||||
|
|
||||||
Only use overrides when the default `transport*` convention is not appropriate.
|
Only use overrides when the default `transport*` convention is not appropriate.
|
||||||
|
|
||||||
## Reference Images
|
## Image Checklist
|
||||||
|
|
||||||
These screenshots show the default transport setup and player workflow:
|
Replace these placeholder image references after screenshots are captured:
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
@ -134,3 +134,9 @@ These screenshots show the default transport setup and player workflow:
|
|||||||

|

|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
|
## Mission-Side Code Requirement
|
||||||
|
|
||||||
|
No mission-side transport service, addAction script, or server event bridge is
|
||||||
|
required. The framework handles menu discovery, destination selection, pricing,
|
||||||
|
billing, cargo movement, and EventBus notifications.
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user