The pack
shootingGallery
function shootingGallery(): Pack<{ shootingGallery: typeof api }>
Install the shooting gallery API.
Helpers
createGallery
function createGallery(config: GalleryConfig): Gallery
Build a gallery.
CROSSBOW_VIEW
const CROSSBOW_VIEW: { w: number; h: number; }
Crossbow's screen: 320 x 240.
crossbowGun
function crossbowGun(): GunDef
The crossbow: single shots, unlimited bolts, one "DON'T SHOOT YOUR FRIENDS!" warning per game.
crossbowKinds
const crossbowKinds: ActorKind[]
Kinds: the friends, every zone's threats (7800 point table), barriers, treasures and the Evil Master.
crossbowPlanes
const crossbowPlanes: PlaneDef[]
Planes: the sky (screen-fixed flyers), the far scenery, the path the friends walk (last: the party's plane).
crossbowPreset
function crossbowPreset(o: CrossbowOptions = {}): GalleryConfig
Crossbow, Exidy 1983: the whole game as a gallery configuration.
crossbowStages
function crossbowStages(): StageDef[]
The eight danger zones and the Evil Master.
GALLERY_STEP
const GALLERY_STEP: number
The gallery's fixed step: 1/60 s.
galleryDifficulty
function galleryDifficulty(d: GalleryDifficulty): GalleryTuning
Difficulty multipliers: Arcade is the original (DIP Medium) tables.
operationWolfGun
function operationWolfGun(o: { magazines?: number; rockets?: number } = {}): GunDef
The light gun: the Uzi (30-round magazines, automatic changes, slow fire when out) and the rockets.
operationWolfItems
const operationWolfItems: ItemDef[]
Items: a magazine is 30 rounds, a rocket one rocket, a power drink 5 damage off, the Super Machine Gun 10 s.
operationWolfKinds
const operationWolfKinds: ActorKind[]
Actor kinds (sizes in pixels at scale 1).
operationWolfMapBoxes
const operationWolfMapBoxes: Record<string, { x: number; y: number; w: number; h: number }>
The operation map boxes for the Japanese free order (the six panels of the arcade's map, 3 x 2).
operationWolfPlanes
const operationWolfPlanes: PlaneDef[]
Depth planes: far, middle and near bands of the sand, the air and the river.
operationWolfPreset
function operationWolfPreset(o: OperationWolfOptions = {}): GalleryConfig
Operation Wolf, Taito 1987: the whole game as a gallery configuration.
operationWolfStages
function operationWolfStages(): StageDef[]
The six missions. Scroll directions follow the walkthrough (Roy Adams walks left on stages 1, 5 and 6).
OPWOLF_VIEW
const OPWOLF_VIEW: { w: number; h: number; }
Operation Wolf's playfield: the 240 x 240 picture left of the 80-pixel status panel.
validateGallery
function validateGallery(c: GalleryConfig): void
Validate a configuration; throws a clear error for unsupported data.
Types
Actor
interface Actor
A live actor (plain data).
id: string— Id (kind-n).kind: string— Kind id.seq: number— Spawn serial.plane: number— Plane index.scale: number— Size multiplier.x: number— Plane-local x: world x for world actors, screen x for screen actors.y: number— Screen y of the centre.sx: number— Screen x of the centre (computed each step).sy: number— Screen y of the centre (computed each step).dir: 1 | -1— Facing / travel direction.vx: number— Velocity x, screen pixels per second.vy: number— Velocity y.hp: number— Hit points left.hits: number— Hits taken.mode: string— Current activity for presenters:move,wait,attack,down,hop,fall,descend,hover,exit,idle,fly,walk,hold.step: number— Script step index.stepT: number— Seconds in the current step.age: number— Seconds alive.hidden: boolean— Hidden actors are not drawn or hit.flash: number— Seconds of attack wind-up left (flashing).attackT: number— Seconds to the next automatic wind-up.attacks: number— Attacks made.down: number— Seconds knocked down.wave: number— Wave index that spawned it (-1: stream, -2: boss, -3: rules).seen: boolean— Has been on screen.slow: number— Speed multiplier (a limping walker).dropped: boolean— Has dropped its item.script: ScriptStep[]— Script (copied).z: number— Draw/hit order.points: number | null— Points override.flight: { x0: number; y0: number; x1: number; y1: number; t: number; travel: number; s0: number; s1: number; arc: number; target: string | null } | null— Flight for ordnance: screen start, end, seconds, elapsed, start and end scale, arc, target walker id.phase: number— Current phase index of a vulnerability cycle.phaseT: number— Seconds in the current phase.phaseName: string— Phase name.data: Record<string, number | string | boolean>— Free data (presentation and script scratch).
ActorKind
interface ActorKind
An actor kind.
id: string— Unique id.role?: "enemy" | "vehicle" | "aircraft" | "protected" | "item" | "prop" | "projectile" | "boss" | "animal" | "barrier" | "threat"— Role for defaults and presenters.w: number— Width at scale 1.h: number— Height at scale 1.regions?: ScreenRegion[]— Light-gun hit regions in kind units about the centre (default the whole box).hp?: number— Hits to destroy (default 1); 0 cannot be destroyed (animals hop instead).points?: number— Points when destroyed.hitPoints?: number— Points for a hit that does not destroy.quota?: string— Quota counter decremented when destroyed ('soldier','helicopter','vehicle','boat').protected?: string— Protected kind label (the gun's penalty table key).speed?: number— Default movement speed in pixels per second at scale 1.anchor?: "world" | "screen"— World actors move with the scrolling ground; screen actors are fixed to the screen (aircraft, ordnance).script?: ScriptStep[]— Default motion script.attack?: AttackDef— Attack.react?: ReactDef— Reaction to non-lethal hits.drops?: DropDef— Drops.item?: string— Shooting this actor collects this item.walker?: WalkerDef— Protected walker.lethal?: { consume?: boolean }— Touching a walker kills it (Crossbow's threats).consumeremoves the threat too.barrier?: BarrierDef— Barrier.pickup?: { points?: number }— Walkers that reach it collect it (Crossbow treasure): points.phases?: PhaseDef[]— Vulnerability cycle.flight?: { travel?: number; scale?: number; arc?: number }— Ordnance flight (role projectile): seconds to arrive, end scale, arc height.damage?: number— Damage when ordnance arrives at the player (default 1).ghost?: boolean— Shots ignore it (default false).life?: number— Seconds before it is removed as escaped (default unlimited).layer?: number— Draw/hit order bias within its plane (default 0).data?: Record<string, number | string | boolean>— Presentation data.
AttackDef
interface AttackDef
How an actor attacks.
windup?: number— Seconds the actor flashes before the attack lands (Operation Wolf's warning flash). Default 1.damage?: number— Damage to the player when a shot lands (hitscan). Default 1.chance?: number— Chance a landed shot hurts (default 1).projectile?: string— Throw or fire a projectile kind instead of a hitscan shot.target?: "player" | "walker"— Who it attacks: the player (default) or the nearest walker.auto?: boolean— Attack automatically on a timer while visible (default true).first?: number— Seconds before the first wind-up starts (default 0.6).every?: number— Seconds between attacks (default 2.5).jitter?: number— Random extra fraction ofevery(default 0.3).max?: number— Attacks before it stops attacking (default unlimited).planes?: string[]— Only attack while on these planes (by id).range?: number— Walker attacks: only strike a walker within this many pixels horizontally (default unlimited).
BarrierDef
interface BarrierDef
A barrier: walkers cannot pass its x while it stands.
fatal?: boolean— Walkers that reach it while it stands die (a crevice, lava) rather than waiting (a raised drawbridge).group?: string— Group: every barrier actor of the group must fall before any opens (two ropes). Default the actor id.gap?: number— Pixels before the barrier's x where walkers stop or fall (default 8).
BossDef
interface BossDef
A boss that appears when the stage's other goals are met.
spawn: SpawnSpec— Spawn spec.banner?: string— Banner text for presenters (WARNING!! THE FINAL HELICOPTER).delay?: number— Seconds of banner before it appears (default 1.5).
CrossbowOptions
interface CrossbowOptions
Options for the Crossbow preset.
difficulty?: GalleryDifficulty— Difficulty (default'normal').friends?: number— Friends at the start (the DIP: 2, 3, 4 or 5; default 3).maxFriends?: number— Most friends (default 8).seed?: number— Seed.
DropDef
interface DropDef
Items left behind when an actor is shot.
items: string[]— Item ids to choose from (seeded).chance?: number— Chance of a drop (default 1).on?: "hit" | "destroy"— When it drops: on any hit or only when destroyed (default'hit').once?: boolean— Drop at most once (default true).smart?: boolean— Leave out items that would do nothing now (a power drink with no damage, rockets at the maximum). Default true.
EndingDef
interface EndingDef
The ending after the final stage.
counter?: string— Counter whose final value picks the bonus.bonus?: number[]— Bonus by counter value (index 0 = none: withfailOnZerothe game ends).failOnZero?: boolean— The game ends if the counter is zero (all hostages dead).restore?: boolean— Restore gun ammunition to the starting stocks and clear the damage before the next loop.partyBonus?: number— Bonus when every party member who entered the final stage left it alive (Crossbow 250,000).
Gallery
interface Gallery
A running gallery.
readonly config: GalleryConfig— The configuration.readonly state: GalleryState— Live state (plain data).readonly gun: Gun— The light gun.readonly stageDef: StageDef— The current stage definition.start(): void— Begin a new game (from attract or game over).tick(seconds: number, input?: GalleryInput): void— Advance bysecondsin whole fixed steps.step(input?: GalleryInput): void— Advance one fixed step.drain(): GalleryEvent[]— Take the events since the last drain.choices(): MapChoice[]— Choices on the map screen.choose(id: string): boolean— Pick a map choice.kind(id: string): ActorKind— Look up a kind.plane(i: number): PlaneDef— A plane by index.actor(id: string): Actor | undefined— An actor by id.quotaLeft(counter: string): number— Quota left on a counter this stage.hud(): GalleryHud— HUD summary.targets(): ScreenTarget[]— The screen targets the gun sees this step (for presenters and debugging).spawn(spec: SpawnSpec): Actor | null— Spawn an actor now (rules extensions, tests).addScore(points: number): void— Add points.snapshot(): { gallery: GalleryState; gun: GunState }— Deep copy of the state (gallery and gun).restore(s: { gallery: GalleryState; gun: GunState }): void— Restore a snapshot from a gallery built from the same configuration.
GalleryConfig
interface GalleryConfig
A complete gallery configuration (plain data plus the gun definition).
view: { w: number; h: number }— The playfield in screen pixels (the HUD is the presenter's).gun: GunDef— The light gun.planes: PlaneDef[]— Depth planes.kinds: ActorKind[]— Actor kinds.items?: ItemDef[]— Pickups.stages: StageDef[]— Stages.map: MapDef— The map.damage?: { max: number; perStage?: number } | null— The damage meter (Operation Wolf): game over when full.party?: PartyDef | null— The party (Crossbow): game over when all are dead.clearBonus?: number— Points per stage cleared.ending?: EndingDef— Ending.penalties?: Record<string, { damage?: number; score?: number }>— Penalty applied by the rules per protected kind:damageon the meter,score.difficulty: GalleryDifficulty— Difficulty name.tuning: GalleryTuning— Difficulty multipliers.timing: GalleryTiming— Timings.seed: number— Seed.topScore?: number— High score to beat.start?: { loop?: number; stage?: string; carry?: Record<string, number> }— Starting loop (0), stage (default the map's first) and carried counters (hostages already freed).flags?: string[]— Flags that start set.reinforce?: { flag: string; factor: number; except?: string[] }— Quota increase without a flag:{ flag, factor }(Operation Wolf: enemy counts rise unless the communication setup is cleared).maxActors?: number— Most actors alive (a resource bound, default 96).
GalleryDifficulty
type GalleryDifficulty = "easy" | "normal" | "arcade"
Difficulty presets: Arcade is the original tables.
GalleryEvent
type GalleryEvent = | { type: "map"; choices: string[] } | { type: "chosen"; choice: string; stage: string } | { type: "stage-start"; stage: string; name: string; number: number; loop: number } | { type: "play"; stage: string } | { type: "spawn"; actor: string; kind: string } | { type: "hit"; actor: string; kind: string; damage: number; points: number; x: number; y: number; region: string } | { type: "destroyed"; actor: string; kind: string; points: number; x: number; y: number; scale: number; by: "shot" | "blast" | "rules"; quota?: string } | { type: "knockdown"; actor: string; kind: string } | { type: "hop"; actor: string; kind: string } | { type: "drop"; actor: string; item: string } | { type: "pickup"; actor: string; item: string; x: number; y: number; points: number } | { type: "windup"; actor: string; kind: string } | { type: "enemy-fire"; actor: string; kind: string; x: number; y: number; hurt: boolean; damage: number } | { type: "launch"; actor: string; kind: string; from: string } | { type: "player-hit"; damage: number; cause: string; total: number; x: number; y: number } | { type: "protected-hit"; actor: string; kind: string; warning: boolean; fatal: boolean; x: number; y: number } | { type: "walker-killed"; actor: string; kind: string; cause: string; x: number; y: number } | { type: "arrived"; actor: string; kind: string; counter: string } | { type: "treasure"; actor: string; points: number; by: string } | { type: "barrier-open"; group: string } | { type: "escaped"; actor: string; kind: string } | { type: "phase"; actor: string; phase: string } | { type: "strike"; actor: string; target: string } | { type: "boss-warning"; banner: string } | { type: "boss"; actor: string; kind: string } | { type: "quota"; counter: string; left: number } | { type: "stage-clear"; stage: string; bonus: number; survivors: number; partyBonus: number } | { type: "party"; members: number; added: number } | { type: "ending"; good: boolean; bonus: number; counter: number } | { type: "loop"; loop: number } | { type: "game-over"; reason: string } | { type: "gun"; event: GunEvent }
Gallery events (gun events are forwarded as { type: 'gun', event }).
GalleryHud
interface GalleryHud
HUD summary for presenters.
quotas: Array<{ counter: string; left: number }>— Visible quota counters and what is left.damage: number— Damage on the meter and its maximum (0/0 without a meter).damageMax: number— Meter maximum.rounds: number— Primary weapon rounds in the magazine.magazines: number | null— Spare magazines (null unlimited).special: number | null— Special weapon stock (null none or unlimited).escort: number— Escort counter shown (hostages freed / boarded).score: number— Score.top: number— High score.party: number— Party members (alive, including those walking).
GalleryInput
interface GalleryInput
Gallery input for one step: the gun's input (pointer, trigger, special, reload).
x?: number— Pointer x in playfield pixels.y?: number— Pointer y in playfield pixels.onScreen?: boolean— Is the gun on the screen.snap?: boolean— Jump the crosshair (touch).stickX?: number— Stick x -1..1 (keyboard aiming).stickY?: number— Stick y -1..1.trigger?: boolean— Trigger held.special?: boolean— Special (rocket) held.reload?: boolean— Reload held.
GalleryState
interface GalleryState
Gallery state (plain data).
status: GalleryStatus— Status.statusT: number— Seconds in the status.stage: string— Current stage id.place: string— Map place (paths mode).loop: number— Loop number (0 first).time: number— Stage time (seconds of play).scroll: number— Scroll position in pixels.score: number— Score.topScore: number— High score.damage: number— Damage on the meter.party: number— Party members alive (between stages; walkers on screen during one).partyEntered: number— Members who entered the current stage.partyToEnter: number— Members still to enter.partyT: number— Seconds to the next member entering.kills: Record<string, number>— Kill counts this stage by quota counter.quotas: Record<string, number>— Quotas this stage (after reinforcement).arrived: Record<string, number>— Arrivals this stage by counter.lost: Record<string, number>— Protected walkers killed this stage by counter.carry: Record<string, number>— Carried counters between stages (hostages freed).cleared: string[]— Stages cleared (ids, this loop).survived: string[]— Stages ever survived (for first-time rewards).flags: string[]— Flags.wave: number— Next wave index.waveT: number— Seconds since the last wave started.streams: Array<{ next: number; spawned: number }>— Time each stream fires next, and spawns so far.boss: null | "pending" | "alive" | "dead"— Boss: null,pending(banner),alive,dead.actors: Actor[]— Actors.queued: Array<{ at: number; spec: SpawnSpec; wave: number; index: number }>— Spawns waiting for their delay.opened: string[]— Barrier groups opened.barriers: string[]— Barrier groups seen this stage.tally: { bonus: number; counted: number; survivors: number; partyBonus: number }— Clear tally: bonus being counted.ending: { bonus: number; counter: number; good: boolean } | null— Ending result.doomed: boolean— Stage failed an escort requirement (the game ends after the stage).autoT: number— Seconds before an automatic map choice.serial: number— Actor serial.rng: number[]— The seeded random stream's state: four words, from the kernel'srng.snapshot(). It advances in place and is saved with the state.stats: { kills: number; escaped: number; rescued: number; lost: number; damageTaken: number; pickups: number }— Statistics.
GalleryStatus
type GalleryStatus = "attract" | "map" | "briefing" | "playing" | "boss-warning" | "clear" | "ending" | "over"
Gallery status.
GalleryTiming
interface GalleryTiming
Timings in seconds.
briefing: number— Briefing before a stage.clear: number— Stage clear tally.ending: number— Ending screen.over: number— Game over before attract.
GalleryTuning
interface GalleryTuning
Difficulty multipliers (Arcade = 1).
windup: number— Attack wind-up multiplier (larger is more time to shoot first).attackEvery: number— Attack interval multiplier.damage: number— Damage multiplier.spawn: number— Stream interval multiplier (larger is fewer spawns).speed: number— Actor speed multiplier.flight: number— Ordnance flight time multiplier.loop: number— Per loop: the wind-up and stream intervals are multiplied by this each loop (harder).
ItemDef
interface ItemDef
A pickup's effect.
id: string— Item id.gun?: Array<{ weapon: string; rounds?: number; magazines?: number; stock?: number; boost?: { rate?: number; free?: boolean; seconds: number } }>— Ammunition and boosts for gun weapons.heal?: number— Damage removed from the meter.points?: number— Points.party?: number— Party members added.
MapChoice
interface MapChoice
A map choice: an id to pass to choose, the stage it leads to, and the box to shoot on the map screen.
id: string— Choice id (go, a stage id, or a path label).stage: string— Stage it leads to.box: { x: number; y: number; w: number; h: number } | null— Screen box, when the map defines one.
MapDef
interface MapDef
The map: how stages follow each other.
mode: "sequence" | "choice" | "paths"—sequence: a fixed order;choice: pick any open stage (prerequisites);paths: coloured paths from the current place.order?: string[]— Sequence order (stage ids).nodes?: Array<{ stage: string; requires?: string[] }>— Choice nodes with prerequisites.start?: string— Paths: the start place id.edges?: Array<{ from: string; to: string; label: string }>— Paths: labelled edges between places (frommay be the start).final?: string— The stage whose clearing ends a loop (default the last inorder).then?: Record<string, string>— Stages that always follow a stage, with no map (Crossbow's Castle Hall then the Evil Master).boxes?: Record<string, { x: number; y: number; w: number; h: number }>— Screen boxes to shoot on the map, by choice id (stage id, label, or'go').boxesByCount?: Record<string, Record<string, { x: number; y: number; w: number; h: number }>>— Boxes by the number of choices on offer (Crossbow's two halves or three thirds); overridesboxes.auto?: number— Seconds before a choice is made automatically (default none).
OperationWolfOptions
interface OperationWolfOptions
Options for the Operation Wolf preset.
difficulty?: GalleryDifficulty— Difficulty (default'normal').magazines?: number— Magazines at the start (the DIP: 4, 5, 6 or 7; default 6).rockets?: number— Rockets at the start (default 5).order?: "english" | "japanese"—english(fixed order, the default) orjapanese(choose the order; the Camp needs the Jungle, the Airport the Camp).damage?: number— Damage meter cells (default 28, counted from the arcade's panel).startStage?: string— Stage to start on (default the Communication Setup).seed?: number— Seed.
PartyDef
interface PartyDef
A party of friends who are the lives (Crossbow).
start: number— Members at the start.max: number— Most members.kinds: string[]— Walker kinds, cycled.gap: number— Seconds between members entering.bonus: number— Points per survivor at the end of each stage.
PhaseDef
interface PhaseDef
A vulnerability cycle: named phases with shielded regions and an attack at the end of a phase.
name: string— Phase name (copied to the actor'sphasefor presenters).t: number— Seconds.shield?: string[]— Region ids that are shields during this phase.strike?: boolean— Attack when the phase ends untouched (the Evil Master's red eyes).breakOnHit?: boolean— Region ids hit during the phase cut it short (default false).
PlaneDef
interface PlaneDef
A depth band: where actors on it stand and how big they are.
id: string— Plane id.ground: number— Screen y of the ground line (actors' feet) on this plane.scale: number— Size multiplier for actors on this plane (1 is the kind's own size).parallax?: number— Scroll factor for world-anchored actors (default 1: they move with the ground).z?: number— Draw and hit order base: higher is nearer (default the plane index).
ReactDef
interface ReactDef
What happens when an actor is hit but not destroyed.
knockdown?: number— Knocked down for this many seconds (Operation Wolf's gray soldiers).hop?: boolean— Hop into the air and run off (chickens and pigs).fall?: boolean— Fall to the ground (a coconut knocked out of a tree).flee?: boolean— Flee off the nearest edge.
RewardDef
interface RewardDef
Stage clear rewards.
heal?: number— Damage removed (on top of the global per-stage heal).ammo?: Array<{ weapon: string; rounds?: number; magazines?: number; stock?: number }>— Set gun ammunition.flag?: string— Set a flag (Operation Wolf's communication setup).party?: number— Party members added the first time this stage is survived (Crossbow).
ScriptStep
type ScriptStep = | { move: { dx?: number; dy?: number; forward?: number; toX?: number; toY?: number; up?: number; speed?: number } } | { wait: number } | { attack: true } | { exit: "left" | "right" | "top" | "bottom" | "forward" | "back"; speed?: number } | { descend: { speed?: number; to?: number } } | { fall: { gravity?: number; bounce?: number } } | { hover: { amp?: number; period?: number; seconds?: number } } | { seek: { speed?: number; seconds?: number } } | { hide: true } | { show: true } | { turn: true } | { loop: number } | { remove: true }
One step of an actor's motion script. Distances are pixels at scale 1 (multiplied by the actor's scale).
SpawnSpec
interface SpawnSpec
Spawn one or more actors.
kind: string— Kind id.side?: "left" | "right" | "top" | "bottom"— Enter from an edge (default'left'unlessxis set).x?: number— View x as a fraction 0..1 (forside: 'top'or a fixed place: a window, a hut).y?: number— Screen y (default the plane's ground minus half the height; aircraft: their script).plane?: string | number— Plane id or index (default 0).delay?: number— Seconds after the wave starts.count?: number— How many (default 1).gap?: number— Seconds between them (default 0.6).spacing?: number— Pixels between them at scale 1 whengapis 0 (a group running together).script?: ScriptStep[]— Script override.points?: number— Points override.data?: Record<string, number | string | boolean>— Data for presenters.layer?: number— Draw order bias.needs?: { counter: string; min: number }— Only spawn when a carried counter is at least this (the Airport's hostages freed in the Camp).aim?: "walker"— Place it above a walker (where that walker will be in a second): falling rocks, stalactites, lightning.safe?: number— Do not appear within this many pixels of a walker: try the other side, else wait for the next chance.
StageDef
interface StageDef
A stage (a mission, a danger zone).
id: string— Unique id.name: string— Display name.caption?: string[]— Briefing lines for presenters.scroll?: { speed: number; dir?: 1 | -1 }— Horizontal scroll: pixels per second and direction (1 rightward, -1 leftward). Default static.quotas?: Record<string, number>— Kill quotas by counter.hiddenQuotas?: string[]— Counters not shown on the HUD (Operation Wolf's trucks).waves?: WaveDef[]— Scripted waves.streams?: StreamDef[]— Continuous spawners.boss?: BossDef— A boss after the quotas (or the party's arrival).escort?: { counter: string; min: number; carry?: boolean }— Rescue requirement: at leastminarrivals of walkers counting towardcounter, or the game ends after the stage.party?: boolean— The party crosses this stage (Crossbow).reward?: RewardDef— Clear rewards.look?: Record<string, string>— Presentation strings (backdrop, colours).
StreamDef
interface StreamDef
A continuous spawner.
kinds: Array<SpawnSpec & { weight?: number }>— Weighted kinds.every: number— Seconds between spawns.jitter?: number— Random extra fraction ofevery(default 0.5).maxAlive?: number— Most actors of this stream alive at once (default 3).from?: number— Seconds into the stage before it starts (default 0).until?: number— Seconds into the stage after which it stops.count?: number— Total spawns (default unlimited).fill?: boolean— Only after the scripted waves are done (quota fill). Default false.
WalkerDef
interface WalkerDef
A protected walker crossing the screen.
goal: "left" | "right" | number— Where it walks to: an edge, or a view x (fraction 0..1).counter?: string— Counter incremented when it arrives ('hostages','party').hits?: number— Hits that kill it once the gun's warnings are used (default 1).slow?: number— Speed multiplier after a non-fatal hit (Crossbow's limp; default 1).turnAt?: number— Turn back at this view x (fraction) instead of crossing (children who run in and out).
WaveDef
interface WaveDef
A scripted wave.
after?: number— Seconds after the previous wave started (default 0).clear?: boolean— Wait until the hostile actors of earlier waves are gone (default true).at?: number— Scroll distance (pixels) before it may start.spawns: SpawnSpec[]— What to spawn.


