NET FORGE DOCS

@netforge/engine/rules API reference

Last updated Checked against @netforge/engine 0.2.0View as Markdown

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.

KindCount
Functions39
Constants22
Types27

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;
}

Source: packages/engine/src/rules/idle.ts