SCRAPLINEStandingsResultsStatsTeamsLiveDocsAbout

SCRAPLINE — Game Specification (normative)

2026-08-25. This document is the rulebook: the engine is built from it and disputes are settled by it. GAME-DESIGN.md explains why; this file defines what. Where the two disagree, this file wins and the disagreement is a bug to fix in one of them. All values here are canonical; no other document may restate a number without linking here.

Status: pre-build draft v0.1. Open items are marked DECISION NEEDED.


1. Conventions

2. Entities

2.1 Headquarters (HQ)

Property Value
Footprint 2×2 tiles, impassable
Hit points 500 (single pool; the 25-block display is visualization: block k shatters when HP ≤ 500 − 20·k)
Repair impossible — HP only decreases, ever
Passive income +1 energy/tick to the bank
Action one BUILD per tick (§7.6)
Damage class STRUCTURE (§3.3)

2.2 Chassis

Chassis Cost HP Base speed Slots Collision mass
LIGHT 20 60 2 1 1
MEDIUM 30 100 1 2 2
HEAVY 60 200 1 3 3

2.3 Modules (20 energy each; duplicates allowed up to slot count)

Module Effect
BLASTER Weapon. Range 2, base damage 24/tick. Class multipliers §3.3
LANCE Weapon. Range 3, base damage 16/tick. Class multipliers §3.3
DRILL +5 mining rate/tick, +30 cargo hold
BOOSTER +1 speed. Speed cap: 3
REPAIR Enables RESTORE: 10 HP/tick to one adjacent friendly rig, 1 energy per 2 HP (§7.5)

A rig’s cost = chassis cost + 20 × modules. Its damage class equals its chassis (LIGHT / MEDIUM / HEAVY).

2.4 Entity ids

Ids are positive integers assigned in creation order, starting with HQ A = 1, HQ B = 2, then each team’s opening state in order (team A first, then team B), then per tick as entities are created. When both teams create entities in the same tick, team A’s are assigned first. Ids are never reused. Ids serve only as deterministic tie-breakers; the residual team-A/team-B asymmetry this creates is controlled for by the league’s both-sides pairing.

2.5 Terrain and objects

Object Passable Notes
Ground yes
Asteroid no blocks movement only; never blocks weapons
Energy node no finite pool; mined from adjacent tiles
Scrap pile yes finite pool on a ground tile; rigs may stand on it
Build ghost no under-construction rig; attackable (§7.6)
HQ footprint no

Weapons are never blocked by anything (no line-of-sight system).

3. Canonical constants

3.1 Match

Constant Value
Tick cap 300
Fleet cap (living rigs + pending ghosts, per team) 16
Starting bank 150 energy per team
HQ hit points 500
Trickle income +1 energy/tick per team

3.2 Economy

Constant Value
Mining rate 5 energy/tick per DRILL
Cargo hold 30 per DRILL (rigs without drills have hold 0)
Transfer cap 30 energy per TRANSFER order
Salvage rate scrap pile = floor(0.6 × rig cost) on death
Cargo drop 100% of carried cargo joins the pile on death
Home nodes 2 per side × 600 energy
Center nodes 2 symmetric pairs: 2 × 600 and 2 × 450 (total 2100)
Build time ceil(cost / 10) ticks
Repair rate / price 10 HP per tick / 1 energy per 2 HP (cost ceil(heal/2))
Repair combat lockout target must have taken no damage for the last 5 completed ticks (§7.5)

(Design note: GAME-DESIGN.md describes center nodes as 600/900/600. The 180° symmetry makes a single central node impossible on an even grid, so the 900 is realized as a symmetric 450-pair at the same total. DECISION NEEDED (D1): accept the 450-pair (default) or make the 900 a 2-tile self-paired node straddling the center.)

3.3 Damage multipliers (attacker weapon × defender class)

vs LIGHT vs MEDIUM vs HEAVY vs STRUCTURE (HQ, ghost)
BLASTER (24) ×1.0 → 24 ×0.5 → 12 ×0.25 → 6 ×0.25 → 6
LANCE (16) ×0.5 → 8 ×0.75 → 12 ×1.0 → 16 ×1.0 → 16

