Implements REQ-MAT-OUTPUT-GROUP. A recipe had two shapes -- outputs produced together, or outputs of which exactly one happened -- and every rule over them was written twice, selected by `building == ReprocessingPlant`: sizing a buffer, deciding whether a cycle fits, resolving what a cycle makes, costing an item. RecipeDef now holds output groups, each a weight and a list of items, and a cycle yields exactly one group. One group is the ordinary recipe, so the old two cases are the same shape with one and with several, and all four rules collapse to one expression apiece with no building-type test left. rollReprocessingOutput becomes rollOutputGroup, where a single group returns without drawing or testing eligibility. That early-out is load-bearing twice over. Drawing there would consume entropy for every ordinary recipe and shift every later random outcome; and eligibility must not apply either, since implicit unlocking is demand-derived, so an ordinary recipe's output can be producible while nothing yet calls for it -- testing it would stop the building producing rather than gate a drop. Past the early-out a group is eligible only when all of its items are unlocked, being produced whole. Threat follows the recipe's shape rather than the building, and the per-unit value now divides by the group's amount as well as its odds. That moves no number today: every item resolved through this path has amount 1, which is why the threat expectations are untouched. Config keeps `outputs = [...]` as the single-group form, so only the two reprocessing recipes change shape. The recipe summary gains "/" between groups and keeps "+" within one, which also fixes the plant reading as though a cycle produced all of its items at once. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Ne3mejABZoLWKLh8fgpM3x
445 lines
14 KiB
TOML
445 lines
14 KiB
TOML
# recipes.toml
|
|
#
|
|
# Production tree v2 (structure in docs/content_design.md, numbers with
|
|
# derivations in docs/balancing/derived.md). Quantities and durations are tuned so that every
|
|
# fitted ship lands on the threat-cost ladder and the ratio curve is
|
|
# realized: tier 1 ratios are 1:1, tier 2 ratios are 2:3, tier 3+ ratios
|
|
# are deliberately strange.
|
|
#
|
|
# A recipe id names the process, not the product — the display name shown in
|
|
# the UI is derived from it — so an item and the recipe that makes it never
|
|
# carry the same name.
|
|
#
|
|
# Input chain per game phase — each phase transition adds exactly one new
|
|
# base input:
|
|
#
|
|
# early iron_ore + copper_ore minable on every asteroid tile (the
|
|
# asteroid is an M-type body — its bulk
|
|
# rock IS ore)
|
|
# mid + quartz geode deposits in expansion territory
|
|
# (deposit gating pending — see action
|
|
# item 5 in docs/balancing/README.md;
|
|
# until then quartz mines anywhere)
|
|
# late + voidsteel battle-forged: ONLY from reprocessing
|
|
# salvaged scrap, so capital production
|
|
# requires combat
|
|
#
|
|
# Run tools/verify_recipes.py and tools/threat_report.py after editing.
|
|
|
|
# -----------------------------------------------------------------------------
|
|
# Mining (tier 0)
|
|
# -----------------------------------------------------------------------------
|
|
|
|
[[recipe]]
|
|
id = "iron_mining"
|
|
building = "miner"
|
|
inputs = []
|
|
outputs = [{item = "iron_ore", amount = 1}]
|
|
duration_seconds = 1.0
|
|
|
|
[[recipe]]
|
|
id = "copper_mining"
|
|
building = "miner"
|
|
inputs = []
|
|
outputs = [{item = "copper_ore", amount = 1}]
|
|
duration_seconds = 1.0
|
|
|
|
[[recipe]]
|
|
id = "quartz_mining"
|
|
building = "miner"
|
|
inputs = []
|
|
outputs = [{item = "quartz", amount = 1}]
|
|
duration_seconds = 2.0
|
|
|
|
# -----------------------------------------------------------------------------
|
|
# Smelting (tier 1) — one recipe per input item; ratios are 1:1 with miners.
|
|
# -----------------------------------------------------------------------------
|
|
|
|
[[recipe]]
|
|
id = "iron_smelting"
|
|
building = "smelter"
|
|
inputs = [{item = "iron_ore", amount = 1}]
|
|
outputs = [{item = "iron_ingot", amount = 1}]
|
|
duration_seconds = 1.0
|
|
|
|
[[recipe]]
|
|
id = "copper_smelting"
|
|
building = "smelter"
|
|
inputs = [{item = "copper_ore", amount = 1}]
|
|
outputs = [{item = "copper_ingot", amount = 1}]
|
|
duration_seconds = 1.0
|
|
|
|
[[recipe]]
|
|
id = "quartz_reduction"
|
|
building = "smelter"
|
|
inputs = [{item = "quartz", amount = 1}]
|
|
outputs = [{item = "silicon", amount = 1}]
|
|
duration_seconds = 2.0
|
|
|
|
# Scrap smelting: the safe, boring sink. Deliberately value-losing (4 threat
|
|
# of scrap becomes a 2-threat ingot) — reprocessing is the value-preserving
|
|
# path.
|
|
[[recipe]]
|
|
id = "scrap_smelting"
|
|
building = "smelter"
|
|
inputs = [{item = "scrap", amount = 1}]
|
|
outputs = [{item = "iron_ingot", amount = 1}]
|
|
duration_seconds = 1.0
|
|
|
|
# -----------------------------------------------------------------------------
|
|
# Reprocessing — the only source of voidsteel (battle-forged; formed when
|
|
# weapon plasma anneals hull metal in the violence of ship destruction).
|
|
# Weights are authored for the fully unlocked pool state; the pool
|
|
# renormalizes over implicitly unlocked items early game.
|
|
# -----------------------------------------------------------------------------
|
|
|
|
[[recipe]]
|
|
id = "scrap_reprocessing"
|
|
building = "reprocessing_plant"
|
|
inputs = [{item = "scrap", amount = 4}]
|
|
duration_seconds = 4.0
|
|
|
|
[[recipe.output_group]]
|
|
probability = 0.3
|
|
items = [{item = "iron_ingot", amount = 1}]
|
|
|
|
[[recipe.output_group]]
|
|
probability = 0.3
|
|
items = [{item = "copper_ingot", amount = 1}]
|
|
|
|
[[recipe.output_group]]
|
|
probability = 0.2
|
|
items = [{item = "silicon", amount = 1}]
|
|
|
|
[[recipe.output_group]]
|
|
probability = 0.2
|
|
items = [{item = "voidsteel", amount = 1}]
|
|
|
|
# -----------------------------------------------------------------------------
|
|
# Tier 2 — early intermediates (clean ratios, ~2:3)
|
|
# -----------------------------------------------------------------------------
|
|
|
|
[[recipe]]
|
|
id = "steel_rolling"
|
|
building = "assembler"
|
|
inputs = [{item = "iron_ingot", amount = 2}]
|
|
outputs = [{item = "steel_plate", amount = 1}]
|
|
duration_seconds = 3.0
|
|
|
|
[[recipe]]
|
|
id = "wire_drawing"
|
|
building = "assembler"
|
|
inputs = [{item = "copper_ingot", amount = 1}]
|
|
outputs = [{item = "copper_wire", amount = 2}]
|
|
duration_seconds = 1.0
|
|
|
|
[[recipe]]
|
|
id = "coil_winding"
|
|
building = "assembler"
|
|
inputs = [{item = "copper_wire", amount = 2}]
|
|
outputs = [{item = "copper_coil", amount = 1}]
|
|
duration_seconds = 1.5
|
|
|
|
# Depth-3 chain (ore -> ingot -> plate -> block) is the factory's
|
|
# doubling-time knob; see the block economy rules in docs/balancing/rules.md.
|
|
# unlocked_at_start: building blocks appear in no schematic's materials, so the
|
|
# implicit item graph can never reach this recipe (REQ-LOCK-IMPLICIT).
|
|
[[recipe]]
|
|
id = "block_pressing"
|
|
building = "assembler"
|
|
unlocked_at_start = true
|
|
inputs = [{item = "steel_plate", amount = 2}]
|
|
outputs = [{item = "building_block", amount = 4}]
|
|
duration_seconds = 2.0
|
|
|
|
# -----------------------------------------------------------------------------
|
|
# Tier 3 — mid intermediates (strange ratios begin; need quartz)
|
|
# -----------------------------------------------------------------------------
|
|
|
|
[[recipe]]
|
|
id = "chip_etching"
|
|
building = "assembler"
|
|
inputs = [{item = "silicon", amount = 1}, {item = "copper_wire", amount = 2}]
|
|
outputs = [{item = "control_chip", amount = 1}]
|
|
duration_seconds = 5.0
|
|
|
|
[[recipe]]
|
|
id = "capacitor_assembly"
|
|
building = "assembler"
|
|
inputs = [{item = "copper_coil", amount = 2}, {item = "silicon", amount = 1}]
|
|
outputs = [{item = "capacitor_bank", amount = 1}]
|
|
duration_seconds = 5.0
|
|
|
|
# The quality gate for m+ hulls: a deliberately long-running recipe
|
|
# (time-heavy archetype).
|
|
[[recipe]]
|
|
id = "steel_hardening"
|
|
building = "assembler"
|
|
inputs = [{item = "steel_plate", amount = 3}]
|
|
outputs = [{item = "hardened_steel", amount = 1}]
|
|
duration_seconds = 12.0
|
|
|
|
[[recipe]]
|
|
id = "ceramic_firing"
|
|
building = "assembler"
|
|
inputs = [{item = "quartz", amount = 2}]
|
|
outputs = [{item = "ceramic_plate", amount = 1}]
|
|
duration_seconds = 4.0
|
|
|
|
[[recipe]]
|
|
id = "drive_assembly"
|
|
building = "assembler"
|
|
inputs = [
|
|
{item = "steel_plate", amount = 2},
|
|
{item = "copper_coil", amount = 2},
|
|
{item = "control_chip", amount = 1},
|
|
]
|
|
outputs = [{item = "drive_unit", amount = 1}]
|
|
duration_seconds = 8.0
|
|
|
|
# -----------------------------------------------------------------------------
|
|
# Tier 4 — late intermediates (need voidsteel)
|
|
# -----------------------------------------------------------------------------
|
|
|
|
[[recipe]]
|
|
id = "voidsteel_forging"
|
|
building = "assembler"
|
|
inputs = [{item = "voidsteel", amount = 1}, {item = "hardened_steel", amount = 1}]
|
|
outputs = [{item = "voidsteel_plate", amount = 1}]
|
|
duration_seconds = 8.0
|
|
|
|
[[recipe]]
|
|
id = "core_assembly"
|
|
building = "assembler"
|
|
inputs = [
|
|
{item = "voidsteel", amount = 2},
|
|
{item = "capacitor_bank", amount = 1},
|
|
{item = "control_chip", amount = 1},
|
|
]
|
|
outputs = [{item = "capital_core", amount = 1}]
|
|
duration_seconds = 10.0
|
|
|
|
# -----------------------------------------------------------------------------
|
|
# Shortcut recipes — drop-only assembler recipes, gated by unlock groups in
|
|
# unlocks.toml (REQ-LOCK-EXPLICIT). Pure rewards: item threat stays defined by
|
|
# the base (expensive) path via the max rule, so shortcuts give real factory
|
|
# efficiency without shifting any balance. Named "direct_*" after the base
|
|
# process they skip a step of, so the reward reads as what it is.
|
|
# -----------------------------------------------------------------------------
|
|
|
|
[[recipe]]
|
|
id = "direct_rolling"
|
|
building = "assembler"
|
|
inputs = [{item = "iron_ore", amount = 3}]
|
|
outputs = [{item = "steel_plate", amount = 1}]
|
|
duration_seconds = 2.0
|
|
|
|
[[recipe]]
|
|
id = "direct_etching"
|
|
building = "assembler"
|
|
inputs = [{item = "quartz", amount = 2}]
|
|
outputs = [{item = "control_chip", amount = 1}]
|
|
duration_seconds = 4.0
|
|
|
|
[[recipe]]
|
|
id = "direct_hardening"
|
|
building = "assembler"
|
|
inputs = [{item = "iron_ingot", amount = 4}]
|
|
outputs = [{item = "hardened_steel", amount = 1}]
|
|
duration_seconds = 8.0
|
|
|
|
# -----------------------------------------------------------------------------
|
|
# Ship hulls
|
|
# -----------------------------------------------------------------------------
|
|
|
|
[[recipe]]
|
|
id = "drone_framing"
|
|
building = "assembler"
|
|
inputs = [{item = "iron_ingot", amount = 1}]
|
|
outputs = [{item = "drone_hull", amount = 1}]
|
|
duration_seconds = 1.0
|
|
|
|
[[recipe]]
|
|
id = "frigate_framing"
|
|
building = "assembler"
|
|
inputs = [{item = "steel_plate", amount = 2}, {item = "copper_wire", amount = 1}]
|
|
outputs = [{item = "frigate_hull", amount = 1}]
|
|
duration_seconds = 2.0
|
|
|
|
[[recipe]]
|
|
id = "destroyer_framing"
|
|
building = "assembler"
|
|
inputs = [{item = "steel_plate", amount = 3}, {item = "copper_coil", amount = 2}]
|
|
outputs = [{item = "destroyer_hull", amount = 1}]
|
|
duration_seconds = 4.0
|
|
|
|
[[recipe]]
|
|
id = "cruiser_framing"
|
|
building = "assembler"
|
|
inputs = [{item = "hardened_steel", amount = 2}, {item = "control_chip", amount = 2}]
|
|
outputs = [{item = "cruiser_hull", amount = 1}]
|
|
duration_seconds = 6.0
|
|
|
|
[[recipe]]
|
|
id = "battlecruiser_framing"
|
|
building = "assembler"
|
|
inputs = [
|
|
{item = "hardened_steel", amount = 3},
|
|
{item = "control_chip", amount = 2},
|
|
{item = "drive_unit", amount = 1},
|
|
]
|
|
outputs = [{item = "battlecruiser_hull", amount = 1}]
|
|
duration_seconds = 8.0
|
|
|
|
[[recipe]]
|
|
id = "battleship_framing"
|
|
building = "assembler"
|
|
inputs = [
|
|
{item = "voidsteel_plate", amount = 3},
|
|
{item = "drive_unit", amount = 1},
|
|
{item = "control_chip", amount = 2},
|
|
]
|
|
outputs = [{item = "battleship_hull", amount = 1}]
|
|
duration_seconds = 10.0
|
|
|
|
[[recipe]]
|
|
id = "dreadnought_framing"
|
|
building = "assembler"
|
|
inputs = [
|
|
{item = "voidsteel_plate", amount = 5},
|
|
{item = "capital_core", amount = 1},
|
|
{item = "drive_unit", amount = 2},
|
|
]
|
|
outputs = [{item = "dreadnought_hull", amount = 1}]
|
|
duration_seconds = 12.0
|
|
|
|
[[recipe]]
|
|
id = "carrier_framing"
|
|
building = "assembler"
|
|
inputs = [
|
|
{item = "voidsteel_plate", amount = 5},
|
|
{item = "capital_core", amount = 1},
|
|
{item = "drive_unit", amount = 2},
|
|
]
|
|
outputs = [{item = "carrier_hull", amount = 1}]
|
|
duration_seconds = 12.0
|
|
|
|
# -----------------------------------------------------------------------------
|
|
# Module prefabs
|
|
# -----------------------------------------------------------------------------
|
|
|
|
[[recipe]]
|
|
id = "railgun_s_kit"
|
|
building = "assembler"
|
|
inputs = [{item = "copper_coil", amount = 1}]
|
|
outputs = [{item = "railgun_s_module", amount = 1}]
|
|
duration_seconds = 1.0
|
|
|
|
[[recipe]]
|
|
id = "salvager_kit"
|
|
building = "assembler"
|
|
inputs = [{item = "steel_plate", amount = 1}, {item = "copper_wire", amount = 2}]
|
|
outputs = [{item = "salvager_module", amount = 1}]
|
|
duration_seconds = 2.0
|
|
|
|
[[recipe]]
|
|
id = "repair_tool_kit"
|
|
building = "assembler"
|
|
inputs = [{item = "steel_plate", amount = 1}, {item = "copper_wire", amount = 2}]
|
|
outputs = [{item = "repair_tool_module", amount = 1}]
|
|
duration_seconds = 2.0
|
|
|
|
# Material-heavy, fast: the armor archetype.
|
|
[[recipe]]
|
|
id = "armor_plates_kit"
|
|
building = "assembler"
|
|
inputs = [{item = "steel_plate", amount = 4}]
|
|
outputs = [{item = "armor_plates_module", amount = 1}]
|
|
duration_seconds = 3.0
|
|
|
|
[[recipe]]
|
|
id = "maneuvering_thrusters_kit"
|
|
building = "assembler"
|
|
inputs = [{item = "steel_plate", amount = 1}, {item = "copper_coil", amount = 1}]
|
|
outputs = [{item = "maneuvering_thrusters_module", amount = 1}]
|
|
duration_seconds = 2.0
|
|
|
|
[[recipe]]
|
|
id = "sensor_booster_kit"
|
|
building = "assembler"
|
|
inputs = [{item = "copper_wire", amount = 2}, {item = "copper_coil", amount = 1}]
|
|
outputs = [{item = "sensor_booster_module", amount = 1}]
|
|
duration_seconds = 2.0
|
|
|
|
[[recipe]]
|
|
id = "afterburner_kit"
|
|
building = "assembler"
|
|
inputs = [{item = "copper_coil", amount = 2}, {item = "steel_plate", amount = 1}]
|
|
outputs = [{item = "afterburner_module", amount = 1}]
|
|
duration_seconds = 3.0
|
|
|
|
[[recipe]]
|
|
id = "weapon_stabilizer_kit"
|
|
building = "assembler"
|
|
inputs = [{item = "steel_plate", amount = 1}, {item = "copper_coil", amount = 1}]
|
|
outputs = [{item = "weapon_stabilizer_module", amount = 1}]
|
|
duration_seconds = 2.0
|
|
|
|
[[recipe]]
|
|
id = "weapon_primer_kit"
|
|
building = "assembler"
|
|
inputs = [{item = "capacitor_bank", amount = 1}, {item = "copper_coil", amount = 1}]
|
|
outputs = [{item = "weapon_primer_module", amount = 1}]
|
|
duration_seconds = 4.0
|
|
|
|
[[recipe]]
|
|
id = "weapon_upgrade_kit"
|
|
building = "assembler"
|
|
inputs = [{item = "control_chip", amount = 1}, {item = "copper_coil", amount = 1}]
|
|
outputs = [{item = "weapon_upgrade_module", amount = 1}]
|
|
duration_seconds = 4.0
|
|
|
|
[[recipe]]
|
|
id = "railgun_m_kit"
|
|
building = "assembler"
|
|
inputs = [
|
|
{item = "capacitor_bank", amount = 1},
|
|
{item = "steel_plate", amount = 2},
|
|
{item = "copper_coil", amount = 1},
|
|
]
|
|
outputs = [{item = "railgun_m_module", amount = 1}]
|
|
duration_seconds = 4.0
|
|
|
|
[[recipe]]
|
|
id = "drone_bay_kit"
|
|
building = "assembler"
|
|
inputs = [
|
|
{item = "control_chip", amount = 1},
|
|
{item = "steel_plate", amount = 2},
|
|
{item = "copper_coil", amount = 1},
|
|
]
|
|
outputs = [{item = "drone_bay_module", amount = 1}]
|
|
duration_seconds = 4.0
|
|
|
|
[[recipe]]
|
|
id = "railgun_l_kit"
|
|
building = "assembler"
|
|
inputs = [
|
|
{item = "capacitor_bank", amount = 1},
|
|
{item = "hardened_steel", amount = 2},
|
|
{item = "ceramic_plate", amount = 1},
|
|
]
|
|
outputs = [{item = "railgun_l_module", amount = 1}]
|
|
duration_seconds = 6.0
|
|
|
|
[[recipe]]
|
|
id = "drone_hangar_kit"
|
|
building = "assembler"
|
|
inputs = [
|
|
{item = "voidsteel_plate", amount = 1},
|
|
{item = "control_chip", amount = 2},
|
|
{item = "drive_unit", amount = 1},
|
|
]
|
|
outputs = [{item = "drone_hangar_module", amount = 1}]
|
|
duration_seconds = 10.0
|