Effect Condition Catalog

Built-in condition types used by the effect engine. Effects (from artifacts, ship passives, and mod abilities) attach an array of ConditionDef entries; the engine evaluates them in array order and bails on first failure. ALL must pass for the effect’s actions to fire. Each entry has shape { type: string, params: Record<string, number | string> } and dispatches through CONDITION_MAP in engine/effects/conditions.ts.

This catalog backs the ConditionDef.type field documented in engine/effects/types.ts. All params support $value placeholders resolved from EffectInstance.values via resolve-params.ts (numeric params through resolveNumber, strings through resolveString).

Conditions are pure reads — they never modify state. Evaluation order matters: list cheapest (signal/random) first, ship-state next, registry lookups last.

Signal-context (cheapest)

These fire against the SignalSnapshot carried by the triggering event. If the trigger has no snapshot (e.g. run_start), most snapshot-based conditions short-circuit.

TypeWhat it checksParams
randomRoll a uniform 0–1 random < chance. Independent per evaluation.chance (0..1, default 1)
signal_str1_eqThe triggering signal’s str1 field equals an expected value. Returns false if no snapshot.value (string, default '')
signal_str1_neqThe triggering signal’s str1 field does NOT equal a value. Returns true if no snapshot (vacuously).value (string, default '')
signal_num1_gteThe triggering signal’s num1 field is at least a threshold. Returns false if no snapshot.value (number, default 0)
damage_tag_eqConvenience alias over signal_str1_eq — checks damage tag carried in str1. Used to gate hit/kill procs by damage type (fire, kinetic, etc.).tag (string, default '')

Ship state

Read against the active ShipState.

TypeWhat it checksParams
hp_belowship.hp / hpMax is below a fraction.threshold (0..1, default 0.5)
hp_aboveship.hp / hpMax is above a fraction.threshold (0..1, default 0.5)
shield_activeShip has any shield remaining (shield > 0).none
shield_brokenShip shield is fully gone (shield <= 0).none
shield_emptyAlias for shield_broken — semantically distinct gating keyword for content authors.none
heat_aboveShip heat gauge is at or above a threshold.threshold (number, default 50)
speed_aboveShip’s current velocity magnitude (sqrt(vx²+vy²)) is at or above a threshold.threshold (number, default 100)
speed_belowShip’s current velocity magnitude is strictly below a threshold. Used for “stationary” procs.threshold (number, default 10)
has_buffAt least one modifier with the given source tag is currently active on this ship (read via Modifiers._modsByTarget).source (string, default '')

Inventory / progression

Read against GameState.

TypeWhat it checksParams
has_artifactThe player has an artifact with the given id in game.artifacts.artifactId (string)
has_upgradegame.upgradeCounts[upgradeId] is at least minLevel.upgradeId (string), minLevel (number, default 1)

Run state / time

TypeWhat it checksParams
kill_streak_abovegame.killStreak is at or above a threshold.threshold (number, default 0)
elapsed_abovegame.time (run-elapsed seconds) is at or above a threshold. Use to gate late-run effects.seconds (number, default 0)
elapsed_belowgame.time is strictly below a threshold. Use for early-run-only effects.seconds (number, default 999999)
tier_at_leastCurrent level/tier (_currentLevel) is at or above a number.tier (number, default 1)

Boss

TypeWhat it checksParams
boss_activeA boss arena is currently active (game.bossArena !== null).none
boss_phase_gteReserved — currently a stub that always returns false. Placeholder for future boss-phase gating.(TBD)

Authoring notes

  • Order matters. Put random / signal checks first, ship-state second, registry lookups (has_artifact, has_upgrade, has_buff) last.
  • AND-only. There’s no OR or NOT at the condition level. Use multiple effects with different condition arrays to express alternates.
  • No snapshot → undefined. Snapshot-based conditions return false when there’s no signal (the _neq variant returns true). Trigger types like run_start, timer, or polling auras have no snapshot, so don’t attach signal conditions to them.
  • Param resolution. Numeric and string params accept $key references resolved against EffectInstance.values at evaluation time, so a single effect template can be reused across stat tiers.
  • Adding a new type. Implement a ConditionFn, register it in CONDITION_MAP at the bottom of engine/effects/conditions.ts. Unknown types throw — there is no silent fallback.
  • engine/effects/types.tsConditionDef, EffectInstance, EffectDef shapes.
  • engine/effects/effect-engine.ts — trigger dispatch + condition orchestration.
  • engine/effects/resolve-params.ts$key placeholder resolution.
  • engine/effects/actions.ts — what runs when all conditions pass.
  • Companion concept: trigger types, action catalog, signal-snapshot fields.