Damage per weapon = floor(base × multiplier). A rig with several weapons fires all of them at the same single target in one FIRE order; their damage sums.

3.4 Collision

Constant Value
Collision damage to a surviving (heavier) rig 40, once per collision event
Mass order HEAVY > MEDIUM > LIGHT

4. Match structure

A match is (bot A, bot B, map seed) and is a pure function of those three inputs. Ticks are numbered 1..300. Each tick resolves in the phase order of §6. The match ends immediately when a win condition (§8) is met.

5. Orders

Each tick, each bot returns at most one order per living rig it owns, plus at most one HQ BUILD. Orders are keyed by rig id (the schema makes duplicates impossible). Recognized actions:

MOVE(steps), FIRE(target), MINE(tile), TRANSFER(target, amount), RESTORE(target), IDLE.

Validation happens when the order is read. An order is invalid if it: names an entity that does not exist or is not the bot’s own living rig; has a malformed shape; uses an action the rig lacks the module for (FIRE without a weapon, MINE without a DRILL, RESTORE without REPAIR); exceeds MOVE’s step count (> speed) or uses a non-cardinal step; targets something type-invalid (e.g. TRANSFER to an enemy, RESTORE on a ghost or HQ, FIRE at a friendly — there is no friendly fire). An invalid order becomes IDLE and emits a loud invalid_order replay event. Range/adjacency conditions that depend on positions are checked at resolution, not at validation (a FIRE that ends up out of range is a whiff, not an invalid order).

A rig with no order IDLEs silently. A bot that crashes, exceeds its fuel budget, or returns unparseable output has all its orders for that tick replaced by IDLE (and no BUILD), with a loud bot_fault event. This never forfeits the match.

6. Tick phase order

  1. Snapshot — the engine serializes the full state; both bots receive identical observations (modulo team labeling).
  2. Orders — both bots are called simultaneously (each under its own fuel budget) and their orders validated (§5).
  3. Movement — §7.1, including collisions.
  4. Combat — §7.2. Then the win check (§8); if the match is over, phases 5–7 do not run.
  5. Economy — in this order: MINE (§7.3), TRANSFER (§7.4), RESTORE (§7.5), auto-deposit (§7.3), trickle (+1 per team).
  6. Production — ghosts advance; completed ghosts become rigs (§7.6); new BUILD orders start ghosts.
  7. End of tick — state hash appended to the replay every 32 ticks and on the final tick.

7. Resolution rules

7.1 Movement and collisions

A MOVE order carries 1..speed cardinal steps (N/E/S/W). Diagonal movement does not exist; diagonal repositioning costs two steps.

Movement resolves in 3 sub-steps (the speed cap). In sub-step s, every rig whose order has an s-th step and that has not been stopped attempts to advance one tile. Within one sub-step, resolution is simultaneous, in this order:

  1. Intents: every moving rig’s target tile is computed.
  2. Swaps: two rigs whose moves exchange tiles (A→B’s tile, B→A’s tile) collide (rule 4). This also covers the case where they would “pass through” each other.
  3. Contested tiles: all rigs (2 or more) targeting the same tile collide (rule 4).
  4. Collision rule (mass rule): among the colliding rigs, if there is a unique heaviest chassis, that rig survives, takes 40 damage, and completes its move; every other collider is destroyed. If two or more colliders tie for heaviest, all colliders are destroyed and the contested tile is entered by no one. Collisions are team-blind (allies collide exactly like enemies). A rig destroyed in a collision drops scrap + cargo on the tile it occupied at the start of the sub-step. A survivor that dies of the 40 collision damage (possible only if already wounded to ≤40) is destroyed on its origin tile and enters nothing.
  5. Blocked moves: a rig whose target tile is impassable (asteroid, node, ghost, HQ) or occupied by a rig that is not moving this sub-step bounces: it stays put, its remaining steps this tick are cancelled, and a bounce event is logged. No damage. Bounces cascade: if A’s target is occupied by B and B bounced (or never moved), A bounces too — evaluated to fixpoint. A rig may enter a tile vacated in the same sub-step (chains are legal).
  6. Sub-step deaths merge scrap piles per §7.7 immediately, before the next sub-step.

Standing still is safe from collisions: a stationary rig cannot be rammed (movers bounce off it). The counter to a stationary blocker is FIRE. (DECISION NEEDED (D2): this is as designed (“the mover stays put”), but it makes parked bodies strong at chokes. Alternative: apply the mass rule to movers hitting stationary rigs too. Default: bounce, as designed.)

7.2 Combat

All FIRE orders resolve simultaneously against post-movement positions:

  1. For each firing rig: if the target no longer exists, or the Chebyshev distance from the firer’s tile to the target’s nearest footprint tile exceeds the weapon’s range, the shot whiffs — a loud whiff event, no effect. Range is evaluated per weapon module (a BLASTER+LANCE rig at distance 3 whiffs the blaster and lands the lance).
  2. All landing damage is computed from the pre-combat state and applied at once. Mutual kills are legal; a rig that dies this phase still deals its damage. Overkill is discarded.
  3. Rigs and ghosts at ≤0 HP are destroyed and drop scrap + cargo on their tile (§7.7). HQ damage is subtracted from its pool and added to the attacker’s damage_dealt total.

last_damaged_tick is recorded for every rig that takes ≥1 damage from any source (weapon or collision), for §7.5.

7.3 Mining and deposit

MINE targets a tile that is the rig’s own tile or orthogonally adjacent and contains an energy node or scrap pile. Miners resolve in ascending entity id: each takes min(5 × drills, pool remaining, hold space) from the pool into its cargo. A pool at 0 is removed from the map (nodes: the tile becomes ground and passable; a loud node_exhausted event).

Auto-deposit (no order needed): during phase 5, after RESTORE, every rig orthogonally adjacent to its own HQ footprint moves its entire cargo into the team bank. Unlimited per tick. Deposited energy and trickle both increment the team’s energy_collected counter (starting bank does not).

7.4 Transfer

TRANSFER moves min(requested, 30, carrier cargo, receiver hold space) energy to an orthogonally adjacent friendly rig. Transfers resolve in ascending id of the sending rig, sequentially (later transfers see earlier results). Receivers with hold 0 make the order resolve to 0 (a loud transfer_void event, not an invalid order).

7.5 Restore

RESTORE heals one orthogonally adjacent friendly rig (never a ghost, never the HQ) by min(10, missing HP, 2 × available energy), where available energy = the restorer’s cargo, then the team bank. Cost = ceil(heal/2), drawn cargo-first. Valid only if the target’s last_damaged_tick is at least 6 ticks ago (i.e. it took no damage in the 5 last completed ticks). Multiple restorers may heal the same target in the same tick (ascending restorer id, capped at max HP).

7.6 Build and ghosts

The HQ may issue one BUILD per tick: (chassis, modules, spawn tile). Valid iff: the spawn tile is ground (scrap piles allowed), unoccupied, and orthogonally adjacent to the HQ footprint; the module list fits the chassis slots; the team’s living rigs + pending ghosts < 16; and the bank covers the full cost, which is deducted immediately.

A ghost then occupies the spawn tile: impassable, attackable (damage class STRUCTURE), HP 40, mass — none (movers bounce off it). It completes at the end of ceil(cost/10) Production phases and becomes a rig at full HP on its tile. A destroyed ghost drops scrap = floor(0.6 × full cost) on its tile (its cargo is nil). Ghosts are visible to both bots and the audience from the tick of the BUILD.

7.7 Scrap piles

A death drops scrap = floor(0.6 × cost) plus 100% of carried cargo onto the relevant tile. If the tile already holds a pile, amounts merge into one pile. Piles on a tile under a rig are legal (rigs stand on them). Piles never decay. If a death would drop scrap onto a non-ground tile (impossible under current rules — deaths happen on the dying rig’s own tile, which is always ground), the amount is dropped on the dying rig’s tile regardless.

8. Winning

