@netforge/engine/rules API reference
Net Forge, the open-source multiplayer browser game engine built for AI coding agents, is published on npm under @netforge with source at github.com/netnetdev/net-forge.
Deterministic rules modules for the board genres (tower defense, idle, card battler, monster collector) behind the same SimAdapter seam as the action templates.
import { rulesAdapter } from "@netforge/engine/rules";Generated from packages/engine/src/rules/index.ts by apps/forge-docs/scripts/api.mjs. Signatures are what the TypeScript compiler reports for the current source; long types are cut and say so.
| Kind | Count |
|---|---|
| Functions | 39 |
| Constants | 22 |
| Types | 27 |
Functions
avatarEntity
Entity state for an avatar. Avatar entity ids are the player ids.
function avatarEntity(player: number, a: Avatar): EntityState;Source: packages/engine/src/rules/kit.ts
bestTowerTile
The best free tile for a tower of type (the most road in reach), with a
per-player tie-break and jitter (0 for the sharpest choice). Null when
no free tile reaches the road. Used by the playtest bots and the
client's autopilot alike.
function bestTowerTile(g: CompiledTowerGame, occupied: ReadonlySet<number>, type: number, salt: number, jitter?: number): { tx: number; ty: number; } | null;Source: packages/engine/src/rules/tower.ts
cardsGenre
function cardsGenre(m: GameManifest): RulesGenre<CardsState> & { readonly game: CompiledCards; };Source: packages/engine/src/rules/cards.ts
collectorGenre
function collectorGenre(m: GameManifest): RulesGenre<CollectorState> & { readonly game: CompiledCollector; };Source: packages/engine/src/rules/collector.ts
compileBoard
function compileBoard(def: { size: readonly [number, number]; path: readonly (readonly [number, number])[]; blocked: readonly (readonly [number, number])[]; }): CompiledBoard;Source: packages/engine/src/rules/tower.ts
compileCards
function compileCards(m: GameManifest): CompiledCards;Source: packages/engine/src/rules/cards.ts
compileCollector
function compileCollector(m: GameManifest): CompiledCollector;Source: packages/engine/src/rules/collector.ts
compileIdleGame
function compileIdleGame(m: GameManifest): CompiledIdleGame;Source: packages/engine/src/rules/idle.ts
compileTowerGame
function compileTowerGame(m: GameManifest): CompiledTowerGame;Source: packages/engine/src/rules/tower.ts
effectiveness
Strong (1), weak (-1) or plain (0): each element beats the next in the cycle.
function effectiveness(attack: number, defend: number): number;Source: packages/engine/src/rules/collector.ts
entity
function entity(id: number, kind: number, owner: number, x: number, z: number, yawTurn: number, type: number, hp: number, flags?: number, value?: number, aux?: number): EntityState;Source: packages/engine/src/rules/kit.ts
genreFor
The genre for a game manifest; throws GameDefinitionError lines through the genre's compile.
function genreFor(m: GameManifest): RulesGenre<unknown>;Source: packages/engine/src/rules/genres.ts
hpAt
Max health at a level.
function hpAt(base: number, level: number): number;Source: packages/engine/src/rules/collector.ts
idleGenre
function idleGenre(m: GameManifest): RulesGenre<IdleState> & { readonly game: CompiledIdleGame; policyInput(s: IdleState, player: number, a: Avatar, tick: number, policy: IdlePolicy): RulesInput; };Source: packages/engine/src/rules/idle.ts
isRulesBot
function isRulesBot(p: number): boolean;Source: packages/engine/src/rules/kit.ts
isRulesTemplate
True when a template plays on a board genre (not engine-sim's action world).
function isRulesTemplate(template: string): boolean;Source: packages/engine/src/rules/genres.ts
labelledContent
Ids of the content players read labels for (towers, cards...), in declaration order.
function labelledContent(m: GameManifest): string[];Source: packages/engine/src/rules/genres.ts
marshCenter
A tile's centre in fixed units.
function marshCenter(map: Pick<CompiledMarsh, "w" | "h">, tx: number, ty: number): { x: number; z: number; };Source: packages/engine/src/rules/collector.ts
marshRoute
Tiles from from to goal (excluding from), around blocked tiles; empty when there is no way.
function marshRoute(map: CompiledMarsh, from: number, goal: number): number[];Source: packages/engine/src/rules/collector.ts
marshTile
The tile at a fixed-unit point (marsh centred on the origin), or -1 off the map.
function marshTile(map: Pick<CompiledMarsh, "w" | "h">, x: number, z: number): number;Source: packages/engine/src/rules/collector.ts
plantCost
Salt (milli) the next level of plant i costs at level.
function plantCost(g: CompiledIdleGame, i: number, level: number): number;Source: packages/engine/src/rules/idle.ts
plantSpot
Where plant i stands on a plot (two rows of four), metres from the plot centre.
function plantSpot(i: number): { x: number; z: number; };Source: packages/engine/src/rules/idle.ts
playRules
function playRules<S>(genre: RulesGenre<S>, manifest: GameManifest, opts: HarnessOptions): RulesPlaytest;Source: packages/engine/src/rules/harness.ts
plotCenter
A plot's centre in metres. Rows sit either side of the canal the contract barge waits on.
function plotCenter(slot: number): { x: number; z: number; };Source: packages/engine/src/rules/idle.ts
rand
function rand(r: Rng): number;Source: packages/engine/src/rules/kit.ts
randInt
0..n-1.
function randInt(r: Rng, n: number): number;Source: packages/engine/src/rules/kit.ts
roadCoverage
function roadCoverage(b: CompiledBoard, rangeQ: number): Int32Array;Source: packages/engine/src/rules/tower.ts
roadPoint
Position on the road at progress d (Q units), in Q units with the board's corner at 0, and the heading (u16 turn).
function roadPoint(b: CompiledBoard, d: number): { qx: number; qy: number; yaw: number; };Source: packages/engine/src/rules/tower.ts
rulesAdapter
The SimAdapter for a board genre built from a game manifest.
function rulesAdapter<S>(genre: RulesGenre<S>, manifest: GameManifest, opts: RulesAdapterOptions): SimAdapter<RulesWorld<S>, RulesInput> & { readonly genre: RulesGenre<S>; readonly manifest: GameManifest; };Source: packages/engine/src/rules/adapter.ts
shuffle
Fisher-Yates in place.
function shuffle<T>(r: Rng, list: T[]): T[];Source: packages/engine/src/rules/kit.ts
statAt
A stat at a level: +12% a level.
function statAt(base: number, level: number): number;Source: packages/engine/src/rules/collector.ts
tileAt
The tile under a point in metres, or null off the board.
function tileAt(b: Pick<CompiledBoard, "w" | "h">, x: number, z: number): { tx: number; ty: number; } | null;Source: packages/engine/src/rules/tower.ts
tileCenter
A tile's centre in metres, board centred on the origin.
function tileCenter(b: Pick<CompiledBoard, "w" | "h">, tx: number, ty: number): { x: number; z: number; };Source: packages/engine/src/rules/tower.ts
tileKey
Tile key.
function tileKey(x: number, y: number): number;Source: packages/engine/src/rules/tower.ts
towerGenre
function towerGenre(m: GameManifest): RulesGenre<TowerState> & { readonly game: CompiledTowerGame; };Source: packages/engine/src/rules/tower.ts
wavePreview
What the next wave brings, by creep type (the HUD's preview).
function wavePreview(g: CompiledTowerGame, n: number): { type: number; count: number; }[];Source: packages/engine/src/rules/tower.ts
waveSpawns
The spawns of wave n (1-based), by tick offset into the wave.
function waveSpawns(g: CompiledTowerGame, n: number, tickRate: number): Spawn[];Source: packages/engine/src/rules/tower.ts
works
Per-second rates a works runs at (litres, kg, crystals), before tending.
function works(g: CompiledIdleGame, w: Pick<Works, "levels">, might: number): { pump: number; pan: number; kiln: number; };Source: packages/engine/src/rules/idle.ts
xpNeed
XP to the next level.
function xpNeed(level: number): number;Source: packages/engine/src/rules/collector.ts
Constants
CardAct
Actions (RulesInput.act).
const CardAct: { readonly Play: 1; readonly Attack: 2; readonly End: 3; readonly Draft: 4; };Source: packages/engine/src/rules/cards.ts
CollectorAct
Actions (RulesInput.act).
const CollectorAct: { readonly Pick: 1; readonly Move: 2; readonly Swap: 3; readonly Snare: 4; readonly Flee: 5; readonly Challenge: 6; };Source: packages/engine/src/rules/collector.ts
CreepFlag
Creep flags on the wire.
const CreepFlag: { readonly Slowed: 1; readonly Boss: 2; readonly Dead: 4; readonly Leaked: 8; };Source: packages/engine/src/rules/tower.ts
ENTITY_BASE
Entity ids a genre uses start here (avatars take the player ids below).
const ENTITY_BASE: 65536;Source: packages/engine/src/rules/kit.ts
IDLE_INPUT
const IDLE_INPUT: RulesInput;Source: packages/engine/src/rules/kit.ts
IDLE_MIN_FIRST_EARN
The gate's floor: no earn rule may pay sooner than this after a fresh works starts, with perfect play (seconds).
const IDLE_MIN_FIRST_EARN: 180;Source: packages/engine/src/rules/idle.ts
IDLE_SEATS
const IDLE_SEATS: number;Source: packages/engine/src/rules/idle.ts
IdleAct
Actions (RulesInput.act).
const IdleAct: { readonly Rake: 1; readonly Buy: 2; readonly Ship: 3; };Source: packages/engine/src/rules/idle.ts
LogKind
What a battle log line says happened.
const LogKind: { readonly Hit: 1; readonly Miss: 2; readonly Heal: 3; readonly Guard: 4; readonly Swap: 5; readonly Snared: 6; readonly Slipped: 7; readonly Fled: 8; readonly Won: 9; readonly Fainted: 10; readonly Wiped: 11; readonly Level: 12; readonly Met: 13; readonly Warden: 14; };Source: packages/engine/src/rules/collector.ts
MARSH_TILE
Metres per tile.
const MARSH_TILE: 2;Source: packages/engine/src/rules/collector.ts
MILLI
Milli-units per unit (litres, kg, crystals).
const MILLI: 1000;Source: packages/engine/src/rules/idle.ts
PLOT
Plot layout: four across, two deep, each 12 x 10 m.
const PLOT: { readonly w: 12; readonly d: 10; readonly cols: 4; readonly rows: 2; readonly gapX: 1.5; readonly gapZ: 5; };Source: packages/engine/src/rules/idle.ts
Q
Fixed-point units per tile.
const Q: 256;Source: packages/engine/src/rules/tower.ts
RF
Field indices in RULES_SCHEMA.
const RF: { readonly x: 0; readonly z: 1; readonly yaw: 2; readonly type: 3; readonly hp: 4; readonly flags: 5; readonly value: 6; readonly aux: 7; };Source: packages/engine/src/rules/kit.ts
RULES_BOT_BASE
Seat bots and only them: player ids at 0xff00 and up (engine-sim's BOT_PLAYER_BASE).
const RULES_BOT_BASE: 65280;Source: packages/engine/src/rules/kit.ts
RULES_SCHEMA
The wire schema every board genre shares: position (1/64 m), facing, a type, health, flags and two small values. Units interpolate their position; everything else steps.
const RULES_SCHEMA: EntitySchema;Source: packages/engine/src/rules/kit.ts
rulesInputCodec
50 bits a tick idle, 99 with an action.
const rulesInputCodec: InputCodec<RulesInput>;Source: packages/engine/src/rules/kit.ts
RulesKind
Entity kinds on the wire.
const RulesKind: { readonly Avatar: 1; readonly Unit: 2; readonly Shot: 3; readonly Structure: 4; readonly Pickup: 5; };Source: packages/engine/src/rules/kit.ts
Target
Target codes (RulesInput.b): 0 none, 1 the enemy hero, 2 your hero, 10+i enemy unit i, 20+i your unit i.
const Target: { readonly None: 0; readonly EnemyHero: 1; readonly OwnHero: 2; readonly EnemyUnit: 10; readonly OwnUnit: 20; };Source: packages/engine/src/rules/cards.ts
TILE_M
Metres per tile.
const TILE_M: 2;Source: packages/engine/src/rules/tower.ts
TowerAct
Actions (RulesInput.act).
const TowerAct: { readonly Build: 1; readonly Upgrade: 2; readonly Sell: 3; readonly Ready: 4; };Source: packages/engine/src/rules/tower.ts
UNITS
Fixed-point units per metre for avatars and entities.
const UNITS: 64;Source: packages/engine/src/rules/kit.ts
Types
Avatar
A player's avatar (fixed point). The only state a client predicts.
interface Avatar {
x: number;
z: number;
yaw: number;
cosmetic: number;
flags: number;
}Source: packages/engine/src/rules/kit.ts
CardsState
interface CardsState {
rng: { s: number };
ctx: RulesContext;
tick: number;
stage: "waiting" | "duel" | "draft" | "done";
duelNo: number;
duel: Duel | null;
countdown: number;
players: Map<number, CardPlayer>;
alone: number;
log: LogLine[];
finished: number;
draws: number;
peakBoard: number;
activity: number;
turnsPlayed: number[];
}Source: packages/engine/src/rules/cards.ts
CollectorState
interface CollectorState {
rng: { s: number };
ctx: RulesContext;
tick: number;
dusk: number;
wardenHp: number;
wardenMax: number;
wardenDown: boolean;
wardenHurt: Set<number>;
keepers: Map<number, Keeper>;
activity: number;
battlesWon: number;
catches: number;
wipes: number;
peakBattles: number;
}Source: packages/engine/src/rules/collector.ts
CompiledBoard
interface CompiledBoard {
readonly w: number;
readonly h: number;
readonly path: readonly (readonly [number, number])[];
readonly cum: readonly number[];
readonly length: number;
readonly road: ReadonlySet<number>;
readonly blocked: ReadonlySet<number>;
}Source: packages/engine/src/rules/tower.ts
CompiledCards
interface CompiledCards {
readonly table: CardTableDef;
readonly cards: readonly { readonly id: string; readonly def: CardDef }[];
readonly starter: readonly number[];
readonly pool: readonly number[];
}Source: packages/engine/src/rules/cards.ts
CompiledCollector
interface CompiledCollector {
readonly marsh: MarshDef;
readonly map: CompiledMarsh;
readonly creatures: readonly (CreatureDef & { id: string; el: number; moveIdx: number[] })[];
readonly moves: readonly (MoveDef & { id: string; el: number })[];
readonly starters: readonly number[];
readonly wardenSpecies: number;
readonly pools: readonly { rate: number; pool: { species: number; weight: number; level: readonly [number, number] }[] }[];
}Source: packages/engine/src/rules/collector.ts
CompiledIdleGame
interface CompiledIdleGame {
readonly shiftTicks: number;
readonly tendTicks: number;
readonly start: number;
readonly rakeSalt: number;
readonly rakeTicks: number;
readonly brinePerSalt: number;
readonly saltPerCrystal: number;
readonly packEvery: number;
readonly contract: number;
readonly plants: readonly { readonly id: string; readonly def: PlantDef }[];
}Source: packages/engine/src/rules/idle.ts
CompiledMarsh
interface CompiledMarsh {
readonly w: number;
readonly h: number;
readonly blocked: Uint8Array;
readonly water: Uint8Array;
readonly grass: Uint8Array;
readonly camp: readonly [number, number];
readonly warden: readonly [number, number];
}Source: packages/engine/src/rules/collector.ts
CompiledTower
interface CompiledTower {
readonly id: string;
readonly def: TowerDef;
readonly levels: readonly TowerStats[];
readonly upgradeCost: readonly number[];
}Source: packages/engine/src/rules/tower.ts
CompiledTowerGame
Everything a tower defense game declared, compiled (shared by the room, the harness and the client).
interface CompiledTowerGame {
readonly board: CompiledBoard;
readonly towers: readonly CompiledTower[];
readonly creeps: readonly { id: string; model: string; health: number; speed: number; value: number; damage: number; boss: boolean }[];
readonly lives: number;
readonly gold: number;
readonly prep: number;
readonly breather: number;
readonly share: number;
readonly waveGold: { base: number; perWave: number };
readonly refund: number;
readonly totalWaves: number;
readonly healthGrowth: number;
readonly groups: readonly { type: number; from: number; until: number; every: number; count: number; grow: number; gap: number; delay: number }[];
}Source: packages/engine/src/rules/tower.ts
IdlePolicy
Bot policies: "best" plays the chain as well as the template knows, "human" slower, "clicker" only rakes, "idle" does nothing.
type IdlePolicy = "best" | "human" | "clicker" | "idle";Source: packages/engine/src/rules/idle.ts
IdleState
interface IdleState {
rng: { s: number };
ctx: RulesContext;
tick: number;
players: Map<number, Works>;
contract: number;
filled: boolean;
done: boolean;
activity: number;
}Source: packages/engine/src/rules/idle.ts
LogLine
interface LogLine {
readonly n: number;
readonly kind: number;
readonly who: 0 | 1;
readonly move?: number;
readonly dmg?: number;
readonly eff?: number;
readonly value?: number;
}Source: packages/engine/src/rules/collector.ts
Mon
interface Mon {
species: number;
level: number;
hp: number;
xp: number;
guard: boolean;
}Source: packages/engine/src/rules/collector.ts
Rng
mulberry32 on a state word kept in the genre's state (so a restored state continues the same stream).
interface Rng {
s: number;
}Source: packages/engine/src/rules/kit.ts
RulesAdapterOptions
interface RulesAdapterOptions {
readonly name: string;
readonly version: string;
}Source: packages/engine/src/rules/adapter.ts
RulesCheck
A genre's own line in the playtest gate: a hard check or a scored part.
interface RulesCheck {
readonly ok: boolean;
readonly line: string;
}Source: packages/engine/src/rules/kit.ts
RulesContext
What a genre reads about the players from the adapter.
interface RulesContext {
bonus(player: number, stat: string): number;
isBot(player: number): boolean;
}Source: packages/engine/src/rules/kit.ts
RulesGenre
One board genre. S is its whole authoritative state: integers, arrays
and maps in insertion order, a PRNG word. Factories build one from the
game's manifest (rules/genres.ts).
interface RulesGenre<S> {
readonly template: string;
readonly tickRate: number;
readonly endSeconds: number;
readonly infoEveryTicks: number;
create(seed: number, ctx: RulesContext): S;
spawn(s: S | null, player: number): { x: number; z: number };
moveAvatar(a: Avatar, input: RulesInput): void;
join(s: S, player: number): void;
leave(s: S, player: number): void;
act(s: S, player: number, input: RulesInput, avatar: Avatar, emit: (e: GameEvent) => void): void;
tend?(s: S, player: number, avatar: Avatar, emit: (e: GameEvent) => void): void;
step(s: S, emit: (e: GameEvent) => void): void;
outcome(s: S): RunOutcome | null;
view(s: S, player: number | null): Record<string, unknown>;
entities(s: S, out: EntityState[]): void;
seats?(s: S, humans: number): number;
bot(s: S, player: number, avatar: Avatar, tick: number, skill: number): RulesInput;
stats(s: S): RulesStats;
activity(s: S): number;
checks(run: RulesHarnessRun): RulesCheck[];
progress(run: RulesHarnessRun): number;
}Source: packages/engine/src/rules/kit.ts
RulesHarnessRun
One harness run's numbers, for a genre's checks.
interface RulesHarnessRun {
readonly seconds: number;
readonly players: number;
readonly stats: RulesStats;
readonly runs: { readonly won: number; readonly lost: number };
readonly earned: Readonly<Record<string, number>>;
readonly firstEarnSeconds: number | null;
readonly firstRunSeconds: number | null;
}Source: packages/engine/src/rules/kit.ts
RulesInput
One tick of a player's input.
interface RulesInput {
readonly mx: number;
readonly mz: number;
readonly cx: number;
readonly cz: number;
readonly act: number;
readonly a: number;
readonly b: number;
readonly c: number;
}Source: packages/engine/src/rules/kit.ts
RulesPlaytest
One run of the playtest, with the genre's numbers kept for its checks.
interface RulesPlaytest {
readonly report: HarnessReport;
readonly run: RulesHarnessRun;
}Source: packages/engine/src/rules/harness.ts
RulesStats
Numbers the headless harness reports (HarnessReport), in the genre's own sense.
interface RulesStats {
readonly kills: number;
readonly wave: number;
readonly level: number;
readonly deaths: number;
readonly peakUnits: number;
readonly scorers: number;
readonly topScore: number;
}Source: packages/engine/src/rules/kit.ts
RulesWorld
interface RulesWorld<S = unknown> {
readonly role: "server" | "client";
state: S | null;
readonly avatars: Map<PlayerId, Avatar>;
tick: number;
runTick: number;
phase: "playing" | "ended";
outcome: RunOutcome | null;
endTick: number;
readonly earn: EarnTracker | null;
readonly late: Set<PlayerId>;
progressed: boolean;
readonly upgrades: Map<PlayerId, Map<string, number>>;
readonly paid: Map<PlayerId, Set<string>>;
readonly bots: Set<PlayerId>;
awards: number;
}Source: packages/engine/src/rules/adapter.ts
RunOutcome
type RunOutcome = "won" | "lost";Source: packages/engine/src/rules/kit.ts
TowerState
interface TowerState {
rng: { s: number };
ctx: RulesContext;
tick: number;
wave: number;
phase: "build" | "wave";
countdown: number;
lives: number;
livesMax: number;
livesBought: Map<number, number>;
queue: Spawn[];
waveTick: number;
creeps: Creep[];
towers: Tower[];
players: Map<number, TowerPlayer>;
nextId: number;
kills: number;
leaks: number;
peak: number;
won: boolean;
activity: number;
}Source: packages/engine/src/rules/tower.ts
Works
interface Works {
slot: number;
brine: number;
salt: number;
crystals: number;
made: number;
packs: number;
cutAcc: number;
cut: number;
levels: number[];
lastTend: number;
rakeAt: number;
shipped: number;
rakes: number;
}