engine/effects/types.ts
Type definitions for the unified effect system. The effect engine provides a signal → condition → action pipeline used by artifacts, ship passives, and ship mod abilities. Every triggered gameplay effect flows through these types.
Consumed by effect-engine.ts (runtime registry, tick, signal dispatch), conditions.ts (condition evaluators), actions.ts (action executors), and run-effects.ts (wires artifacts/passives/mods at run start).
Imports
SignalContextfrom../core/signalsGameState,ShipState,WorldStatefrom../core/types
DamageTag
type DamageTag = 'bullet' | 'energy' | 'bomb' | 'fire' | 'true' | 'boss'Every damage event carries exactly one tag. Weapon-produced events use one of the four exclusive weapon tags (bullet, energy, bomb, fire). true and boss are reserved for engine-internal events.
TriggerType
type TriggerType = 'signal' | 'run_start' | 'aura' | 'timer' | 'counter'How an effect activates:
| Type | Behavior |
|---|---|
signal | Fires when a named Sig signal is emitted. |
run_start | Fires once after all effects are registered at run start. |
aura | Continuously checks conditions; applies/removes modifiers. |
timer | Fires after N seconds (optionally repeating, optionally reset by a signal). |
counter | Fires after counting N occurrences of a signal. |
TriggerDef
Discriminated by type: TriggerType. Fields are conditionally meaningful per trigger type.
| Field | Type | Used by | Notes |
|---|---|---|---|
type | TriggerType | all | required |
signal | string? | signal | signal name (e.g. 'enemy_kill', 'shield_break') |
auraInterval | number? | aura | seconds between checks; default 0.5 |
timerDuration | number? | timer | seconds until fire |
timerRepeat | boolean? | timer | restart after firing; default false |
timerResetSignal | string? | timer | signal that resets countdown to 0 |
counterSignal | string? | counter | signal whose occurrences are counted |
counterThreshold | number? | counter | fires after this many; supports $var |
counterResets | boolean? | counter | resets to 0 after firing; default true |
ConditionDef
interface ConditionDef {
type: string
params: Record<string, number | string>
}A single condition check. All conditions in an effect must pass (AND logic). Evaluated cheapest-first: random/str1 checks before HP/stat queries.
Built-in types: random, signal_str1_eq, signal_str1_neq, signal_num1_gte, hp_below, hp_above, shield_active, shield_broken, shield_empty, has_artifact, has_upgrade, has_buff, kill_streak_above, elapsed_above, elapsed_below, tier_at_least, heat_above, speed_above, damage_tag_eq.
ActionDef
interface ActionDef {
type: string
params: Record<string, number | string | boolean>
}A single action to execute. Actions run in order on each trigger. Params starting with $ are resolved from EffectInstance.values.
Built-in types: modify_stat, modify_stat_scaled, modify_upgrade_count, heal, heal_shield, grant_invuln, set_heat, damage_aoe, damage_single, apply_knockback, spawn_projectile, spawn_beam, spawn_zone, apply_enemy_status, apply_status_aoe, empower_weapon, restore_speed, remove_modifiers, flash_artifact, vfx, emit_signal, custom, custom_tick.
EffectDef
Data-driven, immutable per content. One per artifact/passive/mod definition.
| Field | Type | Notes |
|---|---|---|
id | string | unique (e.g. 'soul_leech_ghosts', 'reactive_plating_stack') |
trigger | TriggerDef | what activates the effect |
conditions | ConditionDef[] | all must pass; empty array = always passes |
actions | ActionDef[] | executed in order when trigger + conditions pass |
cooldown | number? | seconds between activations; 0 = no cooldown |
charges | number? | max activations per run; -1 = unlimited; default -1 |
priority | number? | signal listener priority; default 50 (effects band) |
showBanner | boolean? | push “[Artifact] activated” banner on fire; throttled to 1 per artifact per 0.5s in the banner module; dev-curated, leave off for per-hit procs / auras / run_start |
EffectInstance
Runtime state, one per registered effect.
| Field | Type | Notes |
|---|---|---|
def | EffectDef | immutable definition |
owner | string | owner identifier ('artifact:soul_leech', 'passive:afterburner', 'mod:static_discharge') |
values | Record<string, number> | value dict for $var param resolution (e.g. tier values) |
cooldownRemaining | number | seconds until next allowed fire |
chargesUsed | number | how many times this effect has fired |
counterAccum | number | accumulated count for counter trigger |
timerAccum | number | accumulated time for timer trigger |
auraActive | boolean | for aura trigger: are modifiers currently applied |
enabled | boolean | kill switch — disabled effects skip all evaluation |
SignalSnapshot
interface SignalSnapshot {
name: string
uid1: number
uid2: number
num1: number
num2: number
str1: string
}Snapshot of SignalContext fields captured before action dispatch. Passed to custom action handlers so they read consistent values even if the live signal context mutates mid-pipeline.
CustomActionFn
type CustomActionFn = (
snap: SignalSnapshot | null,
params: Record<string, number>,
game: GameState,
ship: ShipState,
world: WorldState,
) => voidCustom action handler — called for type: 'custom' actions. snap is null for triggers that have no signal (e.g. run_start, aura, timer).
CustomTickFn
type CustomTickFn = (
dt: number,
params: Record<string, number>,
game: GameState,
ship: ShipState,
world: WorldState,
) => voidCustom tick handler — called every frame for type: 'custom_tick' actions. Used for per-frame custom logic that doesn’t map cleanly to a one-shot action.
EnemyStatusType
type EnemyStatusType = 'stunned' | 'shredded' | 'burning'Lightweight status effects on enemies.
EnemyStatusEntry
interface EnemyStatusEntry {
stacks: number
timer: number
value: number
}| Field | Meaning |
|---|---|
stacks | current stack count (shredded stacks, burning stacks) |
timer | seconds remaining before status expires |
value | effect magnitude per stack (DPS for burning, +%dmg for shredded) |
Cross-references
- Engine:
code/engine/effects/effect-engine,code/engine/effects/conditions,code/engine/effects/actions,code/engine/effects/run-effects,code/engine/effects/custom-handlers,code/engine/effects/custom-registry,code/engine/effects/resolve-params,code/engine/effects/enemy-status - Signals:
code/engine/core/signals - Core state:
code/engine/core/types
EXTRACT-CANDIDATE
- Damage tag taxonomy —
bullet | energy | bomb | fireare the four exclusive weapon tags;trueandbossare engine-internal-only. Belongs on acombat/damage-tagsconcept page if one exists, or a Styx roll-up. - Built-in condition catalog (18 types) — extract to
effects/conditionspage as a canonical reference table. - Built-in action catalog (~24 types) — extract to
effects/actionspage as a canonical reference table. - Banner throttle rule — “1 banner per artifact per 0.5s” lives in the banner module; cross-reference from a UI/banner page.
- Priority bands —
50is the “effects band”; full band layout belongs on the signals page. - Trigger-type semantics table (signal/run_start/aura/timer/counter) — candidate for promotion to the
effects/indexoverview if not already there. - Enemy status stack semantics —
burningvalue = DPS-per-stack,shreddedvalue = +%dmg-per-stack; promote to acombat/enemy-statusconcept page.