The pack
pullPin
function pullPin(): Pack<{ pullPin: PullPinApi }>
The pull-pin pack: game.pullPin, Pull the Pin's and Hero Rescue's rules on a physics-2d world per level.
Functions
createPullPin
function createPullPin(level: PullPinLevel, options: PullPinOptions = {}): PullPinGame
Make a game of a level. Throws, listing every problem, on a level validatePullPinLevel refuses.
fillBalls
function fillBalls(fill: PullPinFill): PullPinBall[]
The balls a fill holds: a close-packed grid inside its box, top row first.
validatePullPinLevel
function validatePullPinLevel(level: PullPinLevel, kinds: ReadonlyArray<string> = []): string[]
Check a level and say what is wrong with it, as plain sentences; empty when it can be played.
Constants
pullPinDefaults
const pullPinDefaults: { readonly gravity: 900; readonly pinThickness: 14; readonly pinSpeed: 1400; readonly ballRadius: 11; readonly rockRadius: 22; readonly cupHeight: 90; readonly heroWidth: 36; readonly heroHeight: 56; readonly heroSpeed: 110; readonly enemyWidth: 40; readonly enemyHeight: 52; readonly enemySpeed: 90; readonly crush: 140; readonly settle: 1.5; readonly wallThickness: 16; }
The defaults the level falls back on.
pullPinLevels
const pullPinLevels: { readonly classic: readonly PullPinLevel[]; readonly hero: readonly PullPinLevel[] }
The built-in levels, by box.
Types
PullPinApi
interface PullPinApi
What the pull-pin pack adds to a game: game.pullPin.
create: typeof createPullPin— Make a game of a level.validate: typeof validatePullPinLevel— Check a level; empty when it can be played.fill: typeof fillBalls— The balls a fill holds.levels: typeof pullPinLevels— The built-in levels: the classic box and the hero box.defaults: typeof pullPinDefaults— The defaults every element falls back on.
PullPinBall
interface PullPinBall
A ball.
kind?: PullPinStuff— What it is made of. Default'ball'.x: number— Where it starts, across.y: number— Where it starts, down.radius?: number— Its radius. Default 11 (rocks 22).colour?: string | null— A ball's colour; null (the default) is grey, which takes the colour of a coloured ball it touches.
PullPinContext
interface PullPinContext
What a registered element can reach.
readonly world: World— The physics world.readonly level: Readonly<PullPinLevel>— The level.readonly state: Readonly<PullPinState>— The game's state.readonly balls: ReadonlyMap<number, { body: number; kind: PullPinStuff; colour: string | null; radius: number }>— The balls still in play, by id: their body in the world, stuff and colour.emit(name: string, detail?: unknown): void— Tell the presenter something happened.lose(): void— Lose the game.
PullPinCup
interface PullPinCup
The cup at the bottom: balls that fall into it are counted.
x: number— Its middle, across.y: number— Its top edge.width: number— Its width.height?: number— Its height. Default 90.need: number— How many balls fill it: the level is won when this many coloured balls are in.
PullPinElement
interface PullPinElement
An element of a kind the game registered: kind names it; the rest is its data.
kind: string— The registered kind's name.[key: string]: unknown— The kind's own data.
PullPinElementKind
interface PullPinElementKind<S = unknown>
A kind of element a game adds. Its state must be plain JSON.
create(entry: PullPinElement, ctx: PullPinContext): S— Make an instance's state from its level entry.step?(state: S, ctx: PullPinContext, dt: number): void— Run every fixed step, after the physics and the built-in rules.view?(state: S, ctx: PullPinContext): unknown— What a presenter draws for it.
PullPinEnemy
interface PullPinEnemy
An enemy: walks at the hero when it can see it. Lava or a falling rock kills it.
x: number— Where it stands, across.y: number— Where it stands, down.width?: number— Its width. Default 40.height?: number— Its height. Default 52.speed?: number— How fast it walks. Default 90.
PullPinEvent
type PullPinEvent = | { kind: 'pull'; pin: string } | { kind: 'out'; pin: string } | { kind: 'colour'; ball: number; colour: string } | { kind: 'harden'; ball: number } | { kind: 'cup'; ball: number; count: number } | { kind: 'crush'; enemy: number } | { kind: 'burn'; enemy: number } | { kind: 'loot'; ball: number } | { kind: 'won' } | { kind: 'lost'; cause: 'grey' | 'bomb' | 'hero' | 'stuck' } | { kind: 'element'; element: number; name: string; detail?: unknown }
What happened, for the presenter.
PullPinFill
interface PullPinFill
A box filled with balls on a close-packed grid: how a level holds a chamber full.
kind?: PullPinStuff— What they are made of. Default'ball'.x: number— The box's left edge.y: number— The box's top edge.width: number— The box's width.height: number— The box's height.radius?: number— Each ball's radius. Default 11.colour?: string | null— The balls' colour, or null for grey. Default null.count?: number— How many at most. Default as many as fit.
PullPinGame
interface PullPinGame
A game of one level.
readonly level: Readonly<PullPinLevel>— The level, as played (a copy, fills expanded into balls).readonly state: Readonly<PullPinState>— The state, live.readonly world: World— The physics world, for a registered element or a presenter. Replaced by a restart or a restore.step(dt: number): void— Advance bydtseconds. Once the game is over the physics runs on and the rules stop.pull(pin: string): boolean— Pull a pin by id. False when there is no such pin, it is out already, or the game is over.pinAt(point: { x: number; y: number }, reach?: number): string | null— The pin a tap at this point would pull (its handle, or the bar itself), or null.drain(): PullPinEvent[]— What happened since the last drain, oldest first.view(): PullPinView— Everything to draw.restart(): void— Start the level again.snapshot(): PullPinSave— The game as plain JSON: its moves, replayed on restore.restore(save: PullPinSave): void— Resume a snapshot of this level. Throws on another level's, and leaves the game as it was.
PullPinHero
interface PullPinHero
The hero (Hero Rescue): walks to treasure it can see, and must not touch lava or an enemy.
x: number— Where it stands, across (its middle).y: number— Where it stands, down (its middle).width?: number— Its width. Default 36.height?: number— Its height. Default 56.speed?: number— How fast it walks. Default 110.
PullPinLevel
interface PullPinLevel
A level.
id?: string— Its id, which saves carry.name?: string— A name to show.width: number— The level's width.height: number— The level's height. A ball that falls below it is gone.gravity?: number— Gravity, units per second squared, down. Default 900.walls: PullPinWall[]— The glass.pins: PullPinPin[]— The pins.balls?: PullPinBall[]— Single balls.fills?: PullPinFill[]— Boxes of balls.cup?: PullPinCup— The cup, for the classic game.hero?: PullPinHero— The hero, for the hero game.enemies?: PullPinEnemy[]— Enemies, for the hero game.rules?: PullPinRules— The rule variations.elements?: PullPinElement[]— Elements of kinds the game registered.
PullPinMove
type PullPinMove = { kind: 'advance'; seconds: number } | { kind: 'pull'; pin: string }
A move: time passing, or a pin pulled.
PullPinOptions
interface PullPinOptions
How a game is made.
elements?: Record<string, PullPinElementKind<unknown>>— Element kinds beyond the built-in ones.step?: number— The fixed step the rules and physics run at, seconds. Default 1/120.
PullPinPin
interface PullPinPin
A pin: a bar that holds things up, and slides out along its length when pulled.
id?: string— Its id. Defaultpin-<index>.x: number— Its middle, across.y: number— Its middle, down.length: number— Its length.angle?: number— Its angle, radians: 0 lies across,Math.PI / 2stands up. Default 0.thickness?: number— Its thickness. Default 14.pull?: 1 | -1— Which way it slides out: 1 along its angle (the handle at that end), -1 the other way. Default 1.speed?: number— How fast it slides, units per second. Default 1400.
PullPinRules
interface PullPinRules
The rule variations.
grey?: 'lose' | 'ignore'— A grey ball in the cup:'lose'(the default) or'ignore'(it does not count).bombs?: 'lose' | 'ignore'— A bomb in the cup, or touching the hero:'lose'(the default) or'ignore'.crush?: number— How hard a rock must hit an enemy to crush it, units per second. Default 140.settle?: number— Seconds everything must lie still, with no pin left to pull, before a level that is not won is lost. Default 1.5.
PullPinSave
interface PullPinSave
A saved game.
format: 'phaser-ae-pull-pin'— Always'phaser-ae-pull-pin'.version: 1— The save format's version, 1.level: string— The level's id ('' for a level without one).history: ReturnType<History<unknown, PullPinMove>['snapshot']>— The moves, as the kernel's history saves them.
PullPinState
interface PullPinState
The game's state, to read.
phase: 'playing' | 'won' | 'lost'—'playing','won'or'lost'.cause: 'grey' | 'bomb' | 'hero' | 'stuck' | null— Why a lost game was lost.time: number— Seconds played.cup: number— Balls in the cup.pulled: string[]— The pins pulled, in order.
PullPinStuff
type PullPinStuff = 'ball' | 'bomb' | 'lava' | 'water' | 'stone' | 'rock' | 'gold'
What a ball is made of.
PullPinView
interface PullPinView
Everything a presenter draws, in level units.
walls: PullPinWall[]— The walls, as the level gave them.pins: { id: string; x: number; y: number; length: number; angle: number; thickness: number; handle: { x: number; y: number }; sliding: boolean }[]— Each pin still in the glass: where it is now, its handle's end, and whether it is sliding out.balls: { id: number; x: number; y: number; angle: number; radius: number; kind: PullPinStuff; colour: string | null }[]— Each ball still in play: position, spin, radius, stuff and colour.cup: { x: number; y: number; width: number; height: number; count: number; need: number } | null— The cup and how full it is.hero: { x: number; y: number; width: number; height: number; alive: boolean; facing: 1 | -1; looted: boolean } | null— The hero.enemies: { x: number; y: number; width: number; height: number; alive: boolean; facing: 1 | -1 }[]— The enemies.elements: { kind: string; view: unknown }[]— What each registered element'sviewreturned.
PullPinWall
type PullPinWall = | { kind: 'box'; x: number; y: number; width: number; height: number; angle?: number } | { kind: 'circle'; x: number; y: number; radius: number } | { kind: 'polygon'; points: ReadonlyArray<readonly [number, number]> } /** A wall along a polyline, `thickness` thick: the sides of a glass. */ | { kind: 'chain'; points: ReadonlyArray<readonly [number, number]>; thickness?: number; closed?: boolean }
A static wall. Units are the level's, y down.


