@jgengine/core 0.14.0 → 0.15.0-next.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 +483 -1
- package/dist/ai/difficulty.d.ts +154 -0
- package/dist/ai/difficulty.js +194 -0
- package/dist/ai/driver.d.ts +107 -0
- package/dist/ai/driver.js +175 -0
- package/dist/ai/flock.js +13 -23
- package/dist/ai/laneSelect.js +2 -1
- package/dist/ai/mobBrain.js +2 -1
- package/dist/ai/waveRunner.d.ts +81 -0
- package/dist/ai/waveRunner.js +104 -0
- package/dist/authoring.d.ts +6 -4
- package/dist/authoring.js +6 -4
- package/dist/combat/castRunner.d.ts +13 -1
- package/dist/combat/castRunner.js +5 -1
- package/dist/combat/comboMeter.d.ts +140 -0
- package/dist/combat/comboMeter.js +215 -0
- package/dist/combat/comboPoints.d.ts +11 -0
- package/dist/combat/comboPoints.js +11 -2
- package/dist/combat/damageResolution.d.ts +1 -1
- package/dist/combat/defensiveWindow.d.ts +5 -0
- package/dist/combat/effects.d.ts +24 -0
- package/dist/combat/effects.js +6 -1
- package/dist/combat/projectiles.d.ts +6 -0
- package/dist/combat/projectiles.js +2 -2
- package/dist/combat/regenShield.d.ts +40 -2
- package/dist/combat/regenShield.js +66 -18
- package/dist/combat/resourcePool.d.ts +19 -0
- package/dist/combat/resourcePool.js +20 -2
- package/dist/combat/shotOrigin.d.ts +5 -0
- package/dist/combat/statusApplication.d.ts +1 -1
- package/dist/combat/statusApplication.js +2 -1
- package/dist/combat/statusEffectView.d.ts +56 -0
- package/dist/combat/statusEffectView.js +52 -0
- package/dist/combat.d.ts +4 -2
- package/dist/combat.js +2 -0
- package/dist/devtools/fallbackSeams.d.ts +3 -2
- package/dist/devtools/fallbackSeams.js +1 -1
- package/dist/devtools/textureErrors.d.ts +40 -0
- package/dist/devtools/textureErrors.js +68 -0
- package/dist/economy/shopStock.d.ts +110 -0
- package/dist/economy/shopStock.js +157 -0
- package/dist/economy/wallet.d.ts +6 -0
- package/dist/economy/wallet.js +1 -0
- package/dist/game/achievements.d.ts +80 -0
- package/dist/game/achievements.js +124 -0
- package/dist/game/cameraConfig.d.ts +7 -0
- package/dist/game/codex.d.ts +60 -0
- package/dist/game/codex.js +89 -0
- package/dist/game/credits.d.ts +36 -0
- package/dist/game/credits.js +0 -0
- package/dist/game/defineGame.d.ts +28 -3
- package/dist/game/defineGame.js +5 -0
- package/dist/game/dialogueGraph.d.ts +116 -0
- package/dist/game/dialogueGraph.js +103 -0
- package/dist/game/eventTicker.d.ts +95 -0
- package/dist/game/eventTicker.js +91 -0
- package/dist/game/events.d.ts +24 -5
- package/dist/game/events.js +18 -0
- package/dist/game/gamePhase.d.ts +1 -1
- package/dist/game/gamePhase.js +1 -1
- package/dist/game/leaderboardRank.d.ts +71 -0
- package/dist/game/leaderboardRank.js +76 -0
- package/dist/game/lootTable.d.ts +10 -1
- package/dist/game/lootTable.js +4 -2
- package/dist/game/notifications.d.ts +57 -0
- package/dist/game/notifications.js +107 -0
- package/dist/game/playableGame.d.ts +39 -2
- package/dist/game/quest.d.ts +26 -0
- package/dist/game/quest.js +31 -0
- package/dist/game/runDraft.js +2 -1
- package/dist/game/saveSlots.d.ts +102 -0
- package/dist/game/saveSlots.js +136 -0
- package/dist/game/talentTreeView.d.ts +106 -0
- package/dist/game/talentTreeView.js +114 -0
- package/dist/game/worldItem.js +2 -1
- package/dist/gameplay.d.ts +15 -4
- package/dist/gameplay.js +13 -2
- package/dist/i18n/i18n.d.ts +51 -0
- package/dist/i18n/i18n.js +82 -0
- package/dist/input/axisInput.d.ts +1 -1
- package/dist/input/axisInput.js +18 -2
- package/dist/input/rebindSession.d.ts +141 -0
- package/dist/input/rebindSession.js +235 -0
- package/dist/input/touchControlsMode.d.ts +16 -0
- package/dist/input/touchControlsMode.js +23 -0
- package/dist/input/touchScheme.d.ts +30 -1
- package/dist/input/touchScheme.js +31 -1
- package/dist/interaction/promptRegistry.d.ts +78 -0
- package/dist/interaction/promptRegistry.js +130 -0
- package/dist/inventory/storageTier.js +3 -2
- package/dist/meta/changelog.d.ts +1 -1
- package/dist/meta/changelog.js +1 -1
- package/dist/movement/movementModel.d.ts +26 -3
- package/dist/movement/movementModel.js +121 -15
- package/dist/movement/playerMovement.js +161 -25
- package/dist/physics/drivableVehicle.js +3 -1
- package/dist/physics/kinematicVehicle.d.ts +56 -1
- package/dist/physics/kinematicVehicle.js +99 -10
- package/dist/physics/vehicleObstacles.js +19 -0
- package/dist/random/resolveRng.d.ts +14 -0
- package/dist/random/resolveRng.js +31 -0
- package/dist/render/postProcessing.d.ts +12 -1
- package/dist/runtime/cameraDirector.d.ts +2 -2
- package/dist/runtime/context/combat.js +8 -0
- package/dist/runtime/gameContext.js +6 -1
- package/dist/runtime/gameContextTypes.d.ts +18 -0
- package/dist/runtime/inputSnapshot.d.ts +10 -1
- package/dist/runtime/inputSnapshot.js +13 -1
- package/dist/runtime/runtimeSave.d.ts +3 -3
- package/dist/runtime/runtimeSave.js +11 -2
- package/dist/scene/assetDiagnostics.js +2 -2
- package/dist/scene/autoTarget.js +2 -1
- package/dist/scene/captureCheck.js +3 -2
- package/dist/scene/entityStore.d.ts +4 -1
- package/dist/scene/entityStore.js +3 -0
- package/dist/scene/objectStore.d.ts +10 -0
- package/dist/scene/objectStore.js +29 -6
- package/dist/scene/sceneKinds.d.ts +18 -0
- package/dist/scene/sceneKinds.js +19 -0
- package/dist/scene/sequenceDirector.d.ts +110 -0
- package/dist/scene/sequenceDirector.js +146 -0
- package/dist/session/roles.js +3 -2
- package/dist/settings/settingsModel.d.ts +1 -0
- package/dist/settings/settingsModel.js +1 -0
- package/dist/stats/rollCheck.js +4 -2
- package/dist/time/dayNightCycle.d.ts +114 -0
- package/dist/time/dayNightCycle.js +208 -0
- package/dist/time/timerSet.d.ts +132 -0
- package/dist/time/timerSet.js +243 -0
- package/dist/ui/accessibility.d.ts +51 -0
- package/dist/ui/accessibility.js +83 -0
- package/dist/ui/coachMarks.d.ts +99 -0
- package/dist/ui/coachMarks.js +126 -0
- package/dist/ui/floatingText.d.ts +114 -0
- package/dist/ui/floatingText.js +203 -0
- package/dist/ui/modalStack.d.ts +143 -0
- package/dist/ui/modalStack.js +160 -0
- package/dist/ui/objectiveBanner.d.ts +123 -0
- package/dist/ui/objectiveBanner.js +162 -0
- package/dist/ui/photoMode.d.ts +32 -0
- package/dist/ui/photoMode.js +51 -0
- package/dist/ui/radialMenu.d.ts +47 -0
- package/dist/ui/radialMenu.js +74 -0
- package/dist/ui/screenMarkers.d.ts +128 -0
- package/dist/ui/screenMarkers.js +118 -0
- package/dist/ui.d.ts +8 -0
- package/dist/ui.js +8 -0
- package/dist/vfx/cameraShake.d.ts +97 -0
- package/dist/vfx/cameraShake.js +136 -0
- package/dist/vfx/damageDirection.d.ts +102 -0
- package/dist/vfx/damageDirection.js +188 -0
- package/dist/vfx/particles.d.ts +103 -0
- package/dist/vfx/particles.js +256 -0
- package/dist/vfx/screenEffects.d.ts +149 -0
- package/dist/vfx/screenEffects.js +191 -0
- package/dist/world/authoredObjects.d.ts +18 -0
- package/dist/world/authoredObjects.js +21 -0
- package/dist/world/authoredSpawn.js +19 -0
- package/dist/world/buildingLots.d.ts +54 -11
- package/dist/world/buildingLots.js +116 -30
- package/dist/world/cityBlocks.d.ts +45 -0
- package/dist/world/cityBlocks.js +159 -0
- package/dist/world/cityContent.d.ts +46 -2
- package/dist/world/cityContent.js +160 -2
- package/dist/world/cityGenerator.d.ts +261 -23
- package/dist/world/cityGenerator.js +643 -33
- package/dist/world/cityGeometry.d.ts +20 -0
- package/dist/world/cityGeometry.js +91 -0
- package/dist/world/cityKind.js +1 -44
- package/dist/world/fastTravel.d.ts +64 -0
- package/dist/world/fastTravel.js +108 -0
- package/dist/world/features.d.ts +16 -0
- package/dist/world/features.js +2 -0
- package/dist/world/grounded.d.ts +11 -0
- package/dist/world/grounded.js +12 -0
- package/dist/world/mapAnnotations.d.ts +75 -0
- package/dist/world/mapAnnotations.js +139 -0
- package/dist/world/markers.js +1 -0
- package/dist/world/resourceNode.d.ts +1 -1
- package/dist/world/resourceNode.js +2 -1
- package/dist/world/roads.d.ts +294 -5
- package/dist/world/roads.js +1262 -21
- package/dist/world/sharedAnnotations.d.ts +84 -0
- package/dist/world/sharedAnnotations.js +76 -0
- package/dist/world/spawnOverride.d.ts +37 -0
- package/dist/world/spawnOverride.js +50 -0
- package/dist/world/streetGenerator.d.ts +60 -11
- package/dist/world/streetGenerator.js +1786 -129
- package/dist/world/terrain.d.ts +1 -0
- package/dist/world/terrain.js +2 -0
- package/dist/world/waypoints.d.ts +63 -0
- package/dist/world/waypoints.js +137 -0
- package/dist/world.d.ts +17 -2
- package/dist/world.js +17 -2
- package/package.json +1 -1
- package/skills/ce-handoff/SKILL.md +149 -0
- package/skills/game-design/SKILL.md +2 -0
- package/skills/jgengine/SKILL.md +3 -1
- package/skills/jgengine/api.md +17 -7
- package/skills/jgengine/capabilities.md +12 -0
- package/skills/jgengine/recipes/minimal-game.md +7 -4
- package/skills/jgengine-combat/api.md +40 -4
- package/skills/jgengine-combat/capabilities.md +12 -0
- package/skills/jgengine-combat/reference.md +2 -0
- package/skills/jgengine-gameplay/api.md +212 -11
- package/skills/jgengine-gameplay/capabilities.md +66 -1
- package/skills/jgengine-world/api.md +378 -11
- package/skills/jgengine-world/capabilities.md +123 -2
- package/skills/jgengine-world/reference.md +15 -1
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/** Definition of one achievement. Content-agnostic — the game supplies names, targets, and icons. */
|
|
2
|
+
export interface AchievementDef {
|
|
3
|
+
id: string;
|
|
4
|
+
name: string;
|
|
5
|
+
description?: string;
|
|
6
|
+
/**
|
|
7
|
+
* Counter goal: the achievement unlocks when accumulated progress reaches it.
|
|
8
|
+
* Omit for a boolean achievement unlocked directly with `unlock(id)`.
|
|
9
|
+
*/
|
|
10
|
+
target?: number;
|
|
11
|
+
/** Hide the name/description in UI until unlocked (a spoiler-guarded achievement). */
|
|
12
|
+
secret?: boolean;
|
|
13
|
+
/** Optional score weight (gamerscore-style), summed by {@link AchievementTracker.score}. */
|
|
14
|
+
points?: number;
|
|
15
|
+
category?: string;
|
|
16
|
+
/** Optional icon id / glyph the game renders; the engine never picks art. */
|
|
17
|
+
icon?: string;
|
|
18
|
+
}
|
|
19
|
+
/** A definition plus its live unlock/progress state — what UI renders. */
|
|
20
|
+
export interface AchievementView extends AchievementDef {
|
|
21
|
+
unlocked: boolean;
|
|
22
|
+
/** Unlock time from the injected clock, or null while locked. */
|
|
23
|
+
unlockedAt: number | null;
|
|
24
|
+
/** Current counter value (0 for untouched or boolean achievements). */
|
|
25
|
+
progress: number;
|
|
26
|
+
/** `progress / target` in `[0, 1]`; 1 when unlocked or when there is no target. */
|
|
27
|
+
fraction: number;
|
|
28
|
+
}
|
|
29
|
+
/** Emitted the instant an achievement unlocks — wire to a toast, feed, or sound. */
|
|
30
|
+
export interface AchievementUnlock {
|
|
31
|
+
id: string;
|
|
32
|
+
def: AchievementDef;
|
|
33
|
+
at: number;
|
|
34
|
+
}
|
|
35
|
+
/** Whole serializable state of a tracker — drop into a save blob. */
|
|
36
|
+
export interface AchievementSnapshot {
|
|
37
|
+
/** Achievement id → unlock timestamp. */
|
|
38
|
+
unlocked: Record<string, number>;
|
|
39
|
+
/** Achievement id → counter progress. */
|
|
40
|
+
counters: Record<string, number>;
|
|
41
|
+
}
|
|
42
|
+
/** Live achievement state over a fixed definition set — drives progress, unlocks, score, and a UI view list. */
|
|
43
|
+
export interface AchievementTracker {
|
|
44
|
+
/** Add `amount` (default 1) to a counter achievement; unlocks on reaching `target`. Returns the unlock if it just crossed, else null. */
|
|
45
|
+
progress(id: string, amount?: number): AchievementUnlock | null;
|
|
46
|
+
/** Set a counter achievement's absolute value; unlocks on reaching `target`. Returns the unlock if it just crossed, else null. */
|
|
47
|
+
setProgress(id: string, value: number): AchievementUnlock | null;
|
|
48
|
+
/** Unlock directly (boolean or counter). Returns the unlock, or null if unknown or already unlocked. */
|
|
49
|
+
unlock(id: string): AchievementUnlock | null;
|
|
50
|
+
isUnlocked(id: string): boolean;
|
|
51
|
+
get(id: string): AchievementView | null;
|
|
52
|
+
/** All achievements with live state, in definition order. Stable identity between changes (safe for `useSyncExternalStore`). */
|
|
53
|
+
list(): readonly AchievementView[];
|
|
54
|
+
unlocked(): readonly AchievementView[];
|
|
55
|
+
/** Total `points` across unlocked achievements. */
|
|
56
|
+
score(): number;
|
|
57
|
+
/** Fraction of achievements unlocked, `[0, 1]`. */
|
|
58
|
+
completion(): number;
|
|
59
|
+
subscribe(listener: () => void): () => void;
|
|
60
|
+
snapshot(): AchievementSnapshot;
|
|
61
|
+
restore(snapshot: AchievementSnapshot): void;
|
|
62
|
+
}
|
|
63
|
+
/** Options for {@link createAchievementTracker}. */
|
|
64
|
+
export interface AchievementTrackerOptions {
|
|
65
|
+
defs: readonly AchievementDef[];
|
|
66
|
+
/** Injected clock (ms). Default `Date.now`. */
|
|
67
|
+
now?: () => number;
|
|
68
|
+
/** Fires whenever an achievement unlocks — the seam for toasts, kill-feed lines, sounds, or telemetry. */
|
|
69
|
+
onUnlock?: (unlock: AchievementUnlock) => void;
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Tracks achievement/trophy unlocks over caller-driven events — counter goals
|
|
73
|
+
* (`progress`/`setProgress`) and boolean flags (`unlock`) — with score,
|
|
74
|
+
* completion, an `onUnlock` seam, and serializable `snapshot`/`restore`. State
|
|
75
|
+
* is plain data; the view list keeps a stable identity between changes so React
|
|
76
|
+
* can read it through `useSyncExternalStore` without re-projecting every frame.
|
|
77
|
+
*
|
|
78
|
+
* @capability achievements track achievement/trophy unlocks over counter goals and boolean flags, with score, completion, an onUnlock seam, and serializable snapshot/restore
|
|
79
|
+
*/
|
|
80
|
+
export declare function createAchievementTracker(options: AchievementTrackerOptions): AchievementTracker;
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tracks achievement/trophy unlocks over caller-driven events — counter goals
|
|
3
|
+
* (`progress`/`setProgress`) and boolean flags (`unlock`) — with score,
|
|
4
|
+
* completion, an `onUnlock` seam, and serializable `snapshot`/`restore`. State
|
|
5
|
+
* is plain data; the view list keeps a stable identity between changes so React
|
|
6
|
+
* can read it through `useSyncExternalStore` without re-projecting every frame.
|
|
7
|
+
*
|
|
8
|
+
* @capability achievements track achievement/trophy unlocks over counter goals and boolean flags, with score, completion, an onUnlock seam, and serializable snapshot/restore
|
|
9
|
+
*/
|
|
10
|
+
export function createAchievementTracker(options) {
|
|
11
|
+
const now = options.now ?? Date.now;
|
|
12
|
+
const order = [];
|
|
13
|
+
const defs = new Map();
|
|
14
|
+
for (const def of options.defs) {
|
|
15
|
+
if (defs.has(def.id))
|
|
16
|
+
continue;
|
|
17
|
+
defs.set(def.id, def);
|
|
18
|
+
order.push(def.id);
|
|
19
|
+
}
|
|
20
|
+
const unlockedAt = new Map();
|
|
21
|
+
const counters = new Map();
|
|
22
|
+
const listeners = new Set();
|
|
23
|
+
let cache = null;
|
|
24
|
+
function notify() {
|
|
25
|
+
cache = null;
|
|
26
|
+
for (const listener of listeners)
|
|
27
|
+
listener();
|
|
28
|
+
}
|
|
29
|
+
function viewOf(id) {
|
|
30
|
+
const def = defs.get(id);
|
|
31
|
+
const at = unlockedAt.get(id) ?? null;
|
|
32
|
+
const progress = counters.get(id) ?? 0;
|
|
33
|
+
const fraction = at !== null ? 1 : def.target !== undefined && def.target > 0 ? Math.min(1, progress / def.target) : 0;
|
|
34
|
+
return { ...def, unlocked: at !== null, unlockedAt: at, progress, fraction };
|
|
35
|
+
}
|
|
36
|
+
function doUnlock(id) {
|
|
37
|
+
const at = now();
|
|
38
|
+
unlockedAt.set(id, at);
|
|
39
|
+
const def = defs.get(id);
|
|
40
|
+
if (def.target !== undefined)
|
|
41
|
+
counters.set(id, def.target);
|
|
42
|
+
const unlock = { id, def, at };
|
|
43
|
+
options.onUnlock?.(unlock);
|
|
44
|
+
return unlock;
|
|
45
|
+
}
|
|
46
|
+
function applyCounter(id, value) {
|
|
47
|
+
const def = defs.get(id);
|
|
48
|
+
if (def === undefined || def.target === undefined)
|
|
49
|
+
return null;
|
|
50
|
+
if (unlockedAt.has(id))
|
|
51
|
+
return null;
|
|
52
|
+
const clamped = Math.max(0, Math.min(def.target, value));
|
|
53
|
+
counters.set(id, clamped);
|
|
54
|
+
if (clamped >= def.target) {
|
|
55
|
+
const unlock = doUnlock(id);
|
|
56
|
+
notify();
|
|
57
|
+
return unlock;
|
|
58
|
+
}
|
|
59
|
+
notify();
|
|
60
|
+
return null;
|
|
61
|
+
}
|
|
62
|
+
const tracker = {
|
|
63
|
+
progress(id, amount = 1) {
|
|
64
|
+
return applyCounter(id, (counters.get(id) ?? 0) + amount);
|
|
65
|
+
},
|
|
66
|
+
setProgress(id, value) {
|
|
67
|
+
return applyCounter(id, value);
|
|
68
|
+
},
|
|
69
|
+
unlock(id) {
|
|
70
|
+
if (!defs.has(id) || unlockedAt.has(id))
|
|
71
|
+
return null;
|
|
72
|
+
const unlock = doUnlock(id);
|
|
73
|
+
notify();
|
|
74
|
+
return unlock;
|
|
75
|
+
},
|
|
76
|
+
isUnlocked(id) {
|
|
77
|
+
return unlockedAt.has(id);
|
|
78
|
+
},
|
|
79
|
+
get(id) {
|
|
80
|
+
return defs.has(id) ? viewOf(id) : null;
|
|
81
|
+
},
|
|
82
|
+
list() {
|
|
83
|
+
if (cache === null)
|
|
84
|
+
cache = order.map(viewOf);
|
|
85
|
+
return cache;
|
|
86
|
+
},
|
|
87
|
+
unlocked() {
|
|
88
|
+
return tracker.list().filter((view) => view.unlocked);
|
|
89
|
+
},
|
|
90
|
+
score() {
|
|
91
|
+
let total = 0;
|
|
92
|
+
for (const id of unlockedAt.keys())
|
|
93
|
+
total += defs.get(id)?.points ?? 0;
|
|
94
|
+
return total;
|
|
95
|
+
},
|
|
96
|
+
completion() {
|
|
97
|
+
return order.length === 0 ? 0 : unlockedAt.size / order.length;
|
|
98
|
+
},
|
|
99
|
+
subscribe(listener) {
|
|
100
|
+
listeners.add(listener);
|
|
101
|
+
return () => listeners.delete(listener);
|
|
102
|
+
},
|
|
103
|
+
snapshot() {
|
|
104
|
+
return {
|
|
105
|
+
unlocked: Object.fromEntries(unlockedAt),
|
|
106
|
+
counters: Object.fromEntries(counters),
|
|
107
|
+
};
|
|
108
|
+
},
|
|
109
|
+
restore(snapshot) {
|
|
110
|
+
unlockedAt.clear();
|
|
111
|
+
counters.clear();
|
|
112
|
+
for (const [id, at] of Object.entries(snapshot.counters)) {
|
|
113
|
+
if (defs.has(id))
|
|
114
|
+
counters.set(id, at);
|
|
115
|
+
}
|
|
116
|
+
for (const [id, at] of Object.entries(snapshot.unlocked)) {
|
|
117
|
+
if (defs.has(id))
|
|
118
|
+
unlockedAt.set(id, at);
|
|
119
|
+
}
|
|
120
|
+
notify();
|
|
121
|
+
},
|
|
122
|
+
};
|
|
123
|
+
return tracker;
|
|
124
|
+
}
|
|
@@ -198,6 +198,13 @@ export interface ChaseCameraConfig {
|
|
|
198
198
|
minSpeed?: number;
|
|
199
199
|
response?: number;
|
|
200
200
|
};
|
|
201
|
+
/**
|
|
202
|
+
* Exponential response (`1-exp(-response*dt)`) the chase yaw follows the target's facing with
|
|
203
|
+
* (#1370). The default (5) arcs the boom smoothly behind a body whose facing flips from a strafe
|
|
204
|
+
* or direction change instead of teleporting it to the far side; `Infinity` restores the legacy
|
|
205
|
+
* rigid follow (yaw exactly equals body facing every frame).
|
|
206
|
+
*/
|
|
207
|
+
yawResponse?: number;
|
|
201
208
|
/** Which view to mount. Default "chase". */
|
|
202
209
|
view?: ChaseView;
|
|
203
210
|
/** Local offset for cockpit/hood/rear seats (relative to the vehicle, +z forward). */
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/** A codex/bestiary/lorebook entry the game defines. Discovery state is tracked separately. */
|
|
2
|
+
export interface CodexEntryDef<TMeta = unknown> {
|
|
3
|
+
id: string;
|
|
4
|
+
name: string;
|
|
5
|
+
category?: string;
|
|
6
|
+
description?: string;
|
|
7
|
+
/** Longer lore for a detail pane. */
|
|
8
|
+
lore?: string;
|
|
9
|
+
/** Icon/image id or glyph the game renders; the engine never picks art. */
|
|
10
|
+
icon?: string;
|
|
11
|
+
/** Hide name/description/lore until discovered (a spoiler-guarded entry). */
|
|
12
|
+
secret?: boolean;
|
|
13
|
+
meta?: TMeta;
|
|
14
|
+
}
|
|
15
|
+
/** A definition plus its discovery state — what UI renders. */
|
|
16
|
+
export interface CodexEntryView<TMeta = unknown> extends CodexEntryDef<TMeta> {
|
|
17
|
+
discovered: boolean;
|
|
18
|
+
/** Discovery time from the injected clock, or null. */
|
|
19
|
+
discoveredAt: number | null;
|
|
20
|
+
}
|
|
21
|
+
/** Serializable discovery state — a save blob. */
|
|
22
|
+
export interface CodexSnapshot {
|
|
23
|
+
/** Entry id → discovery timestamp. */
|
|
24
|
+
discovered: Record<string, number>;
|
|
25
|
+
}
|
|
26
|
+
/** A codex/bestiary of defined entries with per-player discovery tracking. */
|
|
27
|
+
export interface Codex<TMeta = unknown> {
|
|
28
|
+
/** Mark an entry discovered; returns the newly-discovered view, or null if unknown or already discovered. */
|
|
29
|
+
discover(id: string): CodexEntryView<TMeta> | null;
|
|
30
|
+
isDiscovered(id: string): boolean;
|
|
31
|
+
get(id: string): CodexEntryView<TMeta> | null;
|
|
32
|
+
/** All entries (optionally filtered to a category) with discovery state, in definition order. Stable identity between changes. */
|
|
33
|
+
list(category?: string): readonly CodexEntryView<TMeta>[];
|
|
34
|
+
categories(): readonly string[];
|
|
35
|
+
discoveredCount(): number;
|
|
36
|
+
total(): number;
|
|
37
|
+
/** Fraction discovered, `[0, 1]`. */
|
|
38
|
+
completion(): number;
|
|
39
|
+
subscribe(listener: () => void): () => void;
|
|
40
|
+
snapshot(): CodexSnapshot;
|
|
41
|
+
restore(snapshot: CodexSnapshot): void;
|
|
42
|
+
}
|
|
43
|
+
/** Options for {@link createCodex}. */
|
|
44
|
+
export interface CodexOptions<TMeta = unknown> {
|
|
45
|
+
entries: readonly CodexEntryDef<TMeta>[];
|
|
46
|
+
/** Injected clock (ms). Default `Date.now`. */
|
|
47
|
+
now?: () => number;
|
|
48
|
+
/** Fires when an entry is discovered for the first time — wire to a toast/notification. */
|
|
49
|
+
onDiscover?: (entry: CodexEntryView<TMeta>) => void;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* A codex / bestiary / lorebook: a fixed set of defined entries plus per-player
|
|
53
|
+
* discovery tracking, with categories, secret masking, completion, an
|
|
54
|
+
* `onDiscover` seam, and serializable `snapshot`/`restore`. The view `list()`
|
|
55
|
+
* keeps a stable identity between changes so React reads it through
|
|
56
|
+
* `useSyncExternalStore` without re-projecting each frame.
|
|
57
|
+
*
|
|
58
|
+
* @capability codex codex/bestiary/lorebook of defined entries with discovery tracking, categories, secret masking, completion, an onDiscover seam, and serializable state
|
|
59
|
+
*/
|
|
60
|
+
export declare function createCodex<TMeta = unknown>(options: CodexOptions<TMeta>): Codex<TMeta>;
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A codex / bestiary / lorebook: a fixed set of defined entries plus per-player
|
|
3
|
+
* discovery tracking, with categories, secret masking, completion, an
|
|
4
|
+
* `onDiscover` seam, and serializable `snapshot`/`restore`. The view `list()`
|
|
5
|
+
* keeps a stable identity between changes so React reads it through
|
|
6
|
+
* `useSyncExternalStore` without re-projecting each frame.
|
|
7
|
+
*
|
|
8
|
+
* @capability codex codex/bestiary/lorebook of defined entries with discovery tracking, categories, secret masking, completion, an onDiscover seam, and serializable state
|
|
9
|
+
*/
|
|
10
|
+
export function createCodex(options) {
|
|
11
|
+
const now = options.now ?? Date.now;
|
|
12
|
+
const order = [];
|
|
13
|
+
const defs = new Map();
|
|
14
|
+
for (const def of options.entries) {
|
|
15
|
+
if (defs.has(def.id))
|
|
16
|
+
continue;
|
|
17
|
+
defs.set(def.id, def);
|
|
18
|
+
order.push(def.id);
|
|
19
|
+
}
|
|
20
|
+
const discoveredAt = new Map();
|
|
21
|
+
const listeners = new Set();
|
|
22
|
+
let cache = null;
|
|
23
|
+
function notify() {
|
|
24
|
+
cache = null;
|
|
25
|
+
for (const listener of listeners)
|
|
26
|
+
listener();
|
|
27
|
+
}
|
|
28
|
+
function viewOf(id) {
|
|
29
|
+
const def = defs.get(id);
|
|
30
|
+
const at = discoveredAt.get(id) ?? null;
|
|
31
|
+
return { ...def, discovered: at !== null, discoveredAt: at };
|
|
32
|
+
}
|
|
33
|
+
const codex = {
|
|
34
|
+
discover(id) {
|
|
35
|
+
if (!defs.has(id) || discoveredAt.has(id))
|
|
36
|
+
return null;
|
|
37
|
+
discoveredAt.set(id, now());
|
|
38
|
+
const view = viewOf(id);
|
|
39
|
+
options.onDiscover?.(view);
|
|
40
|
+
notify();
|
|
41
|
+
return view;
|
|
42
|
+
},
|
|
43
|
+
isDiscovered(id) {
|
|
44
|
+
return discoveredAt.has(id);
|
|
45
|
+
},
|
|
46
|
+
get(id) {
|
|
47
|
+
return defs.has(id) ? viewOf(id) : null;
|
|
48
|
+
},
|
|
49
|
+
list(category) {
|
|
50
|
+
if (cache === null)
|
|
51
|
+
cache = order.map(viewOf);
|
|
52
|
+
return category === undefined ? cache : cache.filter((view) => view.category === category);
|
|
53
|
+
},
|
|
54
|
+
categories() {
|
|
55
|
+
const seen = [];
|
|
56
|
+
for (const id of order) {
|
|
57
|
+
const category = defs.get(id).category;
|
|
58
|
+
if (category !== undefined && !seen.includes(category))
|
|
59
|
+
seen.push(category);
|
|
60
|
+
}
|
|
61
|
+
return seen;
|
|
62
|
+
},
|
|
63
|
+
discoveredCount() {
|
|
64
|
+
return discoveredAt.size;
|
|
65
|
+
},
|
|
66
|
+
total() {
|
|
67
|
+
return order.length;
|
|
68
|
+
},
|
|
69
|
+
completion() {
|
|
70
|
+
return order.length === 0 ? 0 : discoveredAt.size / order.length;
|
|
71
|
+
},
|
|
72
|
+
subscribe(listener) {
|
|
73
|
+
listeners.add(listener);
|
|
74
|
+
return () => listeners.delete(listener);
|
|
75
|
+
},
|
|
76
|
+
snapshot() {
|
|
77
|
+
return { discovered: Object.fromEntries(discoveredAt) };
|
|
78
|
+
},
|
|
79
|
+
restore(snapshot) {
|
|
80
|
+
discoveredAt.clear();
|
|
81
|
+
for (const [id, at] of Object.entries(snapshot.discovered)) {
|
|
82
|
+
if (defs.has(id))
|
|
83
|
+
discoveredAt.set(id, at);
|
|
84
|
+
}
|
|
85
|
+
notify();
|
|
86
|
+
},
|
|
87
|
+
};
|
|
88
|
+
return codex;
|
|
89
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/** One credited line — a person, a studio, an asset pack, a tool. */
|
|
2
|
+
export interface CreditsEntry {
|
|
3
|
+
/** Who or what is credited. */
|
|
4
|
+
label: string;
|
|
5
|
+
/** Free-string qualifier shown beside the label — a role, a license, a pack title. */
|
|
6
|
+
detail?: string;
|
|
7
|
+
/** Where the work came from. Never fetched; the view decides whether to link it. */
|
|
8
|
+
href?: string;
|
|
9
|
+
}
|
|
10
|
+
/** A titled group of entries — "Design", "Music", "3D Assets". */
|
|
11
|
+
export interface CreditsSection {
|
|
12
|
+
heading: string;
|
|
13
|
+
entries: readonly CreditsEntry[];
|
|
14
|
+
}
|
|
15
|
+
/** Everything a credits screen shows. `notice` is the closing line (a license summary, a thank-you). */
|
|
16
|
+
export interface CreditsDocument {
|
|
17
|
+
title?: string;
|
|
18
|
+
sections: readonly CreditsSection[];
|
|
19
|
+
notice?: string;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Merges credit documents into one, concatenating same-heading sections in first-seen order and
|
|
23
|
+
* dropping exact duplicate entries. Use it to fold generated credits (asset packs, dependencies)
|
|
24
|
+
* into the game's hand-authored ones without curating the overlap by hand.
|
|
25
|
+
*
|
|
26
|
+
* @capability merge-credits fold generated and hand-authored credit documents into one, deduped by entry
|
|
27
|
+
*/
|
|
28
|
+
export declare function mergeCredits(...documents: readonly (CreditsDocument | null | undefined)[]): CreditsDocument;
|
|
29
|
+
/**
|
|
30
|
+
* Groups entries into sections by a caller-supplied key — the shape most generated credits arrive
|
|
31
|
+
* in (a flat list of things used, grouped by license, provider, or role). Section order follows
|
|
32
|
+
* first appearance, so a stable input gives a stable screen.
|
|
33
|
+
*
|
|
34
|
+
* @capability group-credits turn a flat list of credited things into ordered credit sections
|
|
35
|
+
*/
|
|
36
|
+
export declare function groupCredits<T>(items: readonly T[], heading: (item: T) => string, entry: (item: T) => CreditsEntry): CreditsSection[];
|
|
Binary file
|
|
@@ -15,7 +15,7 @@ import type { TimeConfig } from "../time/simClock.js";
|
|
|
15
15
|
import type { WorldFeature } from "../world/features.js";
|
|
16
16
|
/** Tunes offline whole-world save (`defineGameDefinition({ persist })`). Offline games already autosave to `localStorage` by default — pass this only to tune it (or `persist: false` to opt out). Defaults: continuous `autosave` to `localStorage`, one slot, no version. */
|
|
17
17
|
export interface PersistConfig {
|
|
18
|
-
/** `"autosave"` (default) writes on a
|
|
18
|
+
/** `"autosave"` (default) writes on a trailing timer while the world changes — at most once per `autosaveMs`, so a never-idle world (AI, physics, day/night) still persists; `"manual"` writes only on `ctx.game.save.checkpoint()` (save points / quest triggers). */
|
|
19
19
|
mode?: RuntimeSaveMode;
|
|
20
20
|
/** `"local"` (default) persists to `localStorage`; `"memory"` keeps saves in-session only (tests, "no persistence" mode). */
|
|
21
21
|
storage?: "local" | "memory";
|
|
@@ -140,6 +140,20 @@ export interface LifecycleConfig<TState = unknown> {
|
|
|
140
140
|
restart?: string;
|
|
141
141
|
};
|
|
142
142
|
}
|
|
143
|
+
/**
|
|
144
|
+
* How a game declares its run-phase story to {@link defineGameDefinition}. Every game states this
|
|
145
|
+
* explicitly so the shell never has to guess — a silent game used to default to `"playing"`, which
|
|
146
|
+
* painted the touch dock over title/menu/results screens (#1337, Vice Isle #1329).
|
|
147
|
+
*
|
|
148
|
+
* - A {@link LifecycleConfig} — the game moves through menu/playing/paused/ended run states; the
|
|
149
|
+
* runtime owns the command glue and phase sync.
|
|
150
|
+
* - `"always-live"` — an explicit, truthful declaration that the game has **no** menu/pause/end
|
|
151
|
+
* screens and runs live from boot. Runtime behaviour is identical to declaring no lifecycle at all
|
|
152
|
+
* (no phase sync, no start/restart commands), but the intent is now *stated*, not implied by
|
|
153
|
+
* silence. Games that instead drive phases by hand call {@link setGamePhase} directly and leave
|
|
154
|
+
* this unset.
|
|
155
|
+
*/
|
|
156
|
+
export type GameLifecycle<TState = unknown> = LifecycleConfig<TState> | "always-live";
|
|
143
157
|
/** Fully-resolved game description produced by {@link defineGameDefinition} — assets, scene, and opted-in subsystems. */
|
|
144
158
|
export interface GameDefinition<TAssetRef extends ModelAssetRef = ModelAssetRef, TMultiplayer = unknown> {
|
|
145
159
|
name: string;
|
|
@@ -177,7 +191,12 @@ export interface GameDefinition<TAssetRef extends ModelAssetRef = ModelAssetRef,
|
|
|
177
191
|
persist?: boolean | PersistConfig;
|
|
178
192
|
ui?: unknown;
|
|
179
193
|
loop?: GameLoop<GameContext>;
|
|
180
|
-
/**
|
|
194
|
+
/**
|
|
195
|
+
* Resolved run lifecycle — see {@link LifecycleConfig}. The config boundary also accepts the
|
|
196
|
+
* `"always-live"` sentinel ({@link GameLifecycle}); {@link defineGameDefinition} resolves that to
|
|
197
|
+
* `undefined` here, so a resolved definition only ever carries a real {@link LifecycleConfig} or
|
|
198
|
+
* nothing.
|
|
199
|
+
*/
|
|
181
200
|
lifecycle?: LifecycleConfig;
|
|
182
201
|
/**
|
|
183
202
|
* Host-side per-viewer replication policy — private-state and area-of-interest projection over the
|
|
@@ -188,8 +207,14 @@ export interface GameDefinition<TAssetRef extends ModelAssetRef = ModelAssetRef,
|
|
|
188
207
|
replication?: ReplicationPolicy;
|
|
189
208
|
}
|
|
190
209
|
/** Input to {@link defineGameDefinition} — a `GameDefinition` with `scene` derived and `assets` optional. */
|
|
191
|
-
export type GameDefinitionConfig<TAssetRef extends ModelAssetRef = ModelAssetRef, TMultiplayer = unknown> = Omit<GameDefinition<TAssetRef, TMultiplayer>, "scene" | "assets"> & {
|
|
210
|
+
export type GameDefinitionConfig<TAssetRef extends ModelAssetRef = ModelAssetRef, TMultiplayer = unknown> = Omit<GameDefinition<TAssetRef, TMultiplayer>, "scene" | "assets" | "lifecycle"> & {
|
|
192
211
|
assets?: AssetCatalog<TAssetRef>;
|
|
212
|
+
/**
|
|
213
|
+
* The game's run-phase story — a {@link LifecycleConfig} or the `"always-live"` sentinel. Every
|
|
214
|
+
* game must state one (or drive phases by hand via {@link setGamePhase}); `check-game-shape`
|
|
215
|
+
* enforces it. See {@link GameLifecycle}.
|
|
216
|
+
*/
|
|
217
|
+
lifecycle?: GameLifecycle;
|
|
193
218
|
};
|
|
194
219
|
/**
|
|
195
220
|
* Host-level constructor for a bare `GameDefinition`: fills in `scene` and default `assets`, validates
|
package/dist/game/defineGame.js
CHANGED
|
@@ -43,11 +43,16 @@ export function defineGameDefinition(config) {
|
|
|
43
43
|
// A place world carries the laws of that place: its physics resolves over the game-level default,
|
|
44
44
|
// so every consumer of definition.physics (movement, combat, shell) sees the active world's laws.
|
|
45
45
|
const physics = resolveWorldPhysics(config.world, config.physics);
|
|
46
|
+
// `"always-live"` is an explicit "no lifecycle sync" declaration — resolve the sentinel to
|
|
47
|
+
// `undefined` so every downstream consumer only ever sees a real LifecycleConfig or nothing,
|
|
48
|
+
// exactly as before the sentinel existed. The statement was for the gate, not the runtime.
|
|
49
|
+
const lifecycle = config.lifecycle === "always-live" ? undefined : config.lifecycle;
|
|
46
50
|
return {
|
|
47
51
|
...config,
|
|
48
52
|
...(physics === undefined ? {} : { physics }),
|
|
49
53
|
features,
|
|
50
54
|
loop,
|
|
55
|
+
lifecycle,
|
|
51
56
|
scene: createEntityStore(),
|
|
52
57
|
assets: config.assets ?? createAssetCatalog(),
|
|
53
58
|
};
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* One selectable response on a conversation node — the text a player clicks and the
|
|
3
|
+
* node it advances to. `kind` is a free style tag the presenter interprets; the model
|
|
4
|
+
* never reads it (no genre baked in).
|
|
5
|
+
*/
|
|
6
|
+
export interface DialogueGraphChoice {
|
|
7
|
+
/** Player-facing choice text. */
|
|
8
|
+
text: string;
|
|
9
|
+
/** Id of the node this choice advances to. Omitted / `null` ends the conversation. */
|
|
10
|
+
to?: string | null;
|
|
11
|
+
/** Free-string style/category tag the game styles on (never interpreted by the model). */
|
|
12
|
+
kind?: string;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* One conversation node: who is speaking, the line they say, and the branches out of it.
|
|
16
|
+
* `speaker`/`speakerKind`/`portrait` are opaque display data — the model never interprets them.
|
|
17
|
+
*/
|
|
18
|
+
export interface DialogueGraphNode {
|
|
19
|
+
/** Stable node id — choices point at it via {@link DialogueGraphChoice.to}. */
|
|
20
|
+
id: string;
|
|
21
|
+
/** Free-string speaker name shown in the view. Omitted → an unattributed line. */
|
|
22
|
+
speaker?: string;
|
|
23
|
+
/** Free-string speaker style tag (the game maps it to a portrait frame / name color). */
|
|
24
|
+
speakerKind?: string;
|
|
25
|
+
/** Opaque portrait key or URL the view renders in its portrait slot. */
|
|
26
|
+
portrait?: string;
|
|
27
|
+
/** The line this node speaks. */
|
|
28
|
+
text: string;
|
|
29
|
+
/** Branching responses. Empty / omitted → a terminal node the player can close. */
|
|
30
|
+
choices?: readonly DialogueGraphChoice[];
|
|
31
|
+
}
|
|
32
|
+
/** A serializable branching conversation: a start node id and the nodes it can reach. */
|
|
33
|
+
export interface DialogueGraph {
|
|
34
|
+
/** Id of the node the conversation opens on. */
|
|
35
|
+
start: string;
|
|
36
|
+
/** Every node in the conversation. */
|
|
37
|
+
nodes: readonly DialogueGraphNode[];
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* The render-ready snapshot of a conversation at one node — everything a view needs to
|
|
41
|
+
* draw speaker, line, and choice buttons, with no traversal logic in the component.
|
|
42
|
+
*/
|
|
43
|
+
export interface DialogueGraphView {
|
|
44
|
+
/** Current node id. */
|
|
45
|
+
nodeId: string;
|
|
46
|
+
/** Speaker name to display, or `undefined` for an unattributed line. */
|
|
47
|
+
speaker?: string;
|
|
48
|
+
/** Speaker style tag the game skins on. */
|
|
49
|
+
speakerKind?: string;
|
|
50
|
+
/** Portrait key/URL for the portrait slot, or `undefined` when none. */
|
|
51
|
+
portrait?: string;
|
|
52
|
+
/** The current line text. */
|
|
53
|
+
text: string;
|
|
54
|
+
/** Branching responses at this node (empty at a terminal node). */
|
|
55
|
+
choices: readonly DialogueGraphChoice[];
|
|
56
|
+
/** True when this node has no onward choices — the conversation can be closed. */
|
|
57
|
+
done: boolean;
|
|
58
|
+
}
|
|
59
|
+
/** Serializable run state — the current node id and the ids already visited. */
|
|
60
|
+
export interface DialogueGraphSnapshot {
|
|
61
|
+
/** Node the run is currently sitting on. */
|
|
62
|
+
nodeId: string;
|
|
63
|
+
/** Node ids visited so far, in order (a start node is the first). */
|
|
64
|
+
visited: readonly string[];
|
|
65
|
+
}
|
|
66
|
+
/** Options for {@link createDialogueRun}. */
|
|
67
|
+
export interface DialogueRunOptions {
|
|
68
|
+
/** Node id to open on. Default: the graph's `start`. */
|
|
69
|
+
startAt?: string;
|
|
70
|
+
/** Visited node ids to seed (e.g. restored from a save). */
|
|
71
|
+
visited?: Iterable<string>;
|
|
72
|
+
}
|
|
73
|
+
/** An observable walk through a {@link DialogueGraph}: current view, choose to advance, serialize. */
|
|
74
|
+
export interface DialogueRun {
|
|
75
|
+
/** The graph being walked. */
|
|
76
|
+
readonly graph: DialogueGraph;
|
|
77
|
+
/** Render-ready view at the current node, or `null` if the current id is unknown. */
|
|
78
|
+
current(): DialogueGraphView | null;
|
|
79
|
+
/** The current node's id. */
|
|
80
|
+
currentId(): string;
|
|
81
|
+
/** Advance via the choice at `index` on the current node; returns the new view (or `null`). */
|
|
82
|
+
choose(index: number): DialogueGraphView | null;
|
|
83
|
+
/** Jump straight to a node id (bypassing choices); returns its view (or `null`). */
|
|
84
|
+
goTo(nodeId: string): DialogueGraphView | null;
|
|
85
|
+
/** Re-open on the start node, clearing visited history. */
|
|
86
|
+
reset(): DialogueGraphView | null;
|
|
87
|
+
/** Whether the current node is terminal (no onward choices). */
|
|
88
|
+
isDone(): boolean;
|
|
89
|
+
/** Whether a node id has been visited this run. */
|
|
90
|
+
hasVisited(nodeId: string): boolean;
|
|
91
|
+
/** Observe advance / jump / reset. Returns an unsubscribe fn. */
|
|
92
|
+
subscribe(listener: () => void): () => void;
|
|
93
|
+
/** Serializable run state for a save. */
|
|
94
|
+
snapshot(): DialogueGraphSnapshot;
|
|
95
|
+
/** Restore from a {@link DialogueGraphSnapshot}. */
|
|
96
|
+
restore(snapshot: DialogueGraphSnapshot): void;
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Project a {@link DialogueGraph} node id to its render-ready {@link DialogueGraphView} —
|
|
100
|
+
* the pure "current view" selector a stateless renderer reads (speaker, line, choices,
|
|
101
|
+
* done). Returns `null` when the id is not in the graph. No traversal or mutation.
|
|
102
|
+
*
|
|
103
|
+
* @capability dialogue-graph-view select a conversation node's render-ready view (speaker, line, branching choices) from a serializable dialogue graph
|
|
104
|
+
*/
|
|
105
|
+
export declare function selectDialogueView(graph: DialogueGraph, nodeId: string): DialogueGraphView | null;
|
|
106
|
+
/**
|
|
107
|
+
* Walk a branching {@link DialogueGraph}: hold the current node, expose its render-ready
|
|
108
|
+
* view, and advance by choosing one of the current node's responses (each choice names the
|
|
109
|
+
* node it leads to; a choice with no `to` ends the conversation). Purely a serializable
|
|
110
|
+
* model — a React host renders `current()` and calls `choose(index)` — so no game
|
|
111
|
+
* re-implements node lookup, choice-to-node traversal, or "am I at the end" bookkeeping.
|
|
112
|
+
* `snapshot`/`restore` round-trip the run through a save.
|
|
113
|
+
*
|
|
114
|
+
* @capability dialogue-run walk a serializable branching dialogue graph — current node view, choose-to-advance traversal, visited history, snapshot/restore
|
|
115
|
+
*/
|
|
116
|
+
export declare function createDialogueRun(graph: DialogueGraph, options?: DialogueRunOptions): DialogueRun;
|