195 lines
7.8 KiB
Markdown
195 lines
7.8 KiB
Markdown
# Content Design — Ships & Modules
|
||
|
||
First real-content iterations (June 2026). Pass 1 defined ship hull grids and
|
||
module surface masks; pass 2 defined the production tree (recipes). Stats and
|
||
threat costs in the config files are still placeholders for the balancing
|
||
pass.
|
||
|
||
## Design principle: footprint gating
|
||
|
||
Which module fits on which hull is controlled purely by geometry — no
|
||
explicit allow-lists. Each hull grid is shaped so that it physically cannot
|
||
contain the footprint of modules from a larger size class. This keeps the
|
||
rules transparent to the player ("it doesn't fit because there is no room")
|
||
and makes them trivially moddable through the config files alone.
|
||
|
||
### Module footprint ladder
|
||
|
||
| Footprint | Modules | Smallest hull that fits it |
|
||
|-----------|---------|----------------------------|
|
||
| 1x1 | laser_cannon_s, salvager, repair_tool | drone |
|
||
| 1x2 | maneuvering_thrusters, sensor_booster, armor_plates | frigate |
|
||
| 1x3 | afterburner | frigate (eats most of it) |
|
||
| L-shape (3 cells) | weapon_stabilizer, weapon_primer, weapon_upgrade | frigate |
|
||
| 2x2 | laser_cannon_m, drone_bay | cruiser |
|
||
| 3x3 | laser_cannon_l | battleship |
|
||
| 2x6 | drone_hangar | carrier (only) |
|
||
|
||
### Hull grids
|
||
|
||
`O` = buildable cell, `X` = hull structure (not buildable).
|
||
|
||
**drone (xs, 1 cell)** — exactly one 1x1 module: a small gun, a salvager, or
|
||
a repair tool. This is what makes drone roles swappable.
|
||
|
||
O
|
||
|
||
**frigate (s, 5 cells)** — plus shape. Every 1x2 placement crosses the center
|
||
cell, so at most ONE 1x2 support fits; alternatively one L-shaped weapon
|
||
modifier or one afterburner through the center line. Gun-boat with one or two
|
||
support modules, as intended.
|
||
|
||
XOX
|
||
OOO
|
||
XOX
|
||
|
||
**destroyer (s, 8 cells)** — gun deck with three turret bumps. More cells
|
||
than the frigate (more small guns), but still no 2x2 area anywhere, so medium
|
||
hardware can never be mounted.
|
||
|
||
OXOXO
|
||
OOOOO
|
||
|
||
**cruiser (m, 12 cells)** — notched corners. Fits at most two 2x2 m guns
|
||
(stacked through the middle), leaving the side cells for supports. No 3x3
|
||
area.
|
||
|
||
XOOX
|
||
OOOO
|
||
OOOO
|
||
XOOX
|
||
|
||
**battlecruiser (m, 16 cells)** — split bow with two gun cheeks, tapered
|
||
stern. Fits three 2x2 m guns — one more than the cruiser — with small support
|
||
slots left over. The bow split and stern taper prevent any 3x3 area (no l
|
||
gun) and any 2x6 area (no drone hangar).
|
||
|
||
OOXXOO
|
||
OOOOOO
|
||
XOOOOX
|
||
XXOOXX
|
||
|
||
**battleship (l, 24 cells)** — broadside hull with notched flanks on every
|
||
other row. Fits four 2x2 m guns (two per gun deck) — one more than the
|
||
battlecruiser — with bow, stern, and flank cells for supports. All 3x3
|
||
placements crowd the center columns, so at most ONE l gun fits: mounted
|
||
center it blocks every m gun mount (pure support strips remain), mounted
|
||
offset it still allows two m guns. The notched rows are never adjacent-and-
|
||
full, so no 2x6 drone hangar fits.
|
||
|
||
XOOOOX
|
||
OOOOOO
|
||
XOOOOX
|
||
OOOOOO
|
||
XOOOOX
|
||
|
||
**dreadnought (xl, 36 cells)** — the main battery deck is split into three
|
||
3x3 gun slots by structural spacer columns, so exactly three l guns fit side
|
||
by side (or m guns / supports in unused slots), plus bow/stern strips for
|
||
supports. The spacers cap every horizontal run at 5 cells, so the 2x6 drone
|
||
hangar can never fit — the carrier stays the only hangar hull.
|
||
|
||
XXXOOOOOXXX
|
||
OOOXOOOXOOO
|
||
OOOXOOOXOOO
|
||
OOOXOOOXOOO
|
||
XXOOXXXOOXX
|
||
|
||
**carrier (xl, 37 cells)** — the top flight deck (rows 0–1) is the only
|
||
region wide enough for the 2x6 drone hangar, and exactly one fits. The middle
|
||
deck row is broken up by elevator shafts (X cells placed so every 3-column
|
||
window hits one), which is what prevents any 3x3 l gun from ever fitting.
|
||
Lower decks hold supports and 2x2 point-defense m guns.
|
||
|
||
XOOOOOOOOX
|
||
OOOOOOOOOO
|
||
OOXOOXOOXO
|
||
XOOOOOOOOX
|
||
XXXOOOOXXX
|
||
|
||
### Verified gating matrix
|
||
|
||
Checked programmatically against the configs (all four mask rotations,
|
||
all placements) with `tools/verify_layouts.py` — re-run it after editing
|
||
layout grids or surface masks:
|
||
|
||
python dota_factory/tools/verify_layouts.py
|
||
|
||
| Footprint | drone | frigate | destroyer | cruiser | battlecruiser | battleship | dreadnought | carrier |
|
||
|-----------|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|
|
||
| 1x1 | x | x | x | x | x | x | x | x |
|
||
| 1x2 | | x | x | x | x | x | x | x |
|
||
| 1x3 | | x | x | x | x | x | x | x |
|
||
| L-shape | | x | x | x | x | x | x | x |
|
||
| 2x2 | | | | x | x | x | x | x |
|
||
| 3x3 | | | | | | x | x | |
|
||
| 2x6 | | | | | | | | x |
|
||
|
||
Maximum simultaneous (disjoint) placements: m guns — cruiser 2,
|
||
battlecruiser 3, battleship 4; l guns — battleship 1, dreadnought 3;
|
||
drone hangar — carrier 1.
|
||
|
||
## Production tree
|
||
|
||
Design principle: each game phase adds exactly one new base input chain, so
|
||
factory complexity ramps alongside ship size.
|
||
|
||
| Phase | New input | How acquired | Unlocks |
|
||
|-------|-----------|--------------|---------|
|
||
| early | iron_ore, copper_ore | mined | drone, frigate, destroyer; small guns and basic supports |
|
||
| mid | titanium_ore | mined (3x slower than iron) | cruiser, battlecruiser; m guns, drone bay, weapon modifiers |
|
||
| late | advanced_alloy | ONLY from reprocessing salvaged scrap | battleship, dreadnought, carrier; l guns, drone hangar |
|
||
|
||
The advanced_alloy gate is the core loop hook: capital ship production
|
||
requires fighting (salvaging scrap from kills and reprocessing it), not just
|
||
mining. The reprocessing plant turns 5 scrap into iron/copper/titanium ingots
|
||
or advanced_alloy probabilistically.
|
||
|
||
Intermediate components, by tier:
|
||
|
||
- **Tier 2 (early):** copper_wire (copper), steel_plate (iron), circuit_board
|
||
(iron + wire), building_block (iron).
|
||
- **Tier 3 (mid):** mechanical_parts (steel + iron), targeting_unit (circuits
|
||
+ wire), drive_unit (steel + mechanical_parts + circuit), titanium_frame
|
||
(titanium + steel).
|
||
- **Tier 4 (late):** reinforced_plating (steel + advanced_alloy),
|
||
capital_core (targeting_unit + drive_unit + 2 advanced_alloy).
|
||
|
||
Hulls and modules consume intermediates of their tier: early items are built
|
||
from tier-2 parts, midgame items require tier-3 parts (deeper chains, more
|
||
assemblers), capital items require tier-4 parts (and therefore combat). Hull
|
||
items are named `<ship>_hull`; module items `<module>_module`. Every item has
|
||
an `[items.*]` entry in visuals.toml; hull item outlines match the ship's
|
||
fleet color from `[ships.*]`.
|
||
|
||
Consistency is checked by `tools/verify_recipes.py` — re-run it after editing
|
||
recipes, ship/module materials, or visuals:
|
||
|
||
python dota_factory/tools/verify_recipes.py
|
||
|
||
It verifies every consumed item has a producer, every item has a visuals
|
||
entry, flags orphaned items, and prints which items are reprocessing-only
|
||
(currently exactly advanced_alloy).
|
||
|
||
## Deliberate placeholders / open questions for later passes
|
||
|
||
- All new hulls have `threat.cost_formula = "0"` so enemy waves do not spawn
|
||
them yet (WaveSystem treats any ship with positive threat cost as wave-
|
||
eligible, regardless of unlock level). The balancing pass should set real
|
||
threat costs together with `default_modules` loadouts so waves spawn them
|
||
armed.
|
||
- All new hulls and all assembler recipes are `unlock_at_station_level = -1`
|
||
(available from the start) to make testing easy; the balancing pass should
|
||
stagger these so mid/lategame recipes drop as schematics from enemy defence
|
||
stations.
|
||
- Recipe quantities and durations are a first guess, deliberately roughly
|
||
tiered (capital hulls ~60 s, drones 4 s); the balancing pass tunes them.
|
||
- `drone_bay` and `drone_hangar` are footprint-only placeholders: the drone
|
||
launching capability does not exist in the simulation yet, so they define
|
||
no capability section.
|
||
- Renames in this pass: `laser_cannon_xs` → `laser_cannon_s` (the old 2x2
|
||
`laser_cannon_s` became `laser_cannon_m`), `armor_plate` → `armor_plates`,
|
||
`manuvering_thrusters` → `maneuvering_thrusters` (typo fix). Test data
|
||
under `bin/test/data/config` intentionally still uses the old ids — it is
|
||
an independent fixture set.
|