run-effects.ts
PURPOSE
Orchestrates per-run wiring of the EffectEngine. At mission start it clears prior state, registers installed mod effects (placeholder) and active artifact effects, primes the engine with game/ship references, subscribes to signals, and fires the one-shot run_start trigger. Replaces the legacy initArtifacts() call. Provides matching teardown for mission end.
OWNS
registerRunEffects(game, ship, activeArtifacts)— exported entry that performs the full clear-register-init sequence.teardownRunEffects()— exported entry that clears the EffectEngine at mission end.- The fixed run-start sequence: clear → mod effects (placeholder) → artifact effects → prime tick → init.
- The convention that every registered effect group gets a source tag of the form
artifact:<id>.
READS FROM
EffectEngine(./effect-engine) — callsclear,register,tick,init.Sig(../core/signals) — imported for the signal-firing contract referenced in the file header (run-start fan-out is documented as happening through engineinitsubscriptions).GameState,ShipState(../core/types) — passed through to the priming tick.ARTIFACT_MAP,getTierValuesAt(../../data/artifacts) — looks up artifact definitions byinst.idand resolves runtime tier index (0-4) to the underlying 4-tuple tier values.ArtifactInstance(../world/artifacts) — input array element type; suppliesidandtier.
PUSHES TO
EffectEngineinternal state — populates the engine’s effect registry with artifact effect groups taggedartifact:<id>and their tier values.EffectEnginesignal subscriptions — established wheninit()runs after registration.
DOES NOT
- Does not evaluate or trigger individual effects itself; that is the EffectEngine’s responsibility.
- Does not iterate the world entity lists; the priming tick passes an empty
{ enemies, playerBullets, enemyBullets, particles }snapshot. - Does not register mod effects yet — Phase A is a placeholder reserved for Phase 6 to populate from
ModTemplate.effects. - Does not skip artifacts based on tier; only skips when the artifact id is missing from
ARTIFACT_MAPor has noeffectsarray. - Does not unregister individual effects — teardown clears the entire engine.
- Does not assemble the run definition; expects to be called after
assembleRunDefbut before gameplay begins.
Signals
- Header documents firing
run_startviaSig.fire('run_start')as step 5 of the sequence; subscribers are wired throughEffectEngine.init()so that any registered effect listening forrun_startruns once at mission start. Sigis imported but the file relies on the engine’s subscription model — handlers attach duringEffectEngine.init().
Entry points
registerRunEffects(game: GameState, ship: ShipState, activeArtifacts: ArtifactInstance[]): void— called bybridge.tsat mission start, after run assembly and before gameplay begins.teardownRunEffects(): void— called bybridge.tsat mission end.
Pattern notes
- Fixed phase order: clear, Phase A (mod effects, placeholder), Phase B (artifact effects), Phase D (priming tick + init). Phase C is implicitly reserved.
- Each artifact contributes a single grouped registration to the engine, scoped by a stable source tag of
artifact:<id>, enabling later targeted teardown if needed. - Tier resolution is centralised through
getTierValuesAt(def, inst.tier)so callers never index the raw 4-tuple directly; the returned values are passed to the engine for$varsubstitution inside effect param payloads. - A zero-delta priming tick (
EffectEngine.tick(0, game, ship, emptyWorld)) is invoked beforeinit()so signal handlers have cachedgame/shiprefs available immediately. The empty world snapshot is cast throughas anybecause no entities exist yet at run-start. - Artifacts with no
effectsarray or an empty one are silently skipped — no warning, no crash. - Teardown is symmetric and minimal: a single
EffectEngine.clear()call removes everything in one shot, matching the run-scoped lifecycle.