@jgengine/core 0.26.0 → 0.28.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +174 -0
- package/dist/ai/policeResponse.d.ts +253 -0
- package/dist/ai/policeResponse.js +421 -0
- package/dist/anim/actionLayer.d.ts +47 -0
- package/dist/anim/actionLayer.js +63 -0
- package/dist/anim/ikSolver.d.ts +14 -0
- package/dist/anim/ikSolver.js +37 -0
- package/dist/anim/locomotionGraph.d.ts +58 -3
- package/dist/anim/locomotionGraph.js +142 -15
- package/dist/anim/ragdollRig.d.ts +53 -0
- package/dist/anim/ragdollRig.js +132 -0
- package/dist/anim/skeletonStandard.d.ts +140 -0
- package/dist/anim/skeletonStandard.js +326 -0
- package/dist/combat/damageRuntime.d.ts +14 -1
- package/dist/combat/damageRuntime.js +62 -4
- package/dist/combat/death.js +7 -3
- package/dist/combat/deathReason.d.ts +7 -1
- package/dist/combat/effects.d.ts +25 -0
- package/dist/combat/effects.js +16 -0
- package/dist/combat/statusRuntime.d.ts +2 -0
- package/dist/combat/statusRuntime.js +1 -0
- package/dist/economy/loanBook.d.ts +182 -0
- package/dist/economy/loanBook.js +303 -0
- package/dist/economy/market.d.ts +161 -0
- package/dist/economy/market.js +248 -0
- package/dist/economy/transactionLedger.d.ts +162 -0
- package/dist/economy/transactionLedger.js +301 -0
- package/dist/editor/creatorStorage.js +3 -1
- package/dist/editor/simulation.d.ts +5 -2
- package/dist/editor/simulation.js +29 -19
- package/dist/game/cameraConfig.d.ts +14 -0
- package/dist/game/clipRoles.d.ts +5 -4
- package/dist/game/clipRoles.js +34 -4
- package/dist/game/events.d.ts +27 -0
- package/dist/game/gameSave.d.ts +142 -0
- package/dist/game/gameSave.js +174 -0
- package/dist/game/playableGame.d.ts +74 -6
- package/dist/game/saveSlotIndex.d.ts +54 -0
- package/dist/game/saveSlotIndex.js +71 -0
- package/dist/game/saveSlots.d.ts +2 -0
- package/dist/game/saveSlots.js +1 -1
- package/dist/game/saveStore.d.ts +8 -0
- package/dist/game/saveStore.js +16 -0
- package/dist/gameplay.d.ts +17 -2
- package/dist/gameplay.js +15 -0
- package/dist/inventory/carryLoad.d.ts +48 -0
- package/dist/inventory/carryLoad.js +44 -0
- package/dist/inventory/equipment.d.ts +95 -0
- package/dist/inventory/equipment.js +169 -0
- package/dist/inventory/inventoryModel.d.ts +15 -6
- package/dist/inventory/inventoryModel.js +54 -5
- package/dist/inventory/shapedGrid.d.ts +26 -0
- package/dist/inventory/shapedGrid.js +47 -0
- package/dist/loot/lootGen.d.ts +186 -0
- package/dist/loot/lootGen.js +437 -0
- package/dist/loot/lootWeapon.d.ts +35 -0
- package/dist/loot/lootWeapon.js +70 -0
- package/dist/meta/changelog.d.ts +1 -1
- package/dist/meta/changelog.js +156 -1
- package/dist/mission/compositions.d.ts +85 -0
- package/dist/mission/compositions.js +130 -0
- package/dist/mission/mission.d.ts +435 -0
- package/dist/mission/mission.js +770 -0
- package/dist/mission/triggers.d.ts +61 -0
- package/dist/mission/triggers.js +108 -0
- package/dist/nav/laneGraph.d.ts +178 -0
- package/dist/nav/laneGraph.js +671 -0
- package/dist/nav/traffic.d.ts +222 -0
- package/dist/nav/traffic.js +918 -0
- package/dist/physics/kinematicVehicle.d.ts +36 -0
- package/dist/physics/kinematicVehicle.js +15 -1
- package/dist/physics/vehicleDamage.d.ts +136 -0
- package/dist/physics/vehicleDamage.js +214 -0
- package/dist/physics/vehicleParts.d.ts +62 -0
- package/dist/physics/vehicleParts.js +65 -0
- package/dist/progression/gearScore.d.ts +56 -0
- package/dist/progression/gearScore.js +59 -0
- package/dist/progression/skillTree.d.ts +129 -0
- package/dist/progression/skillTree.js +265 -0
- package/dist/progression/xpCurve.d.ts +60 -0
- package/dist/progression/xpCurve.js +141 -0
- package/dist/runtime/context/combat.js +11 -0
- package/dist/scene/builtinSceneKinds.js +2 -0
- package/dist/settings/accessibilitySettings.d.ts +81 -0
- package/dist/settings/accessibilitySettings.js +152 -0
- package/dist/settings/graphicsProfile.d.ts +3 -0
- package/dist/settings/graphicsProfile.js +4 -0
- package/dist/settings/settingsModel.d.ts +1 -1
- package/dist/settings/settingsModel.js +1 -0
- package/dist/sim/nearAgents.d.ts +8 -1
- package/dist/sim/nearAgents.js +34 -17
- package/dist/sim/offScreen.d.ts +2 -1
- package/dist/sim/offScreen.js +14 -3
- package/dist/sim/population.d.ts +147 -0
- package/dist/sim/population.js +182 -0
- package/dist/sim/queue.d.ts +90 -0
- package/dist/sim/queue.js +171 -0
- package/dist/sim/rides.d.ts +287 -0
- package/dist/sim/rides.js +471 -0
- package/dist/sim/routine.js +19 -11
- package/dist/ui/loadingTips.d.ts +41 -0
- package/dist/ui/loadingTips.js +64 -0
- package/dist/ui/menuNav.d.ts +79 -0
- package/dist/ui/menuNav.js +147 -0
- package/dist/ui/menuTransition.d.ts +50 -0
- package/dist/ui/menuTransition.js +67 -0
- package/dist/ui.d.ts +2 -0
- package/dist/ui.js +2 -0
- package/dist/vfx/effectLibrary.d.ts +98 -0
- package/dist/vfx/effectLibrary.js +181 -0
- package/dist/vfx/particleBudget.d.ts +40 -0
- package/dist/vfx/particleBudget.js +39 -0
- package/dist/vfx/particleDirector.d.ts +16 -0
- package/dist/vfx/particleDirector.js +18 -0
- package/dist/world/authoredSimulation.js +7 -1
- package/dist/world/captureCamera.d.ts +30 -0
- package/dist/world/captureCamera.js +19 -0
- package/dist/world/decalKind.d.ts +48 -0
- package/dist/world/decalKind.js +86 -0
- package/dist/world/features.d.ts +18 -5
- package/dist/world/features.js +1 -0
- package/dist/world/grassKind.d.ts +5 -0
- package/dist/world/grassKind.js +3 -0
- package/dist/world/terraform.d.ts +8 -0
- package/dist/world/terrain.d.ts +1 -0
- package/dist/world/terrain.js +2 -0
- package/dist/world.d.ts +7 -2
- package/dist/world.js +5 -0
- package/package.json +1 -1
- package/skills/jgengine/api.md +2 -2
- package/skills/jgengine-combat/SKILL.md +9 -1
- package/skills/jgengine-combat/api.md +5 -4
- package/skills/jgengine-combat/reference.md +4 -0
- package/skills/jgengine-gameplay/SKILL.md +86 -0
- package/skills/jgengine-gameplay/api.md +485 -16
- package/skills/jgengine-gameplay/capabilities.md +131 -4
- package/skills/jgengine-gameplay/reference-systems.md +118 -0
- package/skills/jgengine-world/SKILL.md +8 -0
- package/skills/jgengine-world/api.md +243 -11
- package/skills/jgengine-world/capabilities.md +61 -1
- package/skills/jgengine-world/recipes/character-animation.md +25 -2
- package/skills/jgengine-world/recipes/vehicle-feel.md +5 -0
- package/skills/jgengine-world/reference.md +1 -1
|
@@ -0,0 +1,435 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Missions as data: a mission is a graph of objectives a state machine walks, with named fail
|
|
3
|
+
* states, per-objective timers, conditional branches and rewards. Nothing here is a genre kit —
|
|
4
|
+
* escort, chase and defend are compositions of the same objective kinds, built in `compositions.ts`.
|
|
5
|
+
*
|
|
6
|
+
* The machine is pure, serializable and bounded: one active mission, one objective's worth of
|
|
7
|
+
* work per tick, and every fact it reads is supplied by the caller.
|
|
8
|
+
*/
|
|
9
|
+
import { type QuestRewards } from "../game/quest.js";
|
|
10
|
+
import type { ScenePoint3 } from "../world/sceneShapes.js";
|
|
11
|
+
/** Where a mission is in its life. */
|
|
12
|
+
export type MissionStatus = "active" | "completed" | "failed";
|
|
13
|
+
/**
|
|
14
|
+
* The primitive goals an objective can have. Escort, chase and defend are not kinds — they are
|
|
15
|
+
* compositions of these plus fail conditions and timers (see `compositions.ts`).
|
|
16
|
+
*/
|
|
17
|
+
export type MissionObjectiveKind = "reach" | "interact" | "survive" | "pursue" | "kill" | "collect";
|
|
18
|
+
/** Objective kinds that are satisfied only by a counter — a mission made of these alone is a lint error. */
|
|
19
|
+
export declare const MISSION_COUNTER_KINDS: readonly MissionObjectiveKind[];
|
|
20
|
+
/**
|
|
21
|
+
* True when an objective kind completes from a counter rather than a world condition — the test the
|
|
22
|
+
* counter-only lint is built on.
|
|
23
|
+
*
|
|
24
|
+
* @capability mission-validation tell whether an objective kind completes from a counter alone
|
|
25
|
+
*/
|
|
26
|
+
export declare function isCounterObjective(kind: MissionObjectiveKind): boolean;
|
|
27
|
+
/** What a reported world event is. */
|
|
28
|
+
export type MissionWorldEventKind = "kill" | "collect" | "deliver";
|
|
29
|
+
/**
|
|
30
|
+
* One thing that happened in the world this tick, reported by the game. A constrained objective counts
|
|
31
|
+
* matching events and an `event` fail condition reacts to them, so the machine judges the world instead
|
|
32
|
+
* of the game polling its own counters.
|
|
33
|
+
*
|
|
34
|
+
* @capability mission-events count constrained kills and fail a mission on a matching world event
|
|
35
|
+
*/
|
|
36
|
+
export interface MissionWorldEvent {
|
|
37
|
+
kind: MissionWorldEventKind;
|
|
38
|
+
/** Target catalog id, item id or route id the event concerns. */
|
|
39
|
+
target: string;
|
|
40
|
+
/** Actor that caused it. */
|
|
41
|
+
by?: string;
|
|
42
|
+
/** Free-form tags the game attaches — weapon, element, route, `decoy`. */
|
|
43
|
+
tags?: readonly string[];
|
|
44
|
+
/** How many the event is worth. Default 1. */
|
|
45
|
+
count?: number;
|
|
46
|
+
}
|
|
47
|
+
/** Which world events an objective counts or a fail condition reacts to. Absent fields do not filter. */
|
|
48
|
+
export interface MissionEventFilter {
|
|
49
|
+
/** Event kind; a `kill`/`collect` objective defaults to its own kind. */
|
|
50
|
+
kind?: MissionWorldEventKind;
|
|
51
|
+
/** Exact target id. */
|
|
52
|
+
target?: string;
|
|
53
|
+
/** Exact actor that caused it. */
|
|
54
|
+
by?: string;
|
|
55
|
+
/** Every one of these tags must be present. */
|
|
56
|
+
tags?: readonly string[];
|
|
57
|
+
/** None of these may be present — how a decoy or a wrong-weapon kill is excluded. */
|
|
58
|
+
withoutTags?: readonly string[];
|
|
59
|
+
}
|
|
60
|
+
/** A readable fact test a branch or a `fact` fail condition reads. All comparators are optional. */
|
|
61
|
+
export interface MissionFactCondition {
|
|
62
|
+
/** Fact name, or `"score"` for the mission's running survival score. */
|
|
63
|
+
fact: string;
|
|
64
|
+
/** Matches when the fact strictly equals this. */
|
|
65
|
+
is?: string | number | boolean;
|
|
66
|
+
/** Matches when the numeric fact is at least this. */
|
|
67
|
+
atLeast?: number;
|
|
68
|
+
/** Matches when the numeric fact is at most this. */
|
|
69
|
+
atMost?: number;
|
|
70
|
+
/** Invert the whole test. */
|
|
71
|
+
not?: boolean;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* A condition that fails the mission while the objective is active. `to` names a {@link MissionFailDef};
|
|
75
|
+
* with no `to` the mission fails with the generic `"failed"` state.
|
|
76
|
+
*
|
|
77
|
+
* `actor-died`, `timer`, `fact` and `left-area` read world state every tick; `event` reacts to a world
|
|
78
|
+
* event the game reported this tick.
|
|
79
|
+
*/
|
|
80
|
+
export interface MissionFailCondition {
|
|
81
|
+
kind: "actor-died" | "timer" | "fact" | "event" | "left-area";
|
|
82
|
+
/** `actor-died`: the tracked actor whose death fails the mission. `left-area`: the actor watched. */
|
|
83
|
+
actor?: string;
|
|
84
|
+
/** `timer`: seconds in the current objective before the mission fails. */
|
|
85
|
+
seconds?: number;
|
|
86
|
+
/** `fact`: the fact and comparator that fail the mission. */
|
|
87
|
+
fact?: string;
|
|
88
|
+
is?: string | number | boolean;
|
|
89
|
+
atLeast?: number;
|
|
90
|
+
atMost?: number;
|
|
91
|
+
/** `event`: which events fail the mission. Omitted matches any event. */
|
|
92
|
+
match?: MissionEventFilter;
|
|
93
|
+
/** `left-area`: authored marker the watched actor must stay near. */
|
|
94
|
+
marker?: string;
|
|
95
|
+
/** `left-area`: distance (m) past which the actor has left. Default {@link DEFAULT_REACH_RADIUS}. */
|
|
96
|
+
radius?: number;
|
|
97
|
+
/** Named fail state id. */
|
|
98
|
+
to?: string;
|
|
99
|
+
/** Human reason carried on the `failed` event. */
|
|
100
|
+
message?: string;
|
|
101
|
+
}
|
|
102
|
+
/** One outgoing edge of an objective: the first branch whose `when` matches wins over `next`. */
|
|
103
|
+
export interface MissionBranch {
|
|
104
|
+
/** Objective id, a {@link MissionFailDef} id, or `"done"` to complete the mission. */
|
|
105
|
+
to: string;
|
|
106
|
+
when: MissionFactCondition | readonly MissionFactCondition[];
|
|
107
|
+
/** Optional label carried on the `branch` event. */
|
|
108
|
+
label?: string;
|
|
109
|
+
}
|
|
110
|
+
/** One objective. Every field is content; the machine reads only these. */
|
|
111
|
+
export interface MissionObjectiveDef {
|
|
112
|
+
id: string;
|
|
113
|
+
kind: MissionObjectiveKind;
|
|
114
|
+
/** Human label for a HUD tracker; falls back to a derived label. */
|
|
115
|
+
label?: string;
|
|
116
|
+
/** Tracked actor for `reach` / `interact` / `survive` / the `pursue` target. */
|
|
117
|
+
actor?: string;
|
|
118
|
+
/** Pursuer for `pursue`; defaults to the runtime's `defaultPursuer`. */
|
|
119
|
+
pursuer?: string;
|
|
120
|
+
/** Authored scene marker id the actor must reach or interact at. */
|
|
121
|
+
marker?: string;
|
|
122
|
+
/** Proximity radius (m) for `reach` / `interact`. Default {@link DEFAULT_REACH_RADIUS}. */
|
|
123
|
+
radius?: number;
|
|
124
|
+
/** Seconds the actor must hold for `survive`. */
|
|
125
|
+
duration?: number;
|
|
126
|
+
/** Keep-close distance (m) for `pursue`. Default {@link DEFAULT_PURSUE_DISTANCE}. */
|
|
127
|
+
distance?: number;
|
|
128
|
+
/** Distance (m) past which a pursuit counts as escaped. Default `distance * 3`. */
|
|
129
|
+
escapeDistance?: number;
|
|
130
|
+
/** Seconds beyond `escapeDistance` before the pursuit fails. Default `0` (instant). */
|
|
131
|
+
escapeGrace?: number;
|
|
132
|
+
/** Fail state a pursuit escape lands in. Default `"failed"`. */
|
|
133
|
+
escapeFail?: string;
|
|
134
|
+
/** Counter key for `kill` / `collect`; defaults to the objective id. */
|
|
135
|
+
counter?: string;
|
|
136
|
+
/** Counter target for `kill` / `collect`. */
|
|
137
|
+
count?: number;
|
|
138
|
+
/**
|
|
139
|
+
* Count `kill` / `collect` objectives from reported world events instead of a bare counter, so only a
|
|
140
|
+
* matching event credits progress (`tags`, `withoutTags`, `target`). Omitted keeps the counter path.
|
|
141
|
+
*/
|
|
142
|
+
match?: MissionEventFilter;
|
|
143
|
+
/** Survivors that must remain for `survive`; dropping below fails the mission. */
|
|
144
|
+
minSurvivors?: number;
|
|
145
|
+
/** Fail state a `minSurvivors` breach lands in. Default `"failed"`. */
|
|
146
|
+
minSurvivorsFail?: string;
|
|
147
|
+
/** Seconds in this objective before it expires into `onTimeout`. */
|
|
148
|
+
timeout?: number;
|
|
149
|
+
/** Where expiry goes: an objective id, a fail state id, or `"done"`. Default: fail the mission. */
|
|
150
|
+
onTimeout?: string;
|
|
151
|
+
/** Conditions that fail the mission while this objective is active. */
|
|
152
|
+
failOn?: readonly MissionFailCondition[];
|
|
153
|
+
/** Next objective (or `"done"`) when the goal is met and no branch matches. */
|
|
154
|
+
next?: string;
|
|
155
|
+
/** Conditional edges, first match wins. */
|
|
156
|
+
branches?: readonly MissionBranch[];
|
|
157
|
+
}
|
|
158
|
+
/** A named fail state an objective, timer or branch can land in. */
|
|
159
|
+
export interface MissionFailDef {
|
|
160
|
+
id: string;
|
|
161
|
+
message?: string;
|
|
162
|
+
}
|
|
163
|
+
/** What a mission pays. Economy/XP/items/unlocks flow through the quest appliers; loot names tables. */
|
|
164
|
+
export interface MissionRewards extends QuestRewards {
|
|
165
|
+
/** Loot table ids the game rolls through its own loot registry (`createLootRegistry` / `rollLoot`). */
|
|
166
|
+
loot?: string[];
|
|
167
|
+
}
|
|
168
|
+
/** A whole mission: the objective graph plus its fail states and rewards. */
|
|
169
|
+
export interface MissionDef {
|
|
170
|
+
id: string;
|
|
171
|
+
title: string;
|
|
172
|
+
description?: string;
|
|
173
|
+
/** Objective the mission starts on. Defaults to the first objective. */
|
|
174
|
+
start?: string;
|
|
175
|
+
objectives: readonly MissionObjectiveDef[];
|
|
176
|
+
/** Named fail states. */
|
|
177
|
+
fail?: readonly MissionFailDef[];
|
|
178
|
+
/** Rewards paid on completion. */
|
|
179
|
+
rewards?: MissionRewards;
|
|
180
|
+
/** Rewards paid the moment a named objective completes. */
|
|
181
|
+
objectiveRewards?: Readonly<Record<string, MissionRewards>>;
|
|
182
|
+
/** One named fact rolled from `options` at start with the injected RNG — deterministic variation. */
|
|
183
|
+
rollout?: {
|
|
184
|
+
fact: string;
|
|
185
|
+
options: readonly (string | number)[];
|
|
186
|
+
};
|
|
187
|
+
/** Follow-up mission started on completion — how a chain or campaign is authored. */
|
|
188
|
+
next?: string;
|
|
189
|
+
}
|
|
190
|
+
/** A live actor the machine tracks: whether it is alive and, when needed, where it is. */
|
|
191
|
+
export interface MissionActorFact {
|
|
192
|
+
/** Defaults to alive. */
|
|
193
|
+
alive?: boolean;
|
|
194
|
+
position?: ScenePoint3;
|
|
195
|
+
}
|
|
196
|
+
/** Everything the machine reads for one tick. All optional; a mission only touches what it declares. */
|
|
197
|
+
export interface MissionTickInput {
|
|
198
|
+
actors?: Readonly<Record<string, MissionActorFact>>;
|
|
199
|
+
/** Cumulative counters for `kill` / `collect` objectives, by counter key. */
|
|
200
|
+
counters?: Readonly<Record<string, number>>;
|
|
201
|
+
/** World events that happened this tick — what a `match` objective counts and an `event` fail reacts to. */
|
|
202
|
+
events?: readonly MissionWorldEvent[];
|
|
203
|
+
/** Transient facts for branch and `fact` fail conditions. */
|
|
204
|
+
facts?: Readonly<Record<string, string | number | boolean>>;
|
|
205
|
+
/** Actor ids that interacted this frame, for `interact` objectives. */
|
|
206
|
+
interact?: readonly string[];
|
|
207
|
+
/** Survivors on the ground for a `survive` objective; defaults to the living actors in `actors`. */
|
|
208
|
+
survivors?: number;
|
|
209
|
+
}
|
|
210
|
+
/** Serializable mission state — one active mission's position in its graph. */
|
|
211
|
+
export interface MissionState {
|
|
212
|
+
missionId: string;
|
|
213
|
+
status: MissionStatus;
|
|
214
|
+
/** Current objective id, or null once the mission ended. */
|
|
215
|
+
objective: string | null;
|
|
216
|
+
/** Objective ids entered in order — the branch path a test or journal reads. */
|
|
217
|
+
path: string[];
|
|
218
|
+
/** Seconds spent in the current objective. */
|
|
219
|
+
objectiveElapsed: number;
|
|
220
|
+
/** Seconds since the mission started. */
|
|
221
|
+
elapsed: number;
|
|
222
|
+
/** Counter reads recorded for the current mission. */
|
|
223
|
+
progress: Record<string, number>;
|
|
224
|
+
/** Facts the machine set (rollout result, …). */
|
|
225
|
+
facts: Record<string, string | number | boolean>;
|
|
226
|
+
/** Per-objective transient accumulators (pursuit escape seconds). */
|
|
227
|
+
timers: Record<string, number>;
|
|
228
|
+
/** Running survival score — survivors counted as `survive` objectives complete. */
|
|
229
|
+
score: number;
|
|
230
|
+
/** Fail state id when failed, else null. */
|
|
231
|
+
outcome: string | null;
|
|
232
|
+
/** Human reason for a failure. */
|
|
233
|
+
reason: string | null;
|
|
234
|
+
}
|
|
235
|
+
/** Emitted as the machine advances. */
|
|
236
|
+
export type MissionEvent = {
|
|
237
|
+
kind: "started";
|
|
238
|
+
missionId: string;
|
|
239
|
+
mission: MissionDef;
|
|
240
|
+
} | {
|
|
241
|
+
kind: "objective";
|
|
242
|
+
missionId: string;
|
|
243
|
+
objectiveId: string;
|
|
244
|
+
label: string;
|
|
245
|
+
} | {
|
|
246
|
+
kind: "branch";
|
|
247
|
+
missionId: string;
|
|
248
|
+
from: string;
|
|
249
|
+
to: string;
|
|
250
|
+
label?: string;
|
|
251
|
+
} | {
|
|
252
|
+
kind: "timeout";
|
|
253
|
+
missionId: string;
|
|
254
|
+
objectiveId: string;
|
|
255
|
+
to: string;
|
|
256
|
+
} | {
|
|
257
|
+
kind: "reward";
|
|
258
|
+
missionId: string;
|
|
259
|
+
objectiveId: string | null;
|
|
260
|
+
rewards: MissionRewards;
|
|
261
|
+
} | {
|
|
262
|
+
kind: "failed";
|
|
263
|
+
missionId: string;
|
|
264
|
+
state: string;
|
|
265
|
+
reason: string;
|
|
266
|
+
} | {
|
|
267
|
+
kind: "completed";
|
|
268
|
+
missionId: string;
|
|
269
|
+
score: number;
|
|
270
|
+
rewards: MissionRewards | null;
|
|
271
|
+
} | {
|
|
272
|
+
kind: "chained";
|
|
273
|
+
missionId: string;
|
|
274
|
+
nextMissionId: string;
|
|
275
|
+
};
|
|
276
|
+
/** Pooled per-frame readout a HUD tracker renders. */
|
|
277
|
+
export interface MissionView {
|
|
278
|
+
missionId: string;
|
|
279
|
+
title: string;
|
|
280
|
+
status: MissionStatus;
|
|
281
|
+
objectiveId: string | null;
|
|
282
|
+
label: string;
|
|
283
|
+
objectiveElapsed: number;
|
|
284
|
+
/** Seconds left on the current objective's timer, or null when it has none. */
|
|
285
|
+
remaining: number | null;
|
|
286
|
+
/** Counter fraction 0..1 for the current objective, or 0 when it is not a counter. */
|
|
287
|
+
progress: number;
|
|
288
|
+
/** Counter value the current objective has reached. */
|
|
289
|
+
counted: number;
|
|
290
|
+
/** Counter value the current objective needs, or 0 when it is not a counter. */
|
|
291
|
+
count: number;
|
|
292
|
+
/** How many objectives the run has entered — a HUD shows this as "step N". */
|
|
293
|
+
step: number;
|
|
294
|
+
/** Objectives the mission declares; a chain shows "of M". */
|
|
295
|
+
steps: number;
|
|
296
|
+
score: number;
|
|
297
|
+
/** Fail state id once the run failed, else null. */
|
|
298
|
+
outcome: string | null;
|
|
299
|
+
/** Human failure reason, else null. */
|
|
300
|
+
reason: string | null;
|
|
301
|
+
path: readonly string[];
|
|
302
|
+
}
|
|
303
|
+
/** Counters a devtools probe or a test reads. */
|
|
304
|
+
export interface MissionStats {
|
|
305
|
+
missions: number;
|
|
306
|
+
ticks: number;
|
|
307
|
+
started: number;
|
|
308
|
+
completed: number;
|
|
309
|
+
failed: number;
|
|
310
|
+
branches: number;
|
|
311
|
+
timeouts: number;
|
|
312
|
+
/** Slowest single `tick` seen so far, in milliseconds. */
|
|
313
|
+
slowestTickMs: number;
|
|
314
|
+
}
|
|
315
|
+
/** Serializable runtime state for a save. */
|
|
316
|
+
export interface MissionRuntimeSnapshot {
|
|
317
|
+
state: MissionState | null;
|
|
318
|
+
ticks: number;
|
|
319
|
+
started: number;
|
|
320
|
+
completed: number;
|
|
321
|
+
failed: number;
|
|
322
|
+
branches: number;
|
|
323
|
+
timeouts: number;
|
|
324
|
+
}
|
|
325
|
+
/** Appliers a mission reward routes through — the same shape quests use, plus a loot-table hook. */
|
|
326
|
+
export interface MissionRewardAppliers {
|
|
327
|
+
grantXp?(amount: number): void;
|
|
328
|
+
grantEconomy?(currencyId: string, amount: number): void;
|
|
329
|
+
grantItem?(inventoryId: string, itemId: string, count: number): {
|
|
330
|
+
reason: string;
|
|
331
|
+
} | null | void;
|
|
332
|
+
grantItems?(items: Readonly<NonNullable<QuestRewards["items"]>>): {
|
|
333
|
+
reason: string;
|
|
334
|
+
} | null | void;
|
|
335
|
+
grantUnlock?(unlockId: string): void;
|
|
336
|
+
/** Roll a named loot table through the game's loot registry. */
|
|
337
|
+
grantLoot?(tableId: string): void;
|
|
338
|
+
}
|
|
339
|
+
/** Everything a mission runtime needs. */
|
|
340
|
+
export interface MissionRuntimeConfig {
|
|
341
|
+
readonly missions: readonly MissionDef[];
|
|
342
|
+
/** Marker positions resolved from the authored scene, by marker id. See `missionMarkers`. */
|
|
343
|
+
readonly markers?: Readonly<Record<string, ScenePoint3>>;
|
|
344
|
+
/** Actor id used for a `pursue` objective that names no `pursuer`. */
|
|
345
|
+
readonly defaultPursuer?: string;
|
|
346
|
+
/** `[0,1)` source for a mission's `rollout`; pass `ctx.rng`. Only read when a mission declares one. */
|
|
347
|
+
readonly rng?: () => number;
|
|
348
|
+
/** Register a devtools probe under this name so the overlay shows the active mission. */
|
|
349
|
+
readonly devtoolsName?: string;
|
|
350
|
+
/** Skip catalog validation at construction. Tooling and tests only. */
|
|
351
|
+
readonly skipValidation?: boolean;
|
|
352
|
+
}
|
|
353
|
+
/** The mission state machine over one active mission. */
|
|
354
|
+
export interface MissionRuntime {
|
|
355
|
+
/** Mission ids this runtime knows. */
|
|
356
|
+
missionIds(): readonly string[];
|
|
357
|
+
/** A mission definition, or null when unknown. */
|
|
358
|
+
mission(id: string): MissionDef | null;
|
|
359
|
+
/** Start a mission; returns its first state, or null when the id is unknown. Replaces any active run. */
|
|
360
|
+
start(missionId: string, facts?: Readonly<Record<string, string | number | boolean>>): MissionState | null;
|
|
361
|
+
/** Advance the active mission by `dt` seconds against the world. Returns every event this tick. */
|
|
362
|
+
tick(dt: number, input?: MissionTickInput): readonly MissionEvent[];
|
|
363
|
+
/** Force an objective complete — the authored-trigger path. */
|
|
364
|
+
signal(missionId: string, objectiveId: string): readonly MissionEvent[];
|
|
365
|
+
/** Fail the active mission into a named fail state — the authored-trigger path. */
|
|
366
|
+
fail(missionId: string, state: string, reason?: string): readonly MissionEvent[];
|
|
367
|
+
/** Abandon the active mission without completing or failing it. */
|
|
368
|
+
abandon(): void;
|
|
369
|
+
/** The active mission's live state, or null when none is running. */
|
|
370
|
+
state(): MissionState | null;
|
|
371
|
+
/** The pooled per-frame readout to render (do not retain). */
|
|
372
|
+
view(): MissionView | null;
|
|
373
|
+
/** Observe changes (start, tick, signal, fail, abandon, restore). Returns an unsubscribe fn. */
|
|
374
|
+
subscribe(listener: () => void): () => void;
|
|
375
|
+
stats(): MissionStats;
|
|
376
|
+
snapshot(): MissionRuntimeSnapshot;
|
|
377
|
+
restore(next: MissionRuntimeSnapshot): void;
|
|
378
|
+
/** Drop the devtools probe registered by `devtoolsName`. Safe to call twice. */
|
|
379
|
+
dispose(): void;
|
|
380
|
+
}
|
|
381
|
+
/** Default proximity radius (m) for a `reach` / `interact` objective. */
|
|
382
|
+
export declare const DEFAULT_REACH_RADIUS = 2.5;
|
|
383
|
+
/** Default keep-close distance (m) for a `pursue` objective. */
|
|
384
|
+
export declare const DEFAULT_PURSUE_DISTANCE = 3;
|
|
385
|
+
/** A pursuit escapes at this multiple of its keep-close distance when none is declared. */
|
|
386
|
+
export declare const DEFAULT_ESCAPE_MULTIPLE = 3;
|
|
387
|
+
/**
|
|
388
|
+
* Apply a mission's rewards through the same appliers quests use, then roll any named loot tables.
|
|
389
|
+
* Economy, XP, items and unlocks go through {@link applyQuestRewards}; loot is a table id the game's
|
|
390
|
+
* loot registry resolves, so a mission never grows its own reward path.
|
|
391
|
+
*
|
|
392
|
+
* @capability mission-rewards pay mission rewards through the quest appliers and the loot registry
|
|
393
|
+
*/
|
|
394
|
+
export declare function applyMissionRewards(rewards: MissionRewards, appliers: MissionRewardAppliers): {
|
|
395
|
+
reason: string;
|
|
396
|
+
} | null;
|
|
397
|
+
/**
|
|
398
|
+
* Run missions as a state machine. One mission is active at a time; `tick` advances it against the
|
|
399
|
+
* world the caller supplies, moving through objectives on completion, branching on facts, and landing
|
|
400
|
+
* in a named fail state on a fail condition, an expiry or a `minSurvivors` breach. Completion pays
|
|
401
|
+
* rewards through {@link applyMissionRewards} appliers the caller wires, and a mission's `next` chains
|
|
402
|
+
* the follow-up. Escort, chase and defend are compositions of the same objective kinds
|
|
403
|
+
* (`compositions.ts`), never three bespoke systems.
|
|
404
|
+
*
|
|
405
|
+
* Cost per tick is bounded by the active objective's own fail list plus one goal test.
|
|
406
|
+
*
|
|
407
|
+
* @capability mission-runtime missions as a data-driven objective state machine with fail states, timers, branches and rewards
|
|
408
|
+
*/
|
|
409
|
+
export declare function createMissionRuntime(config: MissionRuntimeConfig): MissionRuntime;
|
|
410
|
+
/** A located mission-catalog problem; `path` is a JSON Pointer into the supplied catalog. */
|
|
411
|
+
export interface MissionIssue {
|
|
412
|
+
code: "duplicate-mission" | "duplicate-objective" | "empty-mission" | "missing-start" | "unknown-objective" | "unknown-fail-state" | "unknown-marker" | "missing-actor" | "missing-marker" | "missing-count" | "missing-duration" | "missing-target" | "invalid-number" | "invalid-match" | "unreachable-objective" | "counter-only";
|
|
413
|
+
severity: "error" | "warning";
|
|
414
|
+
message: string;
|
|
415
|
+
path: string;
|
|
416
|
+
missionId?: string;
|
|
417
|
+
objectiveId?: string;
|
|
418
|
+
}
|
|
419
|
+
/** Declarations a mission catalog is validated against. */
|
|
420
|
+
export interface MissionValidationOptions {
|
|
421
|
+
/** Authored marker ids the missions may reference; omitted means marker references are unchecked. */
|
|
422
|
+
markerIds?: Iterable<string>;
|
|
423
|
+
}
|
|
424
|
+
/**
|
|
425
|
+
* Validate a mission catalog without mutation: duplicate ids, unknown branch/next targets, unknown
|
|
426
|
+
* fail states and markers, per-kind required fields, unreachable objectives, and the counter-only
|
|
427
|
+
* rule — a mission that has a completion path made entirely of `kill`/`collect` objectives is an
|
|
428
|
+
* error, because it can be won on a counter alone.
|
|
429
|
+
*
|
|
430
|
+
* Games run this over their mission catalogs (and {@link createMissionRuntime} runs it at
|
|
431
|
+
* construction), so a counter-only mission fails rather than shipping.
|
|
432
|
+
*
|
|
433
|
+
* @capability mission-validation lint mission catalogs, including failing a mission that completes on a counter alone
|
|
434
|
+
*/
|
|
435
|
+
export declare function validateMissionCatalog(missions: readonly MissionDef[], options?: MissionValidationOptions): MissionIssue[];
|