- **ships.toml** — ship stats (HP, speed, damage, attack range, attack rate) as formulas of ship level, required materials per blueprint, threat cost formula, and whether each blueprint is available from the start or unlocked via loot.
- **ships.toml** — ship stats (HP, speed, damage, attack range, attack rate) as formulas of ship level, required materials per blueprint, threat cost formula, and whether each blueprint is available from the start or unlocked via loot.
- **stations.toml** — HP, damage, range, and fire rate for player and enemy defence stations.
- **stations.toml** — HP, damage, range, fire rate, and scrap drop for player and enemy defence stations, defined as formulas of station level.
### Surface Mask Format
Buildings in buildings.toml define a `surface_mask` — a list of strings that describes the building's tile footprint and output port(s). Each character occupies one cell in the grid:
-`A` — building tile that must be placed on an asteroid tile.
-`S` — building tile that must be placed on a space tile.
-` ` (space) — empty cell; not part of the building footprint.
-`>` — output port indicator: the building tile immediately to its left has a rightward-facing output port (items push right).
-`<` — output port indicator: the building tile immediately to its right has a leftward-facing output port (items push left).
-`^` — output port indicator: the building tile immediately below it has an upward-facing output port (items push up).
-`v` — output port indicator: the building tile immediately above it has a downward-facing output port (items push down).
Output port indicators are not building tiles themselves. A building may have more than one output port (e.g. a splitter uses `<A>` to declare both a left and a right output on the same tile).
## Game World
## Game World
- REQ-GW-TILE-SIZE: Tiles are 20×20 pixels. Items on belts are 10×10 pixels (half a tile), so each belt tile holds at most 2 items.
- REQ-GW-TILE-SIZE: Tiles are 20×20 pixels. Items on belts are 10×10 pixels (half a tile), so each belt tile holds at most 2 items.
- REQ-GW-HEIGHT: The world height (in tiles) is read from world.toml.
- REQ-GW-HEIGHT: The world height (in tiles) is read from `world.toml [world].height_tiles`.
- REQ-GW-REGIONS: The world is divided into horizontal regions whose widths (in tiles) are all read from world.toml:
- REQ-GW-REGIONS: The world is divided into horizontal regions whose widths (in tiles) are read from `world.toml [regions]`:
- **Asteroid** — the player's build area.
- **Asteroid** — the player's build area (`asteroid_width`).
- **Player buffer zone** — space between the asteroid and the player's defence stations.
- **Player buffer zone** — space between the asteroid and the player's defence stations (`player_buffer_width`).
- **Contest zone** — space between the player's and enemy's defence stations. This is where combat happens.
- **Contest zone** — space between the player's and enemy's defence stations. This is where combat happens (`contest_zone_width`).
- **Enemy buffer zone** — space between the enemy's defence stations and the enemy spawn boundary.
- **Enemy buffer zone** — space between the enemy's defence stations and the enemy spawn boundary (`enemy_buffer_width`).
- REQ-GW-SCROLL-LIMIT: The player can scroll the view horizontally from the asteroid's left edge to the current set of enemy defence stations (the enemy buffer zone is not visible).
- REQ-GW-SCROLL-LIMIT: The player can scroll the view horizontally from the asteroid's left edge to the current set of enemy defence stations (the enemy buffer zone is not visible).
- REQ-GW-PUSH-EXPAND: When the player destroys a set of enemy defence stations, the scrollable area is extended by a configurable number of tiles (world.toml). A new enemy buffer zone of the same configurable width is added beyond the new enemy defence stations.
- REQ-GW-PUSH-EXPAND: When the player destroys a set of enemy defence stations, the scrollable area is extended by `world.toml [push].push_expand_columns` tiles. A new enemy buffer zone of `world.toml [regions].enemy_buffer_width` tiles is added beyond the new enemy defence stations.
- REQ-GW-ASTEROID-EXPAND: When the player unlocks an asteroid expansion, a configurable number of tile columns (world.toml) is added to the left of the asteroid.
- REQ-GW-ASTEROID-EXPAND: When the player unlocks an asteroid expansion, `world.toml [expansion].columns_per_expansion` tile columns are added to the left of the asteroid.
## HQ & Game Over
## HQ & Game Over
- REQ-HQ-PLACEMENT: The HQ is pre-placed at the asteroid's right edge at game start.
- REQ-HQ-PLACEMENT: The HQ is pre-placed at the asteroid's right edge at game start.
- REQ-HQ-BELT-INPUT: The HQ has a belt input port. Building blocks delivered to it are added to the global building blocks stock.
- REQ-HQ-BELT-INPUT: The HQ has a belt input port. Building blocks delivered to it are added to the global building blocks stock.
- REQ-HQ-STATS: HQ stats (HP) are read from stations.toml.
- REQ-HQ-STATS: HQ stats (HP) are read from `stations.toml [hq]`.
- REQ-HQ-GAME-OVER: If the HQ is destroyed, the game ends and the final survival time is shown.
- REQ-HQ-GAME-OVER: If the HQ is destroyed, the game ends and the final survival time is shown.
- REQ-HQ-INVULNERABLE: Factory buildings (other than the HQ) are never targeted or destroyed by enemies.
- REQ-HQ-INVULNERABLE: Factory buildings (other than the HQ) are never targeted or destroyed by enemies.
## Building Placement & Management
## Building Placement & Management
- REQ-BLD-COST: The player places buildings from a build menu. Placement costs building blocks from the global stock. The cost per building type is read from buildings.toml.
- REQ-BLD-COST: The player places buildings from a build menu. Placement costs building blocks from the global stock. The cost per building type is read from `buildings.toml [[building]].cost`.
- REQ-BLD-QUEUE: Placed buildings enter a construction queue and are built one at a time. Each building takes a duration defined in recipes.toml to construct.
- REQ-BLD-QUEUE: Placed buildings enter a construction queue and are built one at a time. Each building takes a duration defined in `buildings.toml [[building]].construction_time_seconds` to construct.
- REQ-BLD-ASTEROID-ONLY: Buildings can only be placed on asteroid tiles.
- REQ-BLD-ASTEROID-ONLY: Buildings can only be placed on asteroid tiles.
- REQ-BLD-SHIPYARD-EDGE: Shipyards must be placed at the asteroid's right edge.
- REQ-BLD-SHIPYARD-EDGE: Shipyards must be placed at the asteroid's right edge.
- REQ-BLD-BUILDER-MODE: Clicking a build button activates builder mode for that building type. Builder mode is exited by pressing Escape, right-clicking in the game world, or clicking the same build button again.
- REQ-BLD-BUILDER-MODE: Clicking a build button activates builder mode for that building type. Builder mode is exited by pressing Escape, right-clicking in the game world, or clicking the same build button again.
@@ -42,15 +56,15 @@ Config files use the TOML format. The following config files drive game paramete
- REQ-BLD-ROTATE: While in builder mode, pressing E rotates the ghost 90° clockwise and Q rotates it 90° counter-clockwise. Rotation affects the direction of the output port.
- REQ-BLD-ROTATE: While in builder mode, pressing E rotates the ghost 90° clockwise and Q rotates it 90° counter-clockwise. Rotation affects the direction of the output port.
- REQ-BLD-PLACE: Clicking a valid tile in builder mode places a construction site and adds it to the build queue, consuming building blocks from the global stock.
- REQ-BLD-PLACE: Clicking a valid tile in builder mode places a construction site and adds it to the build queue, consuming building blocks from the global stock.
- REQ-BLD-BELT-DRAG: For belts, the player can click and drag across multiple tiles to place a construction site on each tile in one gesture.
- REQ-BLD-BELT-DRAG: For belts, the player can click and drag across multiple tiles to place a construction site on each tile in one gesture.
- REQ-BLD-DEMOLISH: The player can demolish a placed building. Demolition returns a configurable percentage of the original building block cost (default 75%) to the global stock. The refund percentage is read from world.toml.
- REQ-BLD-DEMOLISH: The player can demolish a placed building. Demolition returns `world.toml [world].refund_percentage` percent of the original building block cost (default 75%) to the global stock.
## Building Types
## Building Types
- REQ-BLD-MINER: **Miner** (2×2): The player selects which ore type it extracts. Produces ore at a rate defined in recipes.toml. Ore never depletes.
- REQ-BLD-MINER: **Miner** (2×2): The player selects which ore type it extracts. Each ore type corresponds to a `recipes.toml [[recipe]]` entry with `building = "miner"`, defining the output item and `duration_seconds`. Ore never depletes.
- REQ-BLD-SMELTER: **Smelter** (2×2): Converts ore or scrap into basic materials. No recipe selection required. Inputs, outputs, and rates are defined in recipes.toml.
- REQ-BLD-SMELTER: **Smelter** (2×2): Converts ore or scrap into basic materials. No recipe selection required. Inputs, outputs, and rates are defined in `recipes.toml [[recipe]]` entries with `building = "smelter"`.
- REQ-BLD-ASSEMBLER: **Assembler** (3×3): The player selects a recipe from the config-defined crafting tree. Produces the selected output item at the rate defined in recipes.toml.
- REQ-BLD-ASSEMBLER: **Assembler** (3×3): The player selects a recipe from the config-defined crafting tree. Produces the selected output item at the rate defined in the corresponding `recipes.toml [[recipe]]` entry with `building = "assembler"`.
- REQ-BLD-REPROCESSING: **Reprocessing Plant** (3×3): Consumes scrap per cycle (quantity from recipes.toml) and produces higher-level intermediate products. Each product type has a fixed drop probability per cycle, defined in recipes.toml.
- REQ-BLD-REPROCESSING: **Reprocessing Plant** (3×3): Consumes scrap per cycle and produces higher-level intermediate products. The input quantity, output items, and per-output drop probabilities are defined in `recipes.toml [[recipe]]` entries with `building = "reprocessing_plant"` (`inputs`, `outputs[].amount`, `outputs[].probability`).
- REQ-BLD-SHIPYARD: **Shipyard** (4×2): The player selects a blueprint. Automatically produces one ship of that type at a fixed level (defined in ships.toml, default: 5) whenever all required materials are present in its input buffer. Ship material requirements are defined in ships.toml.
- REQ-BLD-SHIPYARD: **Shipyard** (4×2): The player selects a blueprint. Automatically produces one ship of that type at a fixed level (`ships.toml [ship.blueprint].player_production_level`, default: 5) whenever all required materials (`[ship.blueprint].materials`) are present in its input buffer.
- REQ-BLD-SALVAGE-BAY: **Salvage Bay** (3×2): A dedicated drop-off point for salvage ships. Scrap delivered here is placed onto connected output belts.
- REQ-BLD-SALVAGE-BAY: **Salvage Bay** (3×2): A dedicated drop-off point for salvage ships. Scrap delivered here is placed onto connected output belts.
- REQ-BLD-BELT: **Belt** (1×1): Transports items. Available in straight and curved variants.
- REQ-BLD-BELT: **Belt** (1×1): Transports items. Available in straight and curved variants.
- REQ-BLD-SPLITTER: **Splitter** (1×1): Distributes incoming items between two output directions. Each output can optionally have a filter (a list of item types), configurable via the selected building panel. Routing rules:
- REQ-BLD-SPLITTER: **Splitter** (1×1): Distributes incoming items between two output directions. Each output can optionally have a filter (a list of item types), configurable via the selected building panel. Routing rules:
@@ -72,7 +86,7 @@ Config files use the TOML format. The following config files drive game paramete
## Resources
## Resources
- REQ-RES-ORE: Ore is extracted by miners and smelted into basic materials by smelters.
- REQ-RES-ORE: Ore is extracted by miners and smelted into basic materials by smelters.
- REQ-RES-SCRAP-DROP: Destroyed ships (both player and enemy) and destroyed defence stations (both player and enemy) drop scrap at their location. The scrap amount per unit is defined in ships.toml and stations.toml respectively. Scrap despawns after a configurable duration (world.toml) if not collected.
- REQ-RES-SCRAP-DROP: Destroyed ships (both player and enemy) and destroyed defence stations (both player and enemy) drop scrap at their location. The scrap amount per ship is defined in `ships.toml [ship.loot].scrap_drop`; for stations it is defined as `stations.toml [player_station].scrap_drop_formula` and `[enemy_station].scrap_drop_formula`. Scrap despawns after `world.toml [world].scrap_despawn_seconds` seconds if not collected.
- REQ-RES-SCRAP-COLLECT: Scrap is collected by salvage ships and delivered to a Salvage Bay on the asteroid. From there it can be fed via belt into a smelter (same output as ore) or a Reprocessing Plant.
- REQ-RES-SCRAP-COLLECT: Scrap is collected by salvage ships and delivered to a Salvage Bay on the asteroid. From there it can be fed via belt into a smelter (same output as ore) or a Reprocessing Plant.
- REQ-RES-BUILDING-BLOCKS: Building blocks are produced by an assembler recipe and are the only globally pooled resource. They are added to the global stock when delivered to the HQ via belt.
- REQ-RES-BUILDING-BLOCKS: Building blocks are produced by an assembler recipe and are the only globally pooled resource. They are added to the global stock when delivered to the HQ via belt.
- REQ-RES-CONFIG: All recipes, production rates, and reprocessing probabilities are defined in recipes.toml.
- REQ-RES-CONFIG: All recipes, production rates, and reprocessing probabilities are defined in recipes.toml.
@@ -80,7 +94,7 @@ Config files use the TOML format. The following config files drive game paramete
## Ships
## Ships
- REQ-SHP-AUTONOMOUS: Ships are produced by shipyards and are fully autonomous once produced.
- REQ-SHP-AUTONOMOUS: Ships are produced by shipyards and are fully autonomous once produced.
- REQ-SHP-STATS: All ship stats (HP, speed, damage, attack range, attackrate) are defined as formulas of ship level in ships.toml. Required build materials and whether each blueprint is available from game start or must be unlocked are also defined there.
- REQ-SHP-STATS: All ship stats are defined as formulas of ship level in `ships.toml`: HP (`[ship.health].hp_formula`), speed (`[ship.movement].speed_formula`), damage (`[ship.combat].damage_formula`), attack range (`[ship.combat].attack_range_formula`), attack rate (`[ship.combat].attack_rate_formula`). Required build materials (`[ship.blueprint].materials`) and availability from game start (`[[ship]].available_from_start`) are also defined there.
- REQ-SHP-NO-COLLISION: Ships move independently with no collision between them.
- REQ-SHP-NO-COLLISION: Ships move independently with no collision between them.
- REQ-SHP-COMBAT: **Combat ships** — move right through space and engage enemy ships. The player can configure the following per shipyard (applied to all ships produced by that shipyard):
- REQ-SHP-COMBAT: **Combat ships** — move right through space and engage enemy ships. The player can configure the following per shipyard (applied to all ships produced by that shipyard):
- Stance: aggressive (advance toward enemies) / defensive (hold position near asteroid).
- Stance: aggressive (advance toward enemies) / defensive (hold position near asteroid).
@@ -92,35 +106,35 @@ Config files use the TOML format. The following config files drive game paramete
## Defence Stations
## Defence Stations
- REQ-DEF-PLAYER-PLACEMENT: 2 player defence stations are pre-placed in space at the start. Their positions are determined by the world region widths in world.toml.
- REQ-DEF-PLAYER-PLACEMENT: 2 player defence stations are pre-placed in space at the start. Their positions are determined by `world.toml [regions].asteroid_width` and `player_buffer_width`.
- REQ-DEF-PLAYER-FIRE: Player defence stations automatically fire at approaching enemy ships. Stats are read from stations.toml.
- REQ-DEF-PLAYER-FIRE: Player defence stations automatically fire at approaching enemy ships. Stats are defined as formulas of a fixed station level (`stations.toml [player_station].level`) in `stations.toml [player_station]`: `hp_formula`, `damage_formula`, `range_formula`, `fire_rate_formula`, `scrap_drop_formula`.
- REQ-DEF-PLAYER-DESTRUCTIBLE: Player defence stations can be destroyed by enemies and repaired by repair ships.
- REQ-DEF-PLAYER-DESTRUCTIBLE: Player defence stations can be destroyed by enemies and repaired by repair ships.
- REQ-DEF-ENEMY-PLACEMENT: 2 enemy defence stations are placed at the right boundary of the scrollable area at game start, and again each time a new set is spawned after a push. Stats scale with the station generation (REQ-PSH-STATION-STATS).
- REQ-DEF-ENEMY-PLACEMENT: 2 enemy defence stations are placed at the right boundary of the scrollable area at game start, and again each time a new set is spawned after a push. Stats scale with the station level (REQ-PSH-STATION-STATS).
- REQ-DEF-ENEMY-FIRE: Enemy defence stations automatically fire at player ships within range.
- REQ-DEF-ENEMY-FIRE: Enemy defence stations automatically fire at player ships within range.
- REQ-DEF-NO-CROSSFIRE: Enemy and player defence stations are never in each other's firing range.
- REQ-DEF-NO-CROSSFIRE: Enemy and player defence stations are never in each other's firing range.
- REQ-DEF-PUSH: When both enemy defence stations in a set are destroyed, the push scaling multiplier is applied (REQ-PSH-ACCUMULATION), the scrollable area is extended (REQ-GW-PUSH-EXPAND), and a new set of enemy defence stations is placed at the new boundary. The destroyed stations drop ship blueprint loot.
- REQ-DEF-PUSH: When both enemy defence stations in a set are destroyed, the push scaling multiplier is applied (REQ-PSH-ACCUMULATION), the scrollable area is extended (REQ-GW-PUSH-EXPAND), and a new set of enemy defence stations is placed at the new boundary. The destroyed stations drop ship blueprint loot.
## Threat Level & Enemy Waves
## Threat Level & Enemy Waves
- REQ-WAV-THREAT-RATE: A global **threat level** accumulates continuously over time. The rate of increase per second is determined by a formula read from world.toml where x is elapsed game time in seconds. Example: `1*x - 30` gives 0 threat/s at x=30s and increases linearly after that.
- REQ-WAV-THREAT-RATE: A global **threat level** accumulates continuously over time. The rate of increase per second is determined by `world.toml [waves].threat_rate_formula` where x is elapsed game time in seconds. Example: `1*x - 30` gives 0 threat/s at x=30s and increases linearly after that.
- REQ-WAV-GAP: At game start and immediately after each wave is triggered, a random inter-wave gap is drawn uniformly from a configurable [min, max] range (world.toml, in seconds).
- REQ-WAV-GAP: At game start and immediately after each wave is triggered, a random inter-wave gap is drawn uniformly from [`world.toml [waves].gap_min_seconds`, `gap_max_seconds`].
- REQ-WAV-TRIGGER: When the gap expires, a wave is triggered. Ships are spawned using the accumulated threat level. Any threat not spent on ships carries over to the next wave. A longer gap results in a larger wave.
- REQ-WAV-TRIGGER: When the gap expires, a wave is triggered. Ships are spawned using the accumulated threat level. Any threat not spent on ships carries over to the next wave. A longer gap results in a larger wave.
- REQ-WAV-SHIP-LEVEL: Each wave's enemy ships are assigned a level determined by a formula of elapsed game time in seconds (x), read from world.toml. This is the sole mechanism by which enemy waves grow stronger over time.
- REQ-WAV-SHIP-LEVEL: Each wave's enemy ships are assigned a level determined by `world.toml [waves].ship_level_formula` where x is elapsed game time in seconds. This is the sole mechanism by which enemy waves grow stronger over time.
- REQ-WAV-THREAT-COST: Ships are spawned until the accumulated threat is exhausted. Each ship type has a threat cost defined as a formula of ship level in ships.toml. Because enemy ship level increases with time, threat cost per ship rises naturally over the course of the game.
- REQ-WAV-THREAT-COST: Ships are spawned until the accumulated threat is exhausted. Each ship type has a threat cost defined as `ships.toml [ship.threat].cost_formula`. Because enemy ship level increases with time, threat cost per ship rises naturally over the course of the game.
- REQ-WAV-SPAWN-DURATION: Ships in a wave are spawned one at a time over the spawn duration. Spawning duration is read from world.toml.
- REQ-WAV-SPAWN-DURATION: Ships in a wave are spawned one at a time over `world.toml [waves].spawn_duration_seconds`.
- REQ-WAV-SHIP-STATS: Per-ship stats (damage, attack rate, range, speed) and threat cost are each defined as formulas of ship level in ships.toml.
- REQ-WAV-SHIP-STATS: Per-ship stats (damage: `[ship.combat].damage_formula`, attack rate: `[ship.combat].attack_rate_formula`, range: `[ship.combat].attack_range_formula`, speed: `[ship.movement].speed_formula`) and threat cost (`[ship.threat].cost_formula`) are each defined as formulas of ship level in `ships.toml`.
- REQ-WAV-GRACE-PERIOD: The grace period before the first wave is implicit: threat accumulates from t=0 but the first wave does not trigger until the initial gap (drawn at game start) has elapsed.
- REQ-WAV-GRACE-PERIOD: The grace period before the first wave is implicit: threat accumulates from t=0 but the first wave does not trigger until the initial gap (drawn at game start) has elapsed.
## Push Scaling
## Push Scaling
- REQ-PSH-ACCUMULATION: Each time the player destroys a set of enemy defence stations, a configurable pushscalingfactor (world.toml) is multiplied permanently into the threat level accumulation rate. This causes all subsequent waves to be larger.
- REQ-PSH-ACCUMULATION: Each time the player destroys a set of enemy defence stations, `world.toml [push].scaling_factor` is multiplied permanently into the threat level accumulation rate. This causes all subsequent waves to be larger.
- REQ-PSH-STATION-STATS: Enemy defence station stats (HP, damage, range, fire rate) are each defined as formulas in stations.toml where x is the station generation — an integer starting at 0 for the initial set and incrementing by 1 each time a new set is placed.
- REQ-PSH-STATION-STATS: Enemy defence station stats are each defined as formulas in `stations.toml [enemy_station]`: `hp_formula`, `damage_formula`, `range_formula`, `fire_rate_formula`, `scrap_drop_formula`, where x is the station level — an integer starting at 0 for the initial set and incrementing by 1 each time a new set is placed.
- REQ-PSH-STACKING: Push scaling factors stack multiplicatively with each other and with the time-based threat formula.
- REQ-PSH-STACKING: Push scaling factors stack multiplicatively with each other and with the time-based threat formula.
## Asteroid Expansion
## Asteroid Expansion
- REQ-EXP-UNLOCK: The player can unlock additional asteroid tile columns to the left of the existing asteroid by spending building blocks from the global stock.
- REQ-EXP-UNLOCK: The player can unlock additional asteroid tile columns to the left of the existing asteroid by spending building blocks from the global stock.
- REQ-EXP-COST: Each expansion adds a configurable number of columns (world.toml) and costs a configurable amount of building blocks (world.toml).
- REQ-EXP-COST: Each expansion adds `world.toml [expansion].columns_per_expansion` columns and costs `[expansion].cost_building_blocks` building blocks.
## UI
## UI
Reference in New Issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.