import type { NavPoint } from "../nav/navGrid.js"; /** * Lifecycle status of one phase in an encounter sequence: waiting to run, currently * running, or finished. Groups and leaves share the same three states. */ export type PhaseStatus = "pending" | "active" | "complete"; /** * Reference to a registered completion predicate: a `kind` naming the evaluator plus * opaque `params` the evaluator reads. The sequence core never interprets `params`; the * predicate registered under `kind` does. */ export interface PhaseCompletionRef { kind: string; params?: Readonly>; } /** * Reference to a registered spawn provider invoked when a phase is entered: a `kind` * naming the provider plus opaque `params`. Spawning is one optional node adapter — a * phase without `spawn` simply emits no spawn requests. */ export interface PhaseSpawnRef { kind: string; params?: Readonly>; } /** * One node in an encounter sequence tree. `data` is caller-owned and opaque to the core. * A node with `children` is a group whose children run in order; a node without is a leaf. * `completion` gates when the node finishes, `spawn` names an on-enter provider, and * `repeat` re-runs the node's subtree that many extra times before advancing. */ export interface EncounterPhase { /** Stable, tree-unique id. Survives serialization and phase injection. */ id: string; data?: TData; children?: readonly EncounterPhase[]; /** * Completion predicate reference. A leaf without one completes immediately (a marker or * spawn-only phase); a group without one completes once all its children complete. */ completion?: PhaseCompletionRef; spawn?: PhaseSpawnRef; /** Extra runs of this node's subtree before advancing. Default 0 (runs once). */ repeat?: number; } /** Per-node runtime record. Serializable — holds no functions or tree references. */ export interface PhaseRuntime { status: PhaseStatus; /** 0-based repeat iteration currently running. */ iteration: number; /** `elapsed` at which the node was most recently entered, for time-based predicates. */ enteredAt: number; } /** * Full serializable encounter state: the working phase tree (including any injected * phases), a per-node runtime map, the active path from root to the deepest open node, * accumulated time, and whether the sequence has finished. Round-trips through JSON with * no behavioral change; the registries live in {@link EncounterConfig}, not here. */ export interface EncounterState { roots: EncounterPhase[]; nodes: Record; /** Ids from a root down to the deepest open node; empty before start and once done. */ activePath: string[]; elapsed: number; started: boolean; done: boolean; } /** * Caller-supplied signals a completion predicate reads. Every field is optional and * opaque to the core: `counts` of tagged live entities, continuous `metrics`, cumulative * `events`, and boolean `flags`. Deterministic given the same values. */ export interface EncounterSignals { counts?: Readonly>; metrics?: Readonly>; events?: Readonly>; flags?: Readonly>; } /** * Context passed to {@link startEncounter} / {@link updateEncounter}: the caller signals * predicates evaluate against, plus named `spawnPoints` catalogs (authored in the scene, * referenced by key) that spawn providers place against. Never holds coordinates the * sequence itself owns. */ export interface EncounterContext { signals?: EncounterSignals; /** Named lists of authored scene spawn points, referenced by spawn providers by key. */ spawnPoints?: Readonly>; } /** Evaluation context a completion predicate receives for the node under test. */ export interface PredicateContext { phaseId: string; iteration: number; /** Total accumulated encounter time. */ elapsed: number; /** Time since this node was entered (0 on the tick it is entered). */ phaseElapsed: number; signals: EncounterSignals; } /** * A completion predicate: pure and deterministic, returns true when the node it gates is * finished. Registered under a `kind` and reused across phases with different `params`. */ export type CompletionPredicate = (params: Readonly>, ctx: PredicateContext) => boolean; /** A single spawn request a provider emits; `ref` is caller-defined, `point` optional. */ export interface EncounterSpawnRequest { ref: string; point?: NavPoint; data?: unknown; } /** Evaluation context a spawn provider receives when its phase is entered. */ export interface SpawnProviderContext { phaseId: string; iteration: number; elapsed: number; spawnPoints: Readonly>; } /** * A spawn provider: given the phase's `params` and context, returns the spawn requests to * emit on enter. Deterministic; reads authored scene points from `ctx.spawnPoints` rather * than embedding coordinates. */ export type SpawnProvider = (params: Readonly>, ctx: SpawnProviderContext) => readonly EncounterSpawnRequest[]; /** A lifecycle event emitted while stepping an encounter, carrying provenance. */ export type EncounterEvent = { type: "enter"; phaseId: string; iteration: number; } | { type: "spawn"; phaseId: string; provider: string; requests: readonly EncounterSpawnRequest[]; } | { type: "complete"; phaseId: string; iteration: number; reason: string; } | { type: "done"; }; /** Result of a step: the (mutated, returned) state and the events emitted this step. */ export interface EncounterStep { state: EncounterState; events: EncounterEvent[]; } /** * Non-serializable configuration for an encounter: the authored phase tree plus predicate * and spawn-provider registries. Re-supplied alongside a loaded {@link EncounterState}, the * way `advanceSpawnDirector` pairs config with state, so the state itself stays pure data. */ export interface EncounterConfig { phases: readonly EncounterPhase[]; /** Extra predicates, merged over the built-ins (a same-named entry overrides). */ predicates?: Readonly>; /** Extra spawn providers, merged over the built-ins. */ spawnProviders?: Readonly>; } /** Where to insert an injected phase, relative to an existing node by id. */ export type PhaseInjectAt = { before: string; } | { after: string; } | { childOf: string; index?: number; }; /** * Built-in completion predicates covering the common encounter gates: `immediate` (leaf * marker), `manual`/`flag` (external event via a caller flag), `timer` (phase seconds), * `cleared` (tagged entity count drained), `metric` (threshold on a live value), `event` * (cumulative event count), and `quorum` (at least N of nested predicates met). Merge your * own over these through {@link EncounterConfig.predicates}. * * @capability encounter-predicates gate encounter phase completion on timers, cleared spawns, metrics, events, or a quorum of conditions */ export declare const BUILTIN_COMPLETION_PREDICATES: Readonly>; /** * Built-in spawn providers. `points` reads a named authored scene point list from context * and cycles it to emit `count` requests, keeping coordinates in the scene rather than the * sequence. `list` echoes literal requests authored in `params.requests`. Merge your own * catalog- or director-backed providers through {@link EncounterConfig.spawnProviders}. * * @capability encounter-spawn-providers turn an entered encounter phase into spawn requests from authored scene points or an inline list */ export declare const BUILTIN_SPAWN_PROVIDERS: Readonly>; /** * Build the initial, serializable state for an encounter from its config. Deep-copies the * authored phase tree (so later injection never mutates the config), verifies phase ids are * unique, and leaves every node pending. Does not enter the first phase — call * {@link startEncounter} for that. * * @capability encounter-state create the serializable starting state of a hierarchical encounter sequence */ export declare function createEncounterState(config: EncounterConfig): EncounterState; /** * Start a created encounter: enter the first root phase, descending to its first leaf, and * return the initial enter/spawn events. A no-op (with no events) on an already-started or * empty encounter. Mutates and returns `state`. * * @capability encounter-start enter the first phase of a hierarchical encounter and emit its opening spawn events */ export declare function startEncounter(config: EncounterConfig, state: EncounterState, ctx?: EncounterContext): EncounterStep; /** * Advance an encounter by `dt` seconds against the caller `ctx`. Accumulates time, then * repeatedly: evaluates the cursor node's completion predicate; on completion, either * re-runs its subtree (`repeat`) or marks it complete and advances to the next sibling — * bubbling up to parent groups whose children are exhausted — entering the next chain and * emitting enter/spawn/complete events. Emits a final `done` event when the last phase * completes. Bounded per call by node count; mutates and returns `state`. * * @capability encounter-advance step a hierarchical encounter, resolving predicate-gated completion, repeats, and nested advance with lifecycle events */ export declare function updateEncounter(config: EncounterConfig, state: EncounterState, dt: number, ctx?: EncounterContext): EncounterStep; /** * Force the deepest active phase (or a named active phase) to complete now, regardless of * its predicate — the escape hatch for external/scripted completion and failure/retry flows. * Advances into the next phase and emits the same lifecycle events as a natural completion. * Returns no events if the phase is not currently active. Mutates and returns `state`. * * @capability encounter-force-complete externally complete an active encounter phase to drive scripted or failure-retry transitions */ export declare function forceCompletePhase(config: EncounterConfig, state: EncounterState, ctx?: EncounterContext, phaseId?: string): EncounterStep; /** * Insert a phase into the working tree at runtime — before/after a sibling, or as a child of * a group — without disturbing already-completed or active nodes. The injected subtree * becomes part of the serializable state (so a mid-encounter save preserves it) and is * reached in normal order if it sits ahead of the cursor. Ids must stay tree-unique. Mutates * and returns `state`. * * @capability encounter-inject-phase dynamically insert a phase or branch into a running encounter, e.g. a boss on the final wave */ export declare function injectPhase(state: EncounterState, phase: EncounterPhase, at: PhaseInjectAt): EncounterState; /** * The deepest active phase id — the completion cursor a HUD reads to label the current * wave/phase — or null before start and once done. * * @capability encounter-active-phase read the id of the phase an encounter is currently waiting on */ export declare function activePhaseId(state: EncounterState): string | null; /** * The runtime status of a phase by id (pending/active/complete), or null if the id is * unknown — for driving per-phase HUD ticks and objective checklists. * * @capability encounter-phase-status read whether a specific encounter phase is pending, active, or complete */ export declare function phaseStatus(state: EncounterState, id: string): PhaseStatus | null; /** * Progress across the whole tree: how many phases have completed out of the total node * count, plus whether the encounter has finished. Counts injected phases. * * @capability encounter-progress read completed-vs-total progress across a hierarchical encounter for HUD or objective display */ export declare function encounterProgress(state: EncounterState): { completed: number; total: number; done: boolean; };