Rulebook
Project: Nova is a programming strategy game about preparing a hostile planet for human colonization. Players do not directly command units during play. Instead, each player writes android programs, uploads them as scripts, launches androids, and studies the resulting simulation to improve later script versions.
This rulebook is written for players and coding agents that want to play the current game.
Every number in this document is a default. They are all rules — data, not code — and a host can retune any of them for a given game. Each one below is named with the rule it comes from, such as rules.android.cargoCapacity, and an Android reads the resolved values at run time from the rules global. See Rules for the whole table and how to change it. Where this rulebook states a number, read it as “the shipped default”; where a script needs the truth, read rules.
1. Objective
Only one player can become the planet’s founding colony authority.
Colony readiness is scored continuously from the current world state. Players prepare a viable colony through completed infrastructure, secured material, environmental preparation, and reliable resource supply. Discovery and other information-gathering are useful for play, but do not themselves earn readiness points.
A good android strategy should focus on:
- finding scattered earth-launched material
- building chargers to increase android capacity
- building storage and resource infrastructure
- avoiding or cleaning hazards
- keeping androids charged and alive
- leaving useful broadcasts and recordings for future script improvements
1.1 When the Humans Arrive
A game may have an arrival date: the round the colonists are expected to land on,
set by rules.match.finalRound and read by a script as the finalTurn global.
It is a deadline, not a mechanic. Nothing happens to the world on that round — the engine does not stop the game or score it differently, because it is the host that decides how many rounds to run. What it changes is how an Android should play: a colony that will be inspected on round 20 is worth building differently from one with no arrival date, and readiness banked after the humans land is readiness that arrived too late to count.
Two ways to play set it for you, because in both the round count is a real deadline rather than a suggestion — neither can be continued once it has run:
- A peer match,
nova host --rounds 20or Match › Host in the browser lab. The arrival is the round count the host offered. - A run in the browser lab, where the arrival is the round count in the Run panel.
A game created with nova create-game has no arrival unless its rules file gives
it one, because nova run can always be asked for more rounds.
2. Core Loop
Players repeat this loop:
- Write or update android code.
- Upload the code as an android script version.
- Launch androids using available charger capacity.
- Run the simulation.
- Review the recording, messages, and world state.
- Improve future android behavior.
Androids are autonomous once launched. A script is a module whose default export is its turn function, called once per round and returning that round’s action:
const turn: AndroidTurn = () => ({ type: 'android.move', direction: 'east' });
export default turn;
The turn function runs with these globals:
androidId— the id of the android currently taking its turnworld— the fogged world snapshot visible to the script runnerrules— every number this game is played with (see Rules)turn— the round now being played, counting from 1finalTurn— the round the humans are expected to land on, orundefinedwhen no arrival is scheduled. Nothing happens on that round mechanically; it is the deadline the colony is being built to, and a script that reads it can pace itself against the time it has left
The scripts stored in a game are the compiled result. A factory Android is written in TypeScript, across as many files as it needs, and the CLI compiles and bundles it into one script on upload. The action shapes below are what the turn function returns.
3. World
The planet is a rectangular grid of tiles.
Each tile has:
position:{ x, y }composition: materials and hazards in the groundscattered: loose earth-launched material on the surface- optional
revealedBy: player ids that can currently see the tile
The board’s size is rules.world.width x rules.world.height — 12 x 12 by default — and a script can read it even though the tiles themselves are fogged.
Tile composition is generated randomly when a new map is created, from rules.world.generation. Composition is not the same as loose material. Composition represents things in the ground or environmental conditions.
Current composition fields:
ore— natural material that extractors can harvestwater— natural material that extractors can harvestacid— environmental hazard and extractable/processable materialradiation— environmental hazard
Current scattered material fields:
metalelectronicspolymerorewateracidCanister
What a fresh map actually scatters is narrower than that, and deliberately: metal and electronics, and nothing else. Polymer is never scattered — Earth sent none, and the only polymer on the planet is polymer a colony made, out of an acid processing plant. The rest of the fields exist because material can reach the ground other ways: salvage returns it, and a hand-authored scenario can put anything anywhere.
Scattered material can be collected directly by androids. Composition cannot be collected directly; it requires buildings or special mechanics.
A tile can contain at most one building or construction site.
4. Players
Players are competitors. There are no formal alliances, shared ownership rules, shared victory, or safe teammate permissions.
A player is created when they first upload a script or launch an android. Each player is guaranteed an initial charger. Initial chargers are completed, owned by that player, and cannot be salvaged.
5. Androids
Androids are programmable autonomous units.
Current android fields include:
idownerIdscriptIdpositionbatteryhealthactive- optional
cargo memory— private persistent working state, limited torules.android.memoryLimitcharacters (4,096)recording— player-facing persistent log, limited torules.android.recordingLimitcharacters (16,384)
Androids can currently:
- move one tile orthogonally
- collect scattered material from their current tile
- carry up to
rules.android.cargoCapacitytotal material units (12) - start and continue construction
- charge on owned chargers
- deposit to and withdraw from storage-capable owned buildings
- salvage buildings
- repair an owned damaged building
- broadcast public messages
- clean acid from adjacent tiles if their owner has an acid processing plant
- launch another android of the same owner while standing on an owned completed charger
- dismantle themselves, or another android of the same owner while standing on an owned completed charger
Androids have health. They lose a small amount of health over time. Environmental hazards can damage them faster.
At round end:
- every android loses
rules.android.decayPerRoundhealth from ordinary decay (0.15) - radiation damages androids by
radiation * rules.android.radiationDamagePerPoint(0.75) - acid damages androids by
acid * rules.android.acidDamagePerPoint(1.5)
Hazards are not scenery. Four points of acid is six health a round, so a route across the flats is a decision with a cost, and a tile nobody can cross is a wall an Android can use.
A failed turn — a refused action, a script error, an exhausted turn budget — costs the android rules.android.failedTurnHealthPenalty health (10) on top of the round it lost. One bad edge case is survivable; a script that keeps making the same mistake wears its android out.
Androids with health at or below 0, or battery at or below 0, are destroyed at round end. A destroyed android is deactivated rather than removed: it takes no further turns and no longer holds charger capacity, but it stays in the world as a wreck, so its owner can still read the memory and recording it left behind. Deactivated androids take no further decay or hazard damage, and are not drawn on the board.
6. Chargers and Android Capacity
Chargers determine android deployment capacity.
A player’s active android cap is the sum of rules.buildings[type].androidCapacity over their completed buildings. Only chargers carry capacity by default, and each carries 2.
Examples:
- 1 charger allows 2 active androids
- 3 chargers allow 6 active androids
The starting charger therefore allows a second android from the first turn, and an android standing on it can launch that sibling itself. Doubling the hands before doing anything else is a real opening — and so is deciding not to.
A player always has at least their initial charger. Initial chargers are placed on non-overlapping tiles when the world is set up.
If a non-initial charger is destroyed or salvaged, the player’s deployment cap immediately decreases. Existing androids are not automatically destroyed, but the player cannot launch more androids until their active android count is below the current cap.
Launching is currently immediate if capacity is available. Launch delay is planned but not implemented yet.
A player is not the only one who can spend that capacity. An android standing on one of its owner’s completed chargers can launch a sibling itself with android.launch, and it is held to the same cap: the launch is refused unless the owner’s active android count is below their completed charger count. Because the launching android is itself active, a player at their cap cannot launch another until something frees capacity — a dismantle, a wreck, or another charger.
7. Scripts, Launching, and Dismantling
Players may upload improved script versions during the game. Existing androids do not automatically update to a new script.
To use a new script version, a player must launch a new android with that script id, or dismantle/free capacity and launch a replacement.
Dismantling is voluntary. It deactivates the android and frees charger capacity. It currently returns no material. As with any destroyed android, the dismantled one stays in the world as a wreck.
An android on one of its owner’s completed chargers can also dismantle another android of the same owner, so a fleet can retire and replace its own members without the player intervening. An android can never dismantle another player’s android, and can never name itself as the target — self-destruction is the untargeted form of the same action.
7.1 What a Turn May Spend
A turn runs under three budgets, and they are rules like any other, so a script can read its own allowance from rules.script:
| Rule | Default | What exhausts it |
|---|---|---|
rules.script.fuel | 10,000 | Infinite loops, and searches that never terminate |
rules.script.timeoutMs | 1,000 | Work that is slow without being long, such as allocating relentlessly |
rules.script.memoryBytes | 16 MB | Building enormous arrays or strings |
Exceeding any of them is a failed turn: it costs the round and rules.android.failedTurnHealthPenalty health, and leaves the next turn unaffected. fuel is counted in interpreter ticks rather than milliseconds, so a script is cut off at the same point on every machine — which is what lets two peers replay the same match and agree on the outcome. A normal bot is nowhere near any of these; the shipped starter builder finishes a turn without spending a single tick.
The call stack is bounded too, at 128 KB, but it is not a rule: its ceiling is a property of the sandbox build rather than a design choice.
8. Android Action API
An android script’s turn function must return one android event. The engine adds androidId automatically. Every action may also include optional memory and recording string fields. They replace the Android’s previous values as part of the same turn; they are not separate actions. Scripts can read both values from their Android in world.androids. memory is for operational state across turns. recording is the log available to the player after the Android is deactivated.
Because both fields are written as part of the action, a rejected action takes them with it: if the action is refused — moving outside the map, building without the material, writing past the memory limit — the turn becomes a failed turn, the Android loses rules.android.failedTurnHealthPenalty health, and neither memory nor recording is updated for that round. An Android that needs a reliable log should prefer an action it knows will be accepted over an ambitious one that may be refused.
In a peer match played with --disclosure recording (see the CLI guide), recording is the only account of the match the player receives, alongside the final scores. Under that mode what an Android writes down is part of its design, not a debugging aid.
const action: Action = {
type: 'android.wait',
memory: 'return-to-depot',
recording: 'No safe route found this round.',
};
Wait
Do nothing.
const action: Action = { type: 'android.wait' };
Move
Move one tile north, south, east, or west, for rules.android.moveBatteryCost battery (1). Moving outside the map fails the turn, which costs the android its round and rules.android.failedTurnHealthPenalty health. The map’s bounds are in rules.world, so an Android never has to guess where the edge is.
const action: Action = { type: 'android.move', direction: 'east' };
Directions: north, south, east, west.
Charge
Recharge on an owned completed building on the android’s current tile that can charge — any type whose rules.buildings[type].charge is above zero, which is the charger by default. Adds that much battery (25), capped at rules.android.batteryCapacity (100).
const action: Action = { type: 'android.charge' };
Collect
Collect scattered material from the current tile into cargo. If resources is omitted, the android collects what it can up to cargo capacity.
const action: Action = { type: 'android.collect' };
const withResources: Action = { type: 'android.collect', resources: { metal: 3 } };
Deposit
Deposit cargo into an owned, completed, storage-capable building on the current tile. If resources is omitted, deposits all cargo.
A building accepts deposits when rules.buildings[type].storage.deposit is true: depots, processors, and acid processing plants by default. A construction site is not storage: nothing a building does — charging, storing, extracting, converting, seeing, carrying android capacity, or scoring — happens until it is finished.
const action: Action = { type: 'android.deposit' };
const withResources: Action = { type: 'android.deposit', resources: { ore: 2 } };
Withdraw
Withdraw material from an owned, completed, storage-capable building on the current tile.
const action: Action = { type: 'android.withdraw', resources: { metal: 4 } };
A building allows withdrawals when rules.buildings[type].storage.withdraw is true: depots, extractors, processors, and acid processing plants by default.
Start Construction
Start a building on the current tile. The tile must not already contain a building. Supplied resources can come from android cargo. Current compatibility also allows using loose/current-tile material in some cases, but scripts should prefer collecting material into cargo first.
Only material the building’s cost actually names is accepted, and never more of it than the cost asks for — a depot takes six metal, not eight, and not ten ore. Supplying nothing is allowed: the site is placed unpaid and the material can be delivered later with android.continue-construction.
const action: Action = { type: 'android.start-construction', buildingType: 'charger', resources: { metal: 10 } };
Continue Construction
Continue construction on an owned construction site on the current tile. If material requirements have been met, each continue action reduces remaining construction time by 1 tick.
const action: Action = { type: 'android.continue-construction' };
const withResources: Action = { type: 'android.continue-construction', resources: { electronics: 1 } };
Salvage
Damage/salvage the building on the current tile. Initial chargers cannot be salvaged. Self-salvage is faster than hostile salvage. When a building is fully salvaged, part of its build cost becomes scattered material on the tile.
const action: Action = { type: 'android.salvage' };
Broadcast
Broadcast a public message of up to rules.android.broadcastLimit characters (256). Messages are stored in world messages.
const action: Action = { type: 'android.broadcast', content: 'metal found at 3,4' };
Clean Acid
Clean rules.android.cleanAcidAmount acid (1) from an adjacent tile. The android’s owner must have a completed building that cleans acid anywhere in the world — rules.buildings[type].cleansAcid, the acid processing plant by default. The cleaned acid is stored as acidCanister in that building. Cleaning costs rules.android.cleanAcidBatteryCost battery (1).
const action: Action = { type: 'android.clean-acid', direction: 'north' };
Launch
Launch another android of the same owner on the current tile, which must hold one of the owner’s completed chargers. scriptId must be one of the owner’s scripts, as listed in world.scripts. The launch is refused unless the owner has spare charger capacity, exactly as a player launch is (see Chargers and Android Capacity). The new android starts at full battery and health and takes its first turn in the following round.
const action: Action = { type: 'android.launch', scriptId: 'script-2' };
Dismantle
Destroy this android voluntarily.
const action: Action = { type: 'android.dismantle' };
With targetAndroidId, destroy another android of the same owner instead. The acting android must be on one of its owner’s completed chargers, the target must be one of the owner’s active androids, and an android cannot name itself as the target.
const action: Action = { type: 'android.dismantle', targetAndroidId: 'android-3' };
9. Resources and Progression
There are two resource sources.
9.1 Scattered Earth-Launched Material
Humanity launched material pods before the androids arrived. These materials are scattered across the map and can be directly collected by androids.
This is the early-game resource source. It enables first depots, chargers, and other basic infrastructure.
9.2 Natural Planetary Composition
Tiles may contain natural composition such as ore, water, acid, and radiation.
Composition usually cannot be picked up directly. It requires buildings:
- extractors harvest natural tile composition into building storage
- processors refine ore into metal, and metal and water into electronics
- acid processing plants enable cleanup of hazardous acid, and refine the canisters into polymer
Earth scattered a fixed amount of metal and electronics and it does not grow back. Polymer it sent none of at all. Everything past what is lying on the ground comes out of the ground and through a refinery, which is what makes the middle of the game a supply chain rather than a scavenger hunt.
That is also what stands between a player and a colony module. Its 20 electronics are more than a whole board scatters, and its 20 polymer cannot be found at any price — so the module is only ever built by a colony that runs a processor and has cleaned up enough of the planet to have canisters to refine. Neither refinery costs polymer, for the obvious reason: the first one could never be built.
10. Buildings
Current building types. Costs and construction times are rules.buildings[type].cost and .ticks:
| Building | Cost | Construction ticks | Function |
|---|---|---|---|
charger | 8 metal | 2 | Increases android capacity by 2; charges androids |
depot | 6 metal | 2 | Stores material |
extractor | 10 metal, 2 electronics | 3 | Harvests tile composition into storage |
processor | 15 metal, 3 electronics | 4 | Refines ore into metal, and metal into electronics |
acid-processing-plant | 12 metal, 2 electronics | 4 | Enables acid cleaning; refines canisters into polymer |
relay-tower | 8 metal, 4 electronics | 3 | Planned communication infrastructure |
scanner | 8 metal, 6 electronics | 4 | Reveals nearby tiles at longer range |
radar | 14 metal, 10 electronics, 2 polymer | 7 | Reveals a radius-5 disc of tiles around itself |
colony-module | 50 metal, 20 electronics, 20 polymer | 12 | Scores 1,000 readiness; victory condition planned |
A building under construction occupies its tile immediately. Buildings have rules.buildings[type].health health (100).
A completed building harvests rules.buildings[type].extraction from the composition of its own tile at round end, capped by what the ground holds. Only the extractor does by default:
- up to 3
orefrom tile composition - up to 2
waterfrom tile composition - up to 1
acidCanisterfrom tile acid
Harvesting does not consume composition: the ground keeps yielding.
A completed building runs rules.buildings[type].conversion on its own storage once per round end. A building may hold several recipes, and they run in the order listed, each once, against the storage as the previous one left it — so one building can feed itself. By default:
- the processor: 2
ore-> 1metal, then 1metal+ 1water-> 1electronics - the acid processing plant: 1
acidCanister+ 1water-> 1polymer
This is the only source of electronics and polymer beyond what Earth scattered, and both cost more than they yield in raw material. A colony that wants the parts a colony module is made of has to build the industry that makes them, and keep it fed.
11. Acid and Environmental Preparation
Acid is both a hazard and a strategic resource.
- Androids standing on acid take damage at round end.
- Acid in tile composition is not loose material.
- Androids can clean acid from adjacent tiles only if their owner has a completed acid processing plant.
- Cleaning acid reduces the target tile’s acid by 1 and stores 1
acidCanisterin the plant.
This makes acid cleanup a mid-game environmental preparation goal rather than a free starting ability.
12. Salvage and Sabotage
Androids can salvage buildings on their current tile.
Rules:
- initial chargers cannot be salvaged
- a building whose
rules.buildings[type].salvageableByOthersis false cannot be salvaged by another player at all — the depot, by default - self-salvage deals
rules.salvage.ownDamagebuilding damage per action (25) - hostile salvage deals
rules.salvage.hostileDamagebuilding damage per action (15) - buildings have
rules.buildings[type].healthhealth (100) - when destroyed by salvage, returned material becomes scattered on the tile
- self-salvage returns
rules.salvage.ownReturnRate(60%) of the material actually invested in the building - hostile salvage returns
rules.salvage.hostileReturnRate(35%) of the same
The return is a share of what went into the building, not of what its type costs, so an unpaid construction site is worth nothing to take apart. Anything stored inside a building is different: it spills onto the tile in full, for whoever is standing there. Bringing down a full depot is a robbery, not an erasure — and a stockpile left in a building nobody is guarding is a stockpile within reach.
Salvage is intentionally slower than ordinary collection and requires the android to remain at the target.
Depots are the exception, and the reason is the whole point of hauling: material that reached a depot is material that is safe. A rival can contest the ground, the chargers, the extractors and the refineries, but not the stockpile already banked. A player can still salvage their own depot — the stored material spills onto the tile, and moving it is then their problem.
12.1 Repair
An android standing on one of its owner’s completed buildings can repair it, restoring rules.salvage.repairAmount health (10) for rules.salvage.repairCost (1 metal) out of its cargo. Health never exceeds the building’s own maximum, and a building that is not damaged cannot be repaired.
Repair is what makes a raid a contest. Hostile salvage takes rules.salvage.hostileDamage (15) off a building per action against a repair’s 10, so one defender roughly cancels one attacker: holding ground is possible, never free, and two raiders beat one defender. Buildings under construction are continued, not repaired.
13. Communication
Androids can broadcast public messages.
Messages can be used for:
- local coordination
- map notes
- warnings
- claims
- deception
- negotiation
- debugging script behavior
There is no private radio by default. Relay towers are planned to expand communication behavior, but only basic message storage is currently implemented.
14. Visibility and Information
Visibility is recomputed from scratch at the start and the end of every round: a tile is visible only while something of yours is in range of it, and goes dark again once nothing is. Recomputing at the start is what gives a newly launched Android a lit first turn instead of a view of the single tile it is standing on. Sight comes from rules.android.sight and rules.buildings[type].sight; by default:
- active androids reveal tiles within range 3
- completed scanners reveal tiles within range 4
- completed radars reveal tiles within radius 5
A building type whose sight rule is null reveals nothing.
Sight range is measured two different ways, and the difference is deliberate:
- Androids and scanners count orthogonal steps (
|dx| + |dy|), so their footprint is a diamond. It is the range the piece could actually walk, which makes short-range sight read as the piece looking around itself. - Radars use true distance (
dx² + dy² <= radius²), so their footprint is a disc. A radar sweeps rather than walks, and at radius 5 a diamond would read as an obvious lozenge on the board instead of a sweep.
A radar therefore sees roughly twice the ground a scanner does — about 81 tiles against 41 — for roughly twice the cost and almost twice the construction time. It is the mid-game answer to mapping a region, where the scanner is the early-game answer to seeing past your own Androids.
Each script receives a fogged world projection for its Android’s owner. It includes the tiles that owner can currently see, as well as the acting Android’s current tile so it can always inspect itself. Androids, buildings, and broadcasts are included only when their position is on an included tile. Other players’ scripts and player records are omitted. The acting Android retains its memory and recording; those fields are [Redacted] on every other Android.
Deactivated Androids stay in world.androids as wrecks on the tile where they fell, so a script counting company should filter on active.
Sight is not memory: once your Androids move out of range, or a scanner or radar is salvaged, a tile drops out of the projection again. Scripts that need to remember the map must persist it themselves in Android memory or share it through broadcasts.
A player-facing replay preserves the complete world for rendering, but replaces another player’s script source and Android memory and recording with [Redacted]. The same redaction applies to the corresponding event payloads.
15. Conflict
Project: Nova is primarily a construction, logistics, and programming strategy game. Conflict exists, but should not reduce the game to simple combat.
Current conflict tools are indirect:
- racing to scattered material
- occupying valuable building sites
- salvaging hostile infrastructure
- broadcasting misleading or persuasive information
- denying or cleaning hazardous terrain
Direct android combat is not implemented.
16. Colony Readiness Score
The readiness score answers: which player has prepared the most viable colony right now? It is calculated from the current World and reported per player with a contributor breakdown in nova status and the replay UI.
Only completed, functioning colony assets and materials secured in completed buildings count. Construction sites, loose material, Android cargo, scripts, messages, Android count, map discovery, scanners, radars, and relay towers earn no points. Sight infrastructure and exploration remain strategically useful because they help Androids locate viable resources and building sites.
Points come from rules.scoring.buildings and rules.scoring.materials; anything worth 0 points earns no line in the breakdown at all. The defaults:
| Contributor | Points |
|---|---|
| Colony module | 1,000 each |
| Acid-processing plant | 120 each |
| Processor | 100 each |
| Extractor | 80 each |
| Depot | 40 each |
| Charger | 25, then 80% of the one before |
| Stored metal | 2 per unit |
| Stored electronics or polymer | 3 per unit |
| Stored ore | 1 per unit |
| Stored water or acid canister | 2 per unit |
Stored materials count only when they are in a completed building owned by that player. The algorithm deliberately measures present readiness, not historical achievement: an asset that is salvaged or a stockpile that is spent stops contributing.
17. Design Goals
The rules should create these strategic questions:
- Where should I build my first real base?
- Should I expand chargers or secure resources first?
- Is it worth replacing an android with better code now?
- Should I broadcast openly, encode meaning, or stay silent?
- Is hostile salvage worth the time and risk?
- Should I clean acid, avoid it, or exploit it as a barrier?
- How much should I invest in exploration versus infrastructure?
- Can my androids recover from unexpected situations?
18. Rules
Everything numeric in this rulebook is a rule, and the rules are data. One
object holds all of them, every field has a default, and any subset can be
overridden — {} is the game as it ships.
// rules.json — a complete rules file
{
"world": { "width": 24, "height": 24 },
"android": { "cargoCapacity": 6 },
"buildings": { "depot": { "cost": { "metal": 4 }, "ticks": 1 } },
}
npx nova create-game --file game.json --rules rules.json
The groups:
| Group | Covers |
|---|---|
world | Board size, and how a fresh map’s composition and scattered material are generated |
android | Cargo capacity, battery capacity and costs, decay, hazard damage, the failed-turn penalty, sight, and limits |
buildings | Per type: cost, ticks, health, charging, android capacity, sight, storage, extraction, conversions, acid cleaning, hostile-salvage immunity |
salvage | Salvage damage, the share of invested material returned, and what a repair restores and costs |
scoring | What each building and stored material is worth, and how fast a type’s value diminishes |
script | What one Android turn may spend: CPU ticks, wall clock, and heap |
match | The round the humans are expected to arrive on, and whether lost androids are replaced |
Two conventions are worth knowing when writing a rules file:
- Every single value has a default, so a group can be given partially:
{ "android": { "cargoCapacity": 6 } }leaves every other android rule alone. - A leaf value object — a sight, a generation roll, a conversion — is supplied
whole or not at all.
{ "sight": { "range": 6 } }is rejected rather than silently inheriting a shape from somewhere else.
Mechanics read behaviour off the rules rather than off building names, so some
retunings that look like code changes are not: a depot with androidCapacity: 1
raises the android cap, and a building with a conversion refines material.
Rules and Androids
The resolved rules are handed to every script as the rules global. An Android
should read them rather than repeat them:
const capacity = rules.android.cargoCapacity;
const depotCost = rules.buildings.depot.cost;
const onMap = (p: Position): boolean => p.x >= 0 && p.y >= 0 && p.x < rules.world.width && p.y < rules.world.height;
An Android that copies a number out of this rulebook is an Android that breaks
when the game is tuned — and the point of the rules global is that adapting is
cheaper than guessing.
Rules and Recordings
A game file stores the rules it was created with, alongside the initial world and
the event log. Every later command — run, status, play — replays it under
those rules, so a retuned game continues and scores as itself. A recording made
before rules were data opens under the shipped defaults, which is what it was
played with.
A peer match is played under the host’s rules, and the recording each player
keeps carries them. The board size is currently the only rule the match offer
negotiates; the host’s round count is not negotiated but is written into the
rules as match.finalRound, so both Androids know when the humans land.
19. Not Yet Implemented / Expected Future Work
These concepts are intended but not fully implemented:
- launch delay
- fleet-arrival endgame
- relay tower broadcast extension
- direct defensive structures
- richer natural resource chains
- player-facing reports beyond recordings and world state
Found something wrong? These documents live in the repository.