# Machine Tuning

`data/machines.json` holds every placeable machine: the drills and excavators that dig for
you, the processors that refine materials, the pumps and explosives, the ritual structures,
the forest buildings (sawmill, hunting lodge, apothecary), and the class-landmark machines.
Change these to set how fast machines work, how much fuel they hold, how long they last, what
it costs to repair them, and how many you may place at once.

## In plain terms

A machine is one entry in `machines.json`. Machines fall into a few families, each leaning on
different fields:

- **Miners** (drills, excavators) — dig terrain automatically. Their key fields are
  `work_rate` (dig speed), `max_fuel` (tank size), and `durability_min`/`durability_max` (how
  many tiles before they wear out).
- **Processors** — turn one material into another via a `recipe_id`. They have `work_rate 0`
  and `max_fuel 0` (they run off the recipe, not fuel), a 3x3 `footprint`, and a durability
  measured in *process cycles*.
- **Structures and buildings** — the Astrolabe, binding stakes, pumps, sawmill, lodge, and
  apothecary, each with their own extra schema.
- **Class landmarks** — champion-only signature machines (the Miner's Deepdrill, the Smith's
  Grand Anvil), unlocked at skill node 3 and capped at one each.

Terms:

- **footprint** — the tile rectangle a machine occupies (`footprint_w` x `footprint_h`).
- **work_rate** — for a miner, terrain hit points removed per second, multiplied by the
  quality of the fuel burning (`work_rate_mult` on the fuel material). For processors it is 0.
- **durability** — a wear count rolled once per placement between `durability_min` and
  `durability_max`. For miners it is tiles dug; for processors it is process cycles run. When
  it hits zero the machine breaks and must be repaired.

## The tuning fields

| Setting | Where it lives | What it controls | Turn it up / down |
|---|---|---|---|
| `work_rate` | `machines.json` → `<machine>` | Miner dig speed: terrain HP removed per second (times fuel quality). `0` for processors. | Higher = faster automated digging. Fallback `5.0` if missing. |
| `max_fuel` | `machines.json` → `<machine>` | Fuel tank size in seconds of burn the machine can hold. `0` for fuel-less processors. | Higher = longer unattended running before a refuel. |
| `fuel_material` | `machines.json` → `<machine>` | Restricts a machine to one specific fuel (only the Astrolabe uses this, requiring `strange_root`). Absent = accepts any `is_fuel` material. | Set to lock a machine to one fuel; leave out for general fuels. |
| `footprint_w` / `footprint_h` | `machines.json` → `<machine>` | The tile rectangle the machine occupies and must have clear to place. | Bigger footprints are harder to fit; keep processors at 3x3 for consistency. |
| `dig_width` | `machines.json` → `<machine>` | For excavators and the Deepdrill: how many tiles wide a single pass cuts. | Wider = clears more per pass; pairs with the footprint width. |
| `directional` | `machines.json` → `<machine>` | If true, the player picks a dig direction on placement (Steam Excavator only). | Cosmetic/control flag, not a balance number. |
| `is_processor` | `machines.json` → `<machine>` | Marks a recipe-driven refiner (true) versus a miner/structure (false). | Determines which fields apply; do not flip on an existing machine. |
| `recipe_id` | `machines.json` → `<machine>` | The recipe (in `recipes.json`) a processor runs. | Points a processor at what it makes; the cost/time is in the recipe. |
| `selectable_recipes` | `machines.json` → `<machine>` | For a multi-output processor (Glazing Kiln, Grand Anvil): the list of recipes the player can switch between. | Add recipe ids to give one machine multiple outputs. |
| `recipe_picker_label` | `machines.json` → `<machine>` | The header shown over a multi-output processor's recipe picker (the Anvil says `FORGE OUTPUT`, the kiln keeps `GLAZE TARGET`). | Presentation only, not a balance number. |
| `durability_min` / `durability_max` | `machines.json` → `<machine>` | The range a machine's lifespan is rolled from on placement — tiles (miners) or cycles (processors). `0`/`0` means it never wears (Astrolabe, stakes). | Higher = machines last longer between repairs. |
| `repair_cost` | `machines.json` → `<machine>` | Gold price to repair a broken machine. Alternatively the player can pay materials (see repair economy). | Higher = pricier to keep a machine running. Fallback `5`. |
| `repair_materials` | `machines.json` → `<machine>` | For recipe-less buildings/miners (sawmill/lodge/apothecary/Deepdrill): the explicit material cost of a materials-repair. | The buildings' repair bill; processors instead charge 2x their recipe inputs. |
| `max_placed` | `machines.json` → `<machine>` | How many of this machine may be active at once. If omitted or `0`, a script fallback of **2** applies. Explosives use `0` to mean "not a persistent placement". | Higher = more of that machine running in parallel. |
| `process_section` | `machines.json` → `<machine>` | Menu grouping flag (`buildings`) for pumps and forest buildings. | Organizational, not a balance number. |
| `no_fuel` / `support_bonus` / `gold_per_pop` / `food_per_day` / `wall_line` | `machines.json` → `<machine>` | Landmark-only fields for the fuel-less class buildings (Mead Hall, Trading Post, Bulwark) and the Smokehouse. | See [Village Buildings](/docs/underroot/village-buildings) for these four. |

### The `max_placed` fallback

Any machine that omits `max_placed` (all the processors, and the mechanical/hydraulic/steam
excavators) is capped at **2** active copies by the script constant
`GameConstants.MACHINE_DEFAULT_MAX_PLACED`, applied through `_placement_cap()` in
`MachineController`. The JSON value overrides it when present (drills allow 3, forest buildings
1, the Astrolabe 1, both class-landmark machines 1). To let a player place more of a
processor, add an explicit `max_placed` to its entry. A missing key never means "unlimited".

## Miners (drills and excavators)

Drills dig a single column downward; excavators cut a 3-wide swath. Fuel quality
(`work_rate_mult` on the burning fuel) multiplies `work_rate`, so better fuel digs faster.

| Machine | Family / tier | `work_rate` | `max_fuel` | Footprint | `dig_width` | Durability (min/max = tiles) | `max_placed` |
|---|---|---|---|---|---|---|---|
| Drill | drill 1 | `5.0` | `500` | 1x1 | — | `50` / `50` | `3` |
| Hydraulic Drill | drill 2 | `8.0` | `400` | 1x1 | — | `60` / `60` | `3` |
| Steam Drill | drill 3 | `12.0` | `600` | 1x1 | — | `100` / `100` | `3` |
| Mechanical Excavator | excavator 1 | `5.0` | `400` | 3x1 | `3` | `40` / `40` | fallback 2 |
| Hydraulic Excavator | excavator 2 | `7.0` | `600` | 3x1 | `3` | `70` / `70` | fallback 2 |
| Steam Excavator | excavator 3 | `10.0` | `800` | 3x1 | `3` | `120` / `120` | fallback 2 |

The Steam Excavator is `directional` — the player chooses which way it cuts.

## Processors

Recipe-driven refiners. All share `work_rate 0`, `max_fuel 0`, and a 3x3 footprint; they wear
by process cycles (`durability_min`/`max`) and repair for gold (`repair_cost`) or for 2x their
recipe inputs. None specify `max_placed`, so each caps at 2. The exceptions are the Glazing Kiln
and the Grand Anvil, which set `max_placed` explicitly and carry a `selectable_recipes` list.

| Machine | `recipe_id` | Durability (min/max cycles) | `repair_cost` (gold) |
|---|---|---|---|
| Smelter | `smelt_iron` | `40` / `60` | `25` |
| Forge | `smelt_bronze` | `24` / `40` | `35` |
| Blast Furnace | `smelt_steel` | `20` / `36` | `65` |
| Stone Kiln | `fire_cement` | `24` / `40` | `55` |
| Glass Crucible | `fuse_glass` | `20` / `32` | `70` |
| Glazing Kiln | `glaze_stone` (+5 selectable) | `24` / `40` | `60` |
| Fossil Grinder | `grind_fossils` | `30` / `50` | `50` |
| Pressure Vat | `press_slurry` | `30` / `50` | `60` |
| Alembic | `brew_binding_resin` | `30` / `50` | `45` |
| Lime Kiln | `fire_refined_lime` | `24` / `44` | `50` |
| Root Still | `distill_amber_oil` | `24` / `40` | `45` |
| Whetstone Mill | `grind_wavellite_flux` | `24` / `40` | `45` |
| Crucible Forge | `smelt_refined_iron` | `20` / `36` | `55` |
| Slag Press | `press_obsidian_plate` | `20` / `36` | `60` |
| Alloy Furnace | `alloy_chromium` | `20` / `32` | `70` |
| Binding Press | `press_vault_block` | `24` / `40` | `80` |
| Fermentation Vat | `ferment_ethanol` | `24` / `44` | `45` |

The Glazing Kiln's `selectable_recipes` are `glaze_stone`, `glaze_dense_stone`, `glaze_cement`,
`glaze_iron`, `glaze_bronze`, `glaze_steel` — the player picks which block it glazes.

### The repair economy

A broken machine repairs two ways (`MachineManager`):

- **With gold** — pay the machine's `repair_cost` in gold. Fallback is `5` if the key is
  absent.
- **With materials** — recipe-less buildings (sawmill, lodge, apothecary) and the Deepdrill
  charge the explicit `repair_materials` on their entry; every other processor charges **2x its
  recipe's input materials**. Either way the machine resets to full durability.

## Structures, pumps, and explosives

| Machine | Footprint | Key fields |
|---|---|---|
| Terrestrial Astrolabe | 6x4 | `max_fuel 600`, `fuel_material strange_root`, `max_placed 1`, no durability (0/0) |
| Binding Stake | 1x1 | `max_placed 3`, no durability — three required to fire the Astrolabe |
| Pump | 1x1 | `max_placed 3`, `requires_well true`, `lifespan_days 2`, `water_output 50` |
| Dynamite | 1x1 | `is_explosive true`, single-use, `max_placed 0` |
| Mining Charge | 1x1 | `is_explosive true`, directional 2x7 blast, `max_placed 0` |

The pump fills the well over its 2-day `lifespan_days`, delivering `water_output` (50), then
wears out. Placing it **claims the adjacent water pocket**: the discovery is consumed on the
spot (no dig reward on top — the pump's well delivery is the extraction), so a pocket can't
also be dug for its reward or feed a second pump. The terrain tiles themselves are never
touched. Offline, the pump keeps delivering on the idle clock. Explosives use `max_placed 0`
to mark a one-shot consumable rather than a standing machine.

## Class landmark machines

Two of the six class landmarks are machines, unlocked at **skill node 3** for their champion
and capped at **1** each. Their recipes gate via `unlock_requires_champion_skill` +
`unlock_requires_skill_node` in `recipes.json`. The other four landmarks are village buildings —
see [Village Buildings](/docs/underroot/village-buildings). Skill/class context lives in
[Skills, Classes, and Handicaps](/docs/underroot/skills-classes-and-handicaps).

### Deepdrill — Miner

A `2x1` underground auto-miner that descends and digs on its own, through any stone. It reuses
the excavator/drill tick (`is_processor false`) but cuts a 2-wide pass.

| Setting | Where it lives | Default | What it controls |
|---|---|---|---|
| `work_rate` | `machines.json` → `deepdrill` | `12.0` | Terrain HP per second (times fuel quality) — tops the Steam Drill's rate. |
| `dig_width` | `machines.json` → `deepdrill` | `2` | Tiles wide per pass (matches the 2-wide footprint). |
| `max_fuel` | `machines.json` → `deepdrill` | `2000` | Fuel-tank size in seconds. |
| `durability_min` / `durability_max` | `machines.json` → `deepdrill` | `250` / `250` | Fixed 250-tile lifespan ≈ **125 rows** at 2 tiles per row before repair. |
| `repair_cost` / `repair_materials` | `machines.json` → `deepdrill` | `150` gold, or 3 steel + 2 quartz | Repair bill (repairable). |
| `max_placed` | `machines.json` → `deepdrill` | `1` | One rig at a time. |

Offline the Deepdrill's durability is enforced in `MachineManager.simulate_offline` — it stops
at 250 tiles offline just as it does live, so a long absence never mines past its wear limit.

### Grand Anvil — Smith

A `3x3` **processor** (built on the glazing-kiln template) with a `selectable_recipes` picker
the player switches between. It's the only source of the game's toughest wall and unlocks a
masterwork pickaxe.

| Setting | Where it lives | Default | What it controls |
|---|---|---|---|
| `selectable_recipes` | `machines.json` → `grand_anvil` | `["forge_grand_alloy", "glaze_vault_block"]` | The two outputs: `grand_alloy` (a crafting material) and `glazed_vault_block`. |
| `recipe_picker_label` | `machines.json` → `grand_anvil` | `FORGE OUTPUT` | Header over the picker (the kiln says `GLAZE TARGET`). |
| `durability_min` / `durability_max` | `machines.json` → `grand_anvil` | `40` / `60` | Process-cycle lifespan. |
| `repair_cost` | `machines.json` → `grand_anvil` | `90` | Gold repair (or 2x recipe inputs). |
| `max_placed` | `machines.json` → `grand_anvil` | `1` | One forge at a time. |

The `glazed_vault_block` it glazes is the strongest wall in the game — `wall_hp 5000`,
`base_chew_resistance 7.0` (see [Materials and Mining Yield](/docs/underroot/materials-and-mining-yield)).
Forging `grand_alloy` also opens the `grand_pickaxe` masterwork recipe (tier-6 pick, 5000
durability, reaches tier-8 material) in [Tools and Durability](/docs/underroot/tools-and-durability).
Because both outputs are champion-gated, the Anvil shifts how powerful a Smith run feels rather
than the baseline; the vault-block's `wall_hp` is the number to watch if it makes the Maw
trivial.

## Forest buildings

These sit in the forest zone (west of an `forest_zone_max_x` boundary), burn fuel from a
`max_fuel 2500` tank (~7 game days / ~42 real minutes of continuous burn), and are all
`max_placed 1`. They repair with materials (`repair_materials`) and carry tiered upgrades.

**Sawmill** (2x2) — produces wood passively per day. Durability `250`/`350`, `repair_cost 250`,
`repair_materials` 16 wood / 12 iron / 12 stone. Daily wood output depends on the fuel burning
(`wood_by_fuel`): coal `12`, deep_coal `15`, crude_oil `18`, ethanol `21.6`. Three
`sawmill_upgrades` multiply output: Sharpened Blades `1.5x`, Steel Frame `2.5x`, Steam Engine
`4.0x`.

**Hunting Lodge** (3x2) — sends hunters out for food. Durability `40`/`60`, `repair_cost 150`,
`repair_materials` 8 wood / 6 stone / 6 iron. Timing knobs: `hunt_min_days 0.3` /
`hunt_max_days 0.7`, `rest_min_days 0.2` / `rest_max_days 0.5`, and a `hunt_death_chance 0.05`
(5% chance a hunt ends in a death). Base haul `base_food_min 4` / `base_food_max 8`, raised by
three `lodge_upgrades`: Trained Hunters `8-13`, Expert Trackers `13-20`, Master Hunters `20-35`.

**Apothecary** (3x2) — brews medicine that can save a dying villager. Durability `80`/`120`,
`repair_cost 500`, `repair_materials` 50 wood / 30 stone / 8 quartz / 2 ancient_clay. It brews
while it's fueled, stocked, and the water tower sits above `stored_water_floor 20`, spending
`water_per_dose 3` per dose. Daily dose output by fuel (`doses_by_fuel`): coal `6`, deep_coal
`8`, crude_oil `10`, ethanol `12`. Target stock defaults to `dose_target_default 10`, up to
`dose_target_max 50`. Three `dose_levels` set the save chance and ingredients:

| Dose level | `save_chance` | Ingredients per dose | Unlock `cost` |
|---|---|---|---|
| Tincture | `0.30` | 5 strange_root | — |
| Remedy | `0.60` | 5 strange_root, 1 amber_oil | 4 steel, 3 bronze, 2 root_amber |
| Panacea | `0.90` | 5 strange_root, 1 amber_oil, 1 refined_lime | 3 refined_iron, 1 binding_resin, 1 prismatic_shard |

## Offline behavior

While the game is closed, machines advance on the **idle clock** (elapsed time times the idle
multiplier, default 0.15): fuel burn and output scale together, so the fuel cost per unit of
output offline matches live play. The apothecary is the one exception — it brews at the full
clock because the villager-death sims it counters also run at the full clock. The Trading Post
trickles gold on the idle-scaled clock; the Deepdrill mines on the idle clock and stops at its
250-tile durability offline exactly as it does live. While the game is merely *unfocused* (tab
open in the background), machines run at full speed.

## Safe to change / handle with care

- **`work_rate`** on miners is multiplied by fuel quality and runs continuously. Small bumps
  compound into very fast automated digging that can outrun the whole survival loop. The
  Deepdrill already sits at the top of the range (`12.0`).
- **`durability_min`/`durability_max`** set the repair cadence. Narrow the range for
  predictable wear; widen it for variety. Set both to `0` and a machine is immortal, which is
  only intended for the Astrolabe and stakes.
- **`max_placed`** governs how much a player can parallelize. The fallback is 2 for any
  omitted key; to allow more, add the key explicitly. Both class-landmark machines are capped
  at 1 on purpose — they're signature, not spammable.
- **`max_fuel`** and the fuel materials' `fuel_seconds`/`work_rate_mult` (in `materials.json`)
  together set unattended runtime. Tune them as a pair.
- **Forest-building upgrade multipliers and hauls** (sawmill `output_mult`, lodge food ranges,
  apothecary `doses_by_fuel`) feed the village food/water economy directly, so large changes
  ripple into survival balance.

Any edit to `machines.json` needs the data validator and, for gameplay-affecting numbers, the
smoke test — see [The Safe Change Workflow](/docs/underroot/the-safe-change-workflow).

## Related

- [Materials and Mining Yield](/docs/underroot/materials-and-mining-yield)
- [Tools and Durability](/docs/underroot/tools-and-durability)
- [Village Buildings](/docs/underroot/village-buildings)
- [Skills, Classes, and Handicaps](/docs/underroot/skills-classes-and-handicaps)
- [The Astrolabe Consequence Curve](/docs/underroot/the-astrolabe-consequence-curve)
- [Survival and Supply Drain](/docs/underroot/survival-and-supply-drain)
- [The Safe Change Workflow](/docs/underroot/the-safe-change-workflow)