puzzlescript
Version:
Play PuzzleScript games in your terminal!
249 lines (248 loc) • 8.67 kB
TypeScript
import { GameData } from '.';
import { Cell, CellSaveState } from './engine';
import { GameMetadata } from './models/metadata';
import { A11Y_MESSAGE } from './models/rule';
import { GameSprite } from './models/tile';
import { Soundish } from './parser/astTypes';
export declare type Optional<T> = T | null;
export declare enum RULE_DIRECTION {
UP = "UP",
DOWN = "DOWN",
LEFT = "LEFT",
RIGHT = "RIGHT",
ACTION = "ACTION",
STATIONARY = "STATIONARY",
RANDOMDIR = "RANDOMDIR"
}
export declare enum INPUT_BUTTON {
UP = "UP",
DOWN = "DOWN",
LEFT = "LEFT",
RIGHT = "RIGHT",
ACTION = "ACTION",
UNDO = "UNDO",
RESTART = "RESTART"
}
export declare enum RULE_DIRECTION_RELATIVE {
RELATIVE_LEFT = "<",
RELATIVE_RIGHT = ">",
RELATIVE_UP = "^",
RELATIVE_DOWN = "V"
}
export declare type RULE_DIRECTION_WITH_RELATIVE = RULE_DIRECTION | RULE_DIRECTION_RELATIVE;
export declare function _flatten<T>(arrays: T[][]): T[];
export declare function _debounce(callback: () => any): () => void;
export declare function opposite(dir: RULE_DIRECTION): RULE_DIRECTION.UP | RULE_DIRECTION.DOWN | RULE_DIRECTION.LEFT | RULE_DIRECTION.RIGHT;
export declare function setEquals<T>(set1: Set<T>, set2: Set<T>): boolean;
export declare function setAddAll<T>(setA: Set<T>, iterable: Iterable<T>): Set<T>;
export declare function setIntersection<T>(setA: Set<T>, setB: Iterable<T>): Set<T>;
export declare function setDifference<T>(setA: Set<T>, setB: Iterable<T>): Set<T>;
export declare function nextRandom(maxNonInclusive: number): number;
export declare function resetRandomSeed(): void;
export declare function setRandomValuesForTesting(values: number[]): void;
export declare function clearRandomValuesForTesting(): void;
export declare function getRandomSeed(): number;
/**
* A `DEBUGGER` flag in the game source that causes the evaluation to pause.
* It works like the
* [debugger](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/debugger)
* keyword in JavaScript.
*
* **Note:** the game needs to run in debug mode (`node --inspect-brk path/to/puzzlescript.js` or `npm run play-debug`)
* for this flag to have any effect.
*
* This string can be added to:
*
* - A Rule. Example: `DEBUGGER [ > player | cat ] -> [ > player | > cat ]`
* - A bracket when the condition is updated: `[ > player | cat ] DEBUGGER -> [ > player | > cat ]`
* - A bracket when it is evaluated: `[ > player | cat ] -> [ > player | > cat ] DEBUGGER`
* - A neighbor when the condition is updated: `[ > player DEBUGGER | cat ] -> [ > player | > cat ]`
* - A neighbor when it is evaluated: `[ > player | cat ] -> [ > player | > cat DEBUGGER ]`
* - A tile when the condition is updated: `[ > player | DEBUGGER cat ] -> [ > player | > cat ]`
* - A tile when it is matched: `[ > player | cat ] -> [ > player | DEBUGGER > cat ]`
*/
export declare enum DEBUG_FLAG {
BREAKPOINT = "DEBUGGER",
/**
* Pause when a Cell causes an entry to be removed from the set of matches for this rule/bracket/neighbor/tile
*/
BREAKPOINT_REMOVE = "DEBUGGER_REMOVE"
}
export interface ICacheable {
toKey: () => string;
}
export declare function spritesThatInteractWithPlayer(game: GameData): Set<GameSprite>;
export declare function pollingPromise<T>(ms: number, fn: () => T): Promise<T>;
export interface TypedMessageEvent<T> extends MessageEvent {
data: T;
}
export declare enum MESSAGE_TYPE {
PAUSE = "PAUSE",
RESUME = "RESUME",
TICK = "TICK",
PRESS = "PRESS",
CLOSE = "CLOSE",
ON_GAME_CHANGE = "ON_GAME_CHANGE",
ON_PRESS = "ON_PRESS",
ON_MESSAGE = "ON_MESSAGE",
ON_MESSAGE_DONE = "ON_MESSAGE_DONE",
ON_LEVEL_LOAD = "ON_LEVEL_LOAD",
ON_LEVEL_CHANGE = "ON_LEVEL_CHANGE",
ON_WIN = "ON_WIN",
ON_SOUND = "ON_SOUND",
ON_TICK = "ON_TICK",
ON_PAUSE = "ON_PAUSE",
ON_RESUME = "ON_RESUME"
}
export interface CellishJson {
colIndex: number;
rowIndex: number;
spriteNames: string[];
}
export interface SerializedTickResult {
changedCells: CellishJson[];
soundToPlay: Optional<number>;
messageToShow: Optional<string>;
didWinGame: boolean;
didLevelChange: boolean;
wasAgainTick: boolean;
a11yMessages: A11Y_MESSAGE<CellishJson, string>;
}
export declare type WorkerMessage = {
type: MESSAGE_TYPE.ON_GAME_CHANGE;
code: ArrayBuffer;
level: number;
checkpoint: Optional<CellSaveState>;
} | {
type: MESSAGE_TYPE.PRESS;
button: INPUT_BUTTON;
} | {
type: MESSAGE_TYPE.CLOSE;
} | {
type: MESSAGE_TYPE.PAUSE;
} | {
type: MESSAGE_TYPE.RESUME;
} | {
type: MESSAGE_TYPE.ON_MESSAGE_DONE;
};
export declare type WorkerResponse = {
type: MESSAGE_TYPE.ON_GAME_CHANGE;
payload: ArrayBuffer;
} | {
type: MESSAGE_TYPE.TICK;
payload: SerializedTickResult;
} | {
type: MESSAGE_TYPE.PRESS;
payload: void;
} | {
type: MESSAGE_TYPE.CLOSE;
payload: void;
} | {
type: MESSAGE_TYPE.PAUSE;
payload: void;
} | {
type: MESSAGE_TYPE.RESUME;
payload: void;
} | {
type: MESSAGE_TYPE.ON_PRESS;
direction: INPUT_BUTTON;
} | {
type: MESSAGE_TYPE.ON_MESSAGE;
message: string;
} | {
type: MESSAGE_TYPE.ON_LEVEL_LOAD;
level: number;
levelSize: Optional<{
rows: number;
cols: number;
}>;
} | {
type: MESSAGE_TYPE.ON_LEVEL_CHANGE;
level: number;
cells: Optional<CellishJson[][]>;
message: Optional<string>;
} | {
type: MESSAGE_TYPE.ON_WIN;
} | {
type: MESSAGE_TYPE.ON_PAUSE;
} | {
type: MESSAGE_TYPE.ON_RESUME;
} | {
type: MESSAGE_TYPE.ON_SOUND;
soundCode: number;
} | {
type: MESSAGE_TYPE.ON_TICK;
changedCells: CellishJson[];
checkpoint: Optional<CellSaveState>;
hasAgain: boolean;
a11yMessages: Array<A11Y_MESSAGE<CellishJson, string>>;
};
export interface PuzzlescriptWorker {
postMessage(msg: WorkerMessage, transferrables?: Transferable[]): void;
addEventListener(type: 'message', handler: (msg: {
data: WorkerResponse;
}) => void): void;
}
export declare const shouldTick: (metadata: GameMetadata, lastTick: number) => boolean;
export interface Cellish {
colIndex: number;
rowIndex: number;
getSprites(): GameSprite[];
getSpritesAsSet(): Set<GameSprite>;
getWantsToMove(sprite: GameSprite): Optional<RULE_DIRECTION>;
}
export interface GameEngineHandler {
onGameChange(gameData: GameData): void;
onPress(dir: INPUT_BUTTON): void;
onMessage(msg: string): Promise<void>;
onLevelLoad(level: number, newLevelSize: Optional<{
rows: number;
cols: number;
}>): void;
onLevelChange(level: number, cells: Optional<Cellish[][]>, message: Optional<string>): void;
onWin(): void;
onSound(sound: Soundish): Promise<void>;
onTick(changedCells: Set<Cellish>, checkpoint: Optional<CellSaveState>, hasAgain: boolean, a11yMessages: Array<A11Y_MESSAGE<Cell, GameSprite>>): void;
onPause(): void;
onResume(): void;
}
export interface GameEngineHandlerOptional {
onGameChange?(gameData: GameData): void;
onPress?(dir: INPUT_BUTTON): void;
onMessage?(msg: string): Promise<void>;
onLevelLoad?(level: number, newLevelSize: Optional<{
rows: number;
cols: number;
}>): void;
onLevelChange?(level: number, cells: Optional<Cellish[][]>, message: Optional<string>): void;
onWin?(): void;
onSound?(sound: Soundish): Promise<void>;
onTick?(changedCells: Set<Cellish>, checkpoint: Optional<CellSaveState>, hasAgain: boolean, a11yMessages: Array<A11Y_MESSAGE<Cellish, GameSprite>>): void;
onPause?(): void;
onResume?(): void;
}
export declare class EmptyGameEngineHandler implements GameEngineHandler {
private subHandlers;
constructor(subHandlers?: GameEngineHandlerOptional[]);
onGameChange(gameData: GameData): void;
onPress(dir: INPUT_BUTTON): void;
onMessage(msg: string): Promise<void>;
onLevelLoad(level: number, newLevelSize: Optional<{
rows: number;
cols: number;
}>): void;
onLevelChange(level: number, cells: Optional<Cellish[][]>, message: Optional<string>): void;
onWin(): void;
onSound(sound: Soundish): Promise<void>;
onTick(changedCells: Set<Cellish>, checkpoint: Optional<CellSaveState>, hasAgain: boolean, a11yMessages: Array<A11Y_MESSAGE<Cellish, GameSprite>>): void;
onPause(): void;
onResume(): void;
}
export interface Engineish {
setGame(code: string, level: number, checkpoint: Optional<CellSaveState>): void;
dispose(): void;
pause?(): void;
resume?(): void;
press?(dir: INPUT_BUTTON): void;
tick?(): void;
}