The pack
destructibleCover
function destructibleCover(): Pack<{ destructibleCover: typeof rules; }>
Install the renderer-independent destructible cover API.
Helpers
bunkerPreset
function bunkerPreset( options: { count?: number; worldWidth?: number; /** Top edge of the bunkers. */ y?: number; cellSize?: number; hp?: number; mask?: readonly string[]; /** Left x of the first bunker and gap between bunker left edges; default spreads them evenly. */ left?: number; pitch?: number; } = {}, ): CoverDefinition[]
Evenly spaced bunkers of any authored mask (default: the Space Invaders shield at one unit per pixel).
createDestructibleCover
function createDestructibleCover(definitions: CoverDefinition[] = [])
Create independent damageable masks, or empty cover for a game without shields.
INVADERS_ALIEN_SPLAT
const INVADERS_ALIEN_SPLAT: readonly string[]
The alien-shot explosion stencil (ROM AShotExplo, $1CDC, upright): a ragged 6-wide, 8-tall splat.
INVADERS_PLAYER_SPLAT
const INVADERS_PLAYER_SPLAT: readonly string[]
The player-shot explosion stencil (ROM ShotExploding, $1C91, upright): a ragged 8 x 8 splat.
INVADERS_SHIELD_MASK
const INVADERS_SHIELD_MASK: readonly string[]
The Space Invaders shield, 22 x 16 pixels, upright (from the ROM's ShieldImage at $1D20, which is stored rotated): a flat top with chamfered corners and a notch cut into the base.
Classes
DestructibleCover
class DestructibleCover
Owns mask health and swept contacts through surviving cells; destroyed cells become transparent.
readonly definitions: CoverDefinition[]— The validated definitions (a private copy).constructor(definitions: CoverDefinition[])get revision()— Increments whenever any cell's health changes; renderers can redraw only when it moves.cells(id?: string): CoverCell[]— Surviving cells of one definition or all of them.runs(id?: string): CoverRun[]— Surviving cells merged into horizontal runs of equal material and health.cellHealth(id: string, col: number, row: number)— Health of one cell (0 when destroyed, empty or outside the mask).trace(from: Cell, to: Cell, radius = 0): CoverContact | null— Earliest swept contact for a point/circle approximated as a square of half-sizeradius.traceBox( from: Cell, to: Cell, halfWidth: number, halfHeight: number, ): CoverContact | null— Earliest swept contact for an axis-aligned box of half extentshalfWidth/halfHeightmoving fromfromtoto, through actual surviving cells only, so holes stay transparent.tis 0..1.damage(contact: CoverContact, amount = 1, blastRadius = 0)— Damage the contacted cell byamountand every surviving neighbour whose centre is withinblastRadius.splat(at: Cell, splat: CoverSplat, amount = Infinity)— Stamp an explosion stencil at a world point on every cover it overlaps. A cover cell is damaged when its centre falls inside a set stencil cell.amountdefaults to Infinity (erase), divided by each material's blastResistance; indestructible cells survive.eraseRect( rect: { x: number; y: number; w: number; h: number }, amount = Infinity, )— Damage every cell overlapping a world rectangle, e.g. an invader marching through a bunker.drain()— Take damage events not returned yet.snapshot()— Health of every cell.restore(s: Record<string, number[]>)— Restore health from a snapshot of the same definitions.reset()— Restore every cell to full health.
Types
CoverCell
interface CoverCell extends Cell
One surviving mask cell with its world position (top-left), authored material and current health.
id: string— Owning definition id.col: number— Mask column.row: number— Mask row.size: number— Cell size.material: string— Mask character.hp: number— Remaining health.
CoverContact
interface CoverContact
The earliest swept hit, including mask indices and interpolated contact position.
cover: string— Definition id hit.col: number— Mask column hit.row: number— Mask row hit.t: number— Fraction of the sweep at contact, 0..1.at: Cell— Swept centre at contact.
CoverDamageEvent
interface CoverDamageEvent
One cell's health change.
cover: string— Definition id.col: number— Mask column.row: number— Mask row.remaining: number— Health left.
CoverDefinition
interface CoverDefinition
An arbitrary rectangular material mask positioned in renderer-independent model units.
id: string— Unique id.x: number— Left edge of mask column 0.y: number— Top edge of mask row 0 (y grows downward).cellSize: number— World size of one mask cell.mask: string[]— Equal-width rows;.and space are empty, every other character names a material.materials: Record<string, CoverMaterial>— Material per mask character.
CoverMaterial
interface CoverMaterial
Durability, blast resistance and optional permanent blocking for one mask character.
hp: number— Health of one cell of this material.blastResistance?: number— Divides splash damage from blasts and splats (direct hits are undivided). Default 1.indestructible?: boolean— Blocks traces but never loses health.
CoverRun
interface CoverRun extends Cell
A horizontal run of adjacent surviving cells with one material and one health value, for cheap drawing.
id: string— Owning definition id.row: number— Mask row.col: number— First mask column.length: number— Cells in the run.size: number— Cell size.material: string— Mask character.hp: number— Health shared by the run.
CoverSplat
interface CoverSplat
An explosion stencil. Every non-empty mask cell (any character except . and space) is a pixel of
damage; the stencil is centred on the blast point unless anchor (in stencil cells) says otherwise.
Space Invaders' shot explosions are splats like this: a ragged 8x8 or 6x8 pattern, not a circle and
not a single cell.
mask: string[]— Stencil rows; any character but.and space damages.cellSize?: number— World size of one stencil cell. Default: the damaged cover's own cellSize.anchor?: Cell— Stencil cell placed on the blast point. Default: the stencil centre.


