The pack
corridorShooter
function corridorShooter(): Pack<{ corridorShooter: typeof kit; }>
Compose the corridor shooter rules, floor generator and classic preset under game.corridorShooter.
Helpers
corridorAutopilot
function corridorAutopilot(run: CorridorRun, pilot: CorridorPilot, dt: number, speed = 3, turn = 6): CorridorInput
The controls a simple player would give this step: turn to and shoot the nearest enemy it can see; otherwise fetch
the key a locked door needs, then walk to the exit switch and use it, opening doors on the way. speed is cells
per second (default 3), turn radians per second (default 6). For demos, attract modes and tests that prove a
floor can be finished; it is not a strong player.
corridorFloor
function corridorFloor(n: number, options: { seed?: number; skill?: CorridorSkill; floor?: Partial<FloorOptions> } = {}): CorridorConfig
A whole generated floor with the classic set at a skill: generateFloor with the preset's enemies weighted
(guards most, troopers rarest), its items, a gold-key lock and two secrets, corridorLights(), the enemies' damage
scaled, a par of 90 + 30·n seconds and the tally's bonus (10000 a perfect ratio, 500 a second under par). Floor
n (1 up) grows the map and leans towards the tougher enemies. Every field can be changed afterwards; pass
floor: { lights: null } for an unlit map, or other lights for another look.
corridorLights
function corridorLights(): FloorLights
The classic set's lights: warm lamps hung down the middle of every room (one for each 22 floor cells, up to four), one down the corridors every five cells, a gold glow in each secret passage and a green one at the exit switch.
corridorPreset
function corridorPreset(): { weapons: ArsenalConfig; enemies: EnemyDef[]; items: ItemDef[] }
The classic set, in the manner of the early corridor shooters: a knife, a pistol, a machine gun and a rotary gun sharing bullets (99 at most, 8 to start), with damage falling off with distance; guards, hounds, officers and troopers; food, first aid, ammunition clips, four treasures, a gold key, the two big guns and an extra life.
createCorridorRun
function createCorridorRun(config: CorridorConfig): CorridorRun
Start a corridor shooter floor. Throws, naming the problem, on a config it cannot play.
createPilot
function createPilot(): CorridorPilot
A fresh autopilot memory.
cryptFloor
function cryptFloor(n: number, options: { seed?: number; skill?: CorridorSkill; floor?: Partial<FloorOptions> } = {}): CorridorConfig
A generated crypt floor with the crypt set: larger floors than the classic set's, walls in crypt, moss and bone,
skeletons and archers from the start with wraiths and brutes joining, a silver-key lock, three secrets,
cryptLights(), a par of 120 + 40·n seconds and a smaller bonus (5000 a perfect ratio, 200 a second under par).
Every field can be changed afterwards.
cryptLights
function cryptLights(): FloorLights
The crypt set's lights: flickering torches on the walls (one for each 14 floor cells, two to five), some rooms left dark, a torch down the corridors every seven cells, a violet glow in each secret passage and a pale blue one at the exit.
cryptPreset
function cryptPreset(): { weapons: ArsenalConfig; enemies: EnemyDef[]; items: ItemDef[]; player: CorridorPlayerDef }
A second set, to show the rules are not one game's: a crypt crawl. A dagger, a crossbow whose bolts fly, a scattergun of seven pellets and a fire staff whose bursts splash, on three kinds of ammunition; skeletons that swing, archers and wraiths that throw things the player can dodge, and slow, heavy brutes; potions and elixirs up to 150 health, gems and idols, a silver key and a heart for an extra life.
generateFloor
function generateFloor(options: FloorOptions): CellDungeonConfig
Generate a floor for createCorridorRun: rooms and corridors from levelgen's dungeon, each room's walls in its own
picture, doors in the doorways, the exit switch on a wall of the far room, an optional locked door on the only way
there with its key in a room before it, secret rooms behind push-walls holding treasure, and enemies and items
scattered by room; with lights, lamps or torches in the rooms and corridors and glows over the secrets and the exit.
Returns a cell-dungeon map whose things are 'start', the enemy ids (with ':patrol') and the item ids given.
Lights are drawn from their own random stream, so turning them on or changing them leaves the rest of the floor as
it was.
Classes
CorridorRun
class CorridorRun
A floor of a classic corridor shooter in play, built from the mechanic packs: the cell-dungeon map, the
fps-weapons arsenal and the fps-enemies horde. Each step moves the player with sliding collision, uses doors,
secret walls and the exit switch, fires (hitscan pellets against enemies and walls, melee, rockets), lets enemies
hear the shot through open doors, runs the enemies' attacks, flies projectiles and collects pickups, scoring
treasure and kills and giving extra lives. A death costs a life and respawn restarts the floor; the exit switch
ends it with its tally. Get one from createCorridorRun.
map!: CellDungeon— The map, live: ask it for walls, doors and rays to draw.arsenal!: Arsenal— The arsenal, live.horde!: Horde— The enemies, live.constructor(config: CorridorConfig)get status(): 'playing' | 'dead' | 'complete' | 'over'—'playing','dead'(waiting forrespawn),'complete'(the exit switch was used) or'over'(no lives left).get player(): CorridorPlayer— The player (a copy).get stats(): CorridorStats— The floor's numbers so far.get tally(): CorridorTally | null— The last finished floor's tally, or null before the first exit.pickups(): CorridorItem[]— The pickups still lying about.flying(): CorridorProjectile[]— What is flying.item(id: string): ItemDef | undefined— An item kind's definition.respawn(): boolean— After a death with lives left: the floor starts again with a fresh arsenal; the score is kept.nextFloor(config: CorridorConfig): boolean— After the exit switch: go on to another floor, as the classic games do. The score, lives, health and arsenal (guns, ammunition, the weapon in hand) carry over; keys stay behind.configis the new floor's: its map, enemies, items, par and player limits. Itsweaponsmust name every gun the arsenal holds, which the same set always does. Returns false, changing nothing, unless the floor is complete; throws on a config it cannot play.step(dt: number, input: CorridorInput): CorridorEvent[]— Run the floor on bydtseconds (0 to 0.25) with this step's controls.
Types
CorridorConfig
interface CorridorConfig
A corridor shooter game: a floor and the things on it.
map: CellDungeonConfig— The floor: acell-dungeonmap whose things are'start', enemy kinds (with':patrol'to patrol) and item ids.weapons: ArsenalConfig— The weapons and ammunition.enemies: EnemyDef[]— The enemy kinds.items: ItemDef[]— The pickups.player?: CorridorPlayerDef— The player.damageScale?: number— Multiplies enemy damage, 0 to 10; default 1.maxAttackers?: number— Most enemies aiming at once; default 3.par?: number— Par time for the floor in seconds; default 0, none.bonus?: { perfect?: number; parPerSecond?: number }— The bonus the tally pays when the exit is used:perfectpoints for each of kills, secrets and treasure at 100 per cent, andparPerSecondfor each whole second under par. Default none.sounds?: CorridorSounds— Sounds for doors, secrets, the exit and the player; default none.infighting?: boolean— Enemies hurt by another kind turn on it; default true.seed?: number— Seed, 0 to 4294967295; default 1.
CorridorEvent
type CorridorEvent = | { type: 'shot'; weapon: string; pellets: number } | { type: 'hit'; enemy: string; damage: number; dist: number } | { type: 'wall-hit'; x: number; z: number } | { type: 'hurt'; damage: number; from: string } | { type: 'picked-up'; item: string; id: string } | { type: 'door'; x: number; z: number; opening: boolean } | { type: 'locked'; key: string } | { type: 'secret'; x: number; z: number } | { type: 'exit'; tally: CorridorTally } | { type: 'extra-life'; lives: number } | { type: 'died'; lives: number } | { type: 'enemy'; event: HordeEvent } | { type: 'projectile-hit'; id: string; x: number; z: number } | { type: 'sound'; sound: string; x: number; y: number; z: number }
What happened in a step, besides the map's and the enemies' own events.
CorridorInput
interface CorridorInput
One step's controls.
move: { x: number; z: number }— Where the player wants to move this step, in cells: an offset from where they stand.yaw: number— The engine's yaw the player looks along.fire: boolean— Whether the trigger is held.use?: boolean— Use the door, secret wall or switch in front (a press).select?: string— Switch to this weapon.cycle?: 1 | -1— Switch to the next (1) or previous (−1) weapon.
CorridorItem
interface CorridorItem
A thing lying on the floor.
id: string— Unique id.item: string— Its item kind's id.x: number— Position in cells.z: number— Position in cells.
CorridorPilot
interface CorridorPilot
An autopilot's memory between steps.
route: { x: number; z: number }[]— The cells it is walking, next first.replan: number— Seconds until it plans again.goal: string— What it is heading for:'key','exit','enemy'or'supplies'.stuck: number— Seconds it has made no progress, to try another way.held: boolean— Whether it held the trigger last step: a one-shot weapon needs it let go between shots.target: { x: number; z: number } | null— The exact point it walks to once the route runs out (an item off a cell's centre), or null.
CorridorPlayer
interface CorridorPlayer
The player now.
x: number— Position in cells.z: number— Position in cells.yaw: number— The engine's yaw.health: number— Health.lives: number— Lives left (not counting this one).score: number— Points.keys: string[]— Keys carried.alive: boolean— Whether they are alive.
CorridorPlayerDef
interface CorridorPlayerDef
The player's numbers.
health?: number— Health at the start of a floor, 1 to 1000; default 100.maxHealth?: number— Most health, 1 to 1000; default 100.lives?: number— Lives at the start, 0 to 99; default 3.radius?: number— Body radius in cells, 0.1 to 0.45; default 0.3.extraLifeEvery?: number— Points for each extra life, 0 for none; default 40000.
CorridorProjectile
interface CorridorProjectile
Something flying: a player's rocket or an enemy's fireball.
id: string— Unique id.from: string— Who threw it:'player'or an enemy's id.x: number— Position in cells.z: number— Position in cells.yaw: number— The engine's yaw it flies along.speed: number— Cells per second.radius: number— Radius in cells.damage: number— Damage on a direct hit.splash?: { radius: number; damage: [number, number] }— Splash around where it lands.
CorridorSkill
type CorridorSkill = 'easy' | 'normal' | 'hard' | 'brutal'
How hard: enemy damage scale and how many enemies a floor has.
CorridorSounds
interface CorridorSounds
Sounds the run asks for, by name, as sound events with where they happen; play them with a positional audio pack.
Enemies' sounds come from their own sounds, weapons' from their sound, pickups' from the item's. Any may be
left out.
door?: string— A door starts opening.locked?: string— A locked door refuses.secret?: string— A secret wall starts sliding.exit?: string— The exit switch is used.hurt?: string— The player is hurt.death?: string— The player dies.extraLife?: string— An extra life.nothing?: string— Use with nothing to use.
CorridorStats
interface CorridorStats
A floor's numbers, for the tally screen.
kills: number— Enemies killed.killsTotal: number— Enemies there were.secrets: number— Secret walls pushed.secretsTotal: number— Secret walls there were.treasure: number— Treasure picked up.treasureTotal: number— Treasure there was.time: number— Seconds on the floor.par: number— Par time, or 0.
CorridorTally
interface CorridorTally
A finished floor's tally, for the screen between floors.
kills: number— Enemies killed, whole per cent (100 when the floor had none).secrets: number— Secrets found, whole per cent (100 when the floor had none).treasure: number— Treasure taken, whole per cent (100 when the floor had none).time: number— Seconds taken, whole.par: number— The par, seconds (0 for none).bonus: number— Points the bonus added to the score.
FloorGlow
interface FloorGlow
A single light the generator places over something (a secret closet, the exit). Every field has a default.
color?: string— Colour, CSS.intensity?: number— Brightness, 0 to 1000, incell-dungeon's units.radius?: number— Reach in cells, 0.1 to 128.flicker?: number— Flicker, 0 to 1.height?: number— Height above the floor in cells, 0 to 16.
FloorLights
interface FloorLights
The lights a generated floor gets, written into the map's lights: some in every room, some along the corridors, a
glow over each secret closet and one at the exit switch. Every field has a default; the presets choose lamps for the
classic set and torches for the crypt.
kind?: CellLightKind— What the rooms' and corridors' lights are:'lamp'(hung under the ceiling),'torch'(on a wall) or'glow'; default'lamp'.perRoom?: { cells?: number; min?: number; max?: number }— How many lights a room gets: one for everycellsfloor cells (1 to 400), at leastminand at mostmax(0 to 16); default 24, 1 and 4.dark?: number— The chance a room is left dark, 0 to 1; default 0. The start and exit rooms are always lit.colors?: string[]— Colours, one picked per room (and per corridor light); default['#ffe2b0'].intensity?: number— Brightness of each, 0 to 1000; default 2 for lamps, 1.6 for torches, 1.2 for glows.radius?: number— Reach in cells, 0.1 to 128; default fitted to the room (half its longer side plus 2, at most 7), 3.5 in corridors.flicker?: number— Flicker, 0 to 1; default 0 for lamps and glows, 0.45 for torches.height?: number— Height above the floor in cells, 0 to 16; default 0.85 for lamps, 0.62 for torches, 0.5 for glows.corridor?: number— A light every this many cells along the corridors, 2 to 64, or 0 for none; default 7.secret?: FloorGlow | null— A glow over each secret closet, or null for none; default a soft gold one.exit?: FloorGlow | null— A glow in front of the exit switch, or null for none; default a green one.
FloorOptions
interface FloorOptions
What to generate. Only seed is required.
seed: number— Seed, 0 to 4294967295; the same options give the same floor.width?: number— Width in cells, 16 to 96; default 40.height?: number— Height in cells, 16 to 96; default 40.enemies?: { id: string; weight: number; patrol?: number }[]— Enemy kinds and how often each appears;patrolis the chance one walks a beat. Default none.density?: number— Enemies per room on average, 0 to 8; default 1.5.items?: { health?: string[]; ammo?: string[]; treasure?: string[]; weapon?: string; life?: string }— Item ids to scatter by kind. Each list may be empty.textures?: string[]— Wall pictures, one per room style, 1 to 23 of them; default['stone', 'wood', 'brick'].doorTexture?: string— The doors' picture; default'door'. A locked door's isdoor-<key>.exitTexture?: string— The exit switch's picture; default'switch', the nameretro-textures' themes give a switch.lock?: { item: string; key: string } | null— A locked door on the way to the exit, and its key, by item id and key name; null or absent for none.secrets?: number— Secret rooms behind push-walls, 0 to 6; default 2.lights?: FloorLights | null— Lights for the rooms, corridors, secrets and exit, or null or absent for an unlit map.
ItemDef
interface ItemDef
What a pickup does.
id: string— Unique id; the map places it by this name.kind: 'health' | 'ammo' | 'weapon' | 'treasure' | 'key' | 'life'—'health','ammo','weapon','treasure','key'or'life'.amount?: number— Health points, ammunition rounds (weapons: the rounds that come with it), or 0.ammo?: string— Ammo: the ammunition type.weapon?: string— Weapon: the weapon's id.key?: string— Key: the key's name, as doors name it.score?: number— Points for picking it up; default 0.upTo?: number— Health: only taken while health is below this; default the player's maximum.sound?: string— A sound to play when it is picked up, by name; default none.