Checked immediately after Combat (§6 step 4):

  1. Enemy HQ at ≤0 HP and yours above 0 → you win (win_condition: hq_destroyed).
  2. Both HQs at ≤0 HP in the same tick → tiebreak chain (rule 3) applied immediately.
  3. After tick 300’s Combat with both HQs alive — or under rule 2 — the winner is decided by, in order: higher damage_dealt (cumulative HP inflicted on the enemy HQ) → higher energy_collecteddraw (win_condition: draw; league scores it 1–1).

Final scoring fields (in every replay): winner, win_condition (hq_destroyed | damage_tiebreak | energy_tiebreak | draw), final tick, and per team: HQ HP remaining, damage_dealt, energy_collected, rigs living, rigs lost, energy mined / leaked-to-piles, bot_fault count.

9. Map generator

Input: a 64-bit seed. Output: a map, deterministically.

Parameter Range
Board 24×24, 180° rotationally symmetric
HQ A footprint tiles (2,2)–(3,3); HQ B at the rotational image (20,20)–(21,21)
Home nodes 2 per side, 600 each, at Chebyshev 3–5 from the owner’s HQ footprint
Center nodes 2 symmetric pairs (600×2, 450×2), every node tile within Chebyshev 4 of the board center point
Asteroids 4–12 symmetric pairs (8–24 tiles)

Validation (regenerate with the next derived sub-seed until all pass): (a) every passable tile reachable from every other (single connected component); (b) each HQ has ≥6 free orthogonally adjacent spawn tiles; (c) every node has ≥2 passable orthogonally adjacent mining tiles; (d) no node or asteroid orthogonally adjacent to an HQ footprint; (e) shortest passable path between HQ footprints ≥ 14 steps.

The league’s census map set is drawn from this generator, stratified over its parameter space (see LEAGUE-RULES.md §5).

10. Glossary

Term Meaning
Rig A mobile unit: chassis + modules
Ghost A rig under construction, standing on its spawn tile
Hold A rig’s cargo capacity, 30 × drills
Bank A team’s stored energy at the HQ
Pile Scrap and/or dropped cargo lying on a tile
Whiff A FIRE whose target is out of range/gone at resolution
Bounce A move into an occupied/impassable tile: mover stays put
Fault A bot crash, fuel exhaustion, or unparseable reply for one tick
energy_collected Cumulative deposits + trickle (excludes starting bank)
damage_dealt Cumulative HP inflicted on the enemy HQ

11. Clarifications

Where the rules above under-specified an order or a boundary, the engine adopts the reading below. These are normative: they are what the engine implements, and they are frozen for the season along with everything else in this document.

Ref Section Reading the engine implements
C1 §7.1 Per sub-step: blocked moves bounce first (to a fixpoint — off-board, impassable, or a tile whose rig will not vacate it), then collision components (swap pairs and shared targets, unioned) resolve by the mass rule, then everyone left enters. Two rigs walking into one asteroid bounce; they do not collide
C2 §7.1 A collision survivor keeps its remaining steps this tick
C3 §7.2 damage_dealt counts HP actually removed from the enemy HQ
C4 §5, §7.3–7.5 Position/state failures at resolution are loud no-ops: mine_void, transfer_void, restore_void (with a reason), like whiff
C5 §7.5 RESTORE legal iff never damaged or tick − last_damaged_tick ≥ 6; damage earlier in the same tick blocks it
C6 §7.6 BUILD in tick T ⇒ ready_tick = T + ceil(cost/10); rig at the end of that Production; acts from ready_tick + 1. Spawn conditions checked at Production time, after completions; refused builds are not charged
C7 §2.4 Cross-team contention for a nearly-empty pool is the only place ascending-id order changes an outcome; the engine marks it with id_order_asymmetry
C10 §5 FIRE at a non-existent or friendly id is invalid_order; a target that dies during Movement is a whiff
C11 §9 Center-node coordinates lie in 8..=15 on both axes
C15 §9 With the fixed footprints, validation (b) is implied by (d) and (e) always holds (open-board path = 32 steps); both checks are kept