diff --git a/docs/progression_design.md b/docs/progression_design.md index 11c54a4..4674bfa 100644 --- a/docs/progression_design.md +++ b/docs/progression_design.md @@ -1,14 +1,274 @@ -# Recipe and Production Design +# Progression & Balancing Design -* two resources at the start -* third resource unlocked mid game -* forth resource unlocked end game but only gathered form scrap -* input items for recipes should make sense for what the recipe produces (maybe crystals for lasers, heat sinks for bigger lasers, etc.) -* different kinds of modules need a different radio of input materials and production time. example: armor plates are simple items. they need a lot of input materials but are fast to produce. shield modules are technically complex and need lots of time to make but don't need many input materials. but maybe higher tier input materials. -* output to input production time ratios: - * the most basic resource shall have a nice miner to smelter ratio (e.g. 1 miner to 2 smelters or 1 to 1) - * the next resource shall have a little more complex ratio (e.g. 2 miners to 3 smelters) - * some recipes shall have strange ratios - * for the really strange ones there shall be explicitly unlockable recipes that simplify the process a lot (e.g. for a production that involves t1 -> t2 -> t3 where t3 needs some strange amounts of t2 the unlockable recipe may do t1 -> t3 and make the ratios of the assemblers that need to be placed for 100% throughput nice) -* bigger version of module needs a new input that can be produced from some of the smaller version's inputs plus the rest of the smaller version's inputs plus a new lower level mat -* or maybe not? I want to archieve that the player can learn (by playing and experimenting) to set up the factory in a way that does not cost much more than what an unexperienced player would do, but allows to easily swap something out later and then the next size or tier can be produced without much rebuilding \ No newline at end of file +Rules and principles that govern the production tree, progression pacing, +and balancing. This document contains **rules only** — concrete content +(item lists, recipes, unlock levels, stat numbers) lives in the config files +and `content_design.md`; those numbers must follow the rules stated here. + +## Player-experience goals + +What each phase of a run should feel like: + +- **Early:** learning belts and ratios with forgiving chains. The building + block economy is the main constraint; the player bootstraps a + self-sustaining factory from the starting stock. +- **Mid:** deeper chains, the first real ratio puzzles, and the first + meaningful drop decisions (which schematic, when to push). +- **Late:** combat feeds the factory — capital production requires salvage. + Progress means extending and refactoring the existing factory, not + rebuilding it. Strange ratios are deliberate optimization puzzles. + +Overarching: an experienced player gains efficiency through **knowledge** — +layout foresight, understanding chains, exploiting shortcut recipes — never +through hidden mechanics. An inexperienced setup should not cost much more +than an experienced one; experience pays off in how easily the factory +adapts later (see Refactorability). + +## Resource phases + +- A run has exactly **four base inputs**: + 1. Two mined ores available from the start. + 2. A third mined ore unlocked mid-game (slower to mine than the starting + ores). + 3. A fourth input unlocked late-game, obtainable **only** from + reprocessing salvaged scrap. +- The fourth input is the core loop hook: capital ship production requires + fighting (salvaging and reprocessing), not just mining. +- There is no direct "resource unlock" mechanism. Miner recipes unlock + **implicitly** (REQ-LOCK-IMPLICIT) when some unlocked schematic's material + chain reaches that ore. Resource pacing is therefore controlled entirely + through the `unlock_at_station_level` values of ships, modules, and + assembler recipe schematics — and the content must guarantee that the + chains actually connect (a mid-game schematic must require an item whose + chain reaches the third ore, or the ore never unlocks). + +## Production tree rules + +### Structure + +- **One new base input chain per phase.** Factory complexity ramps + alongside ship size; no phase adds more than one new bottom-level chain. +- **Intermediates are generic shared parts.** Keep the item count low — + modules and hulls of a tier draw from a shared pool of that tier's + intermediates rather than each having bespoke inputs. +- **Thematic naming over thematic items.** Inputs should be plausible for + what the recipe produces (crystals for lasers, heat sinks for bigger + lasers). Achieve this through naming and chain membership, not by adding + item types: rename a generic part, don't add a parallel one. + +### Ratios + +- **Ratio "niceness" degrades with tier.** The producer:consumer ratios + needed for 100% throughput follow a curve: + - Tier 1 (ore → basic material): trivially nice (e.g. 1:1 or 1:2 + miner:smelter). + - Tier 2: slightly complex but still clean (e.g. 2:3). + - Higher tiers: increasingly strange ratios, as deliberate optimization + puzzles. +- Exceptions in both directions are allowed when there is a reason — a + clean late chain as a breather, an odd early chain as a teaser — but the + curve is the default. + +### Shortcut recipes + +- Some strange chains get a **shortcut recipe**: an explicitly unlockable + assembler recipe schematic (`unlock_at_station_level ≥ 0`, drop-only per + REQ-LOCK-EXPLICIT) that skips a step (e.g. t1 → t3 directly) and yields + nice ratios for a chain whose base path is strange. +- **Not every strange chain gets a shortcut.** Some strangeness is + permanent; the absence of a fix is a valid design choice. +- **Shortcuts are pure rewards, never balance factors.** An item's threat + value is the *maximum* across its producing recipes (REQ-THREAT-ITEM), so + unlocking a cheaper recipe does not lower the item's threat accounting — + the player gains real factory efficiency without their ships being + valued cheaper and without enemy wave budgets shifting. Consequently: + **balance every chain around its base (expensive) path**; the shortcut's + savings define the size of the reward. + +### Refactorability + +- **Rule (the property):** unlocking the next tier or size of a thing must + be an *extension* of the existing production line — adding assemblers and + belts to what is already built — never a teardown and rebuild. +- **Default technique:** the bigger version introduces one new intermediate + that is produced from a subset of the smaller version's inputs (possibly + plus one additional low-tier material), and otherwise reuses the smaller + version's inputs. Existing lines keep running and feed the new + intermediate's assemblers. +- The property is the rule; the technique is only the default. It may be + broken where it fights thematic plausibility, as long as the property + still holds. + +## Cost archetypes + +Every item has two cost knobs: **material quantity** and **cycle time**. +Both feed the threat value identically (threat = recursive +production-seconds, REQ-MOD-THREAT), so the split between them does not +change what an item is *worth* — it changes what kind of **factory +pressure** it creates: + +- **Material-heavy, fast** (e.g. armor plates): simple items; stress belt + throughput, splitter logistics, and miner/smelter counts. +- **Time-heavy, lean** (e.g. shield modules): technically complex items; + few inputs — possibly higher-tier ones — but long cycles; stress + assembler counts and parallelization. + +**Rule:** each module family commits to a clear archetype, so factories +supporting different fleet doctrines feel structurally different to build. + +## Threat model (balancing backbone) + +- Threat cost = total recursive production-seconds (REQ-MOD-THREAT). One + factory-second equals one threat; player output and enemy wave budgets + are denominated in the same currency. +- **Rule: combat power per threat is roughly constant** across all ships, + modules, and tiers. Higher tiers are better per *ship* and per *module + slot*, not per invested factory-second — their advantage is + concentration (fewer, bigger things; slot geometry per + `content_design.md`) and qualitative capabilities, not a better exchange + rate. Deviations from this rule are deliberate and documented. +- **Difficulty race:** the enemy threat rate (`threat_rate_formula`) is + tuned against the factory output (threat/s) achievable by a competent + player — slightly below it early, crossing above it eventually. The game + is endless; enemy scaling must ultimately outpace any factory, and + player skill shifts *when*, not *whether*. +- **All time scaling lives in the threat rate** — waves get bigger, ships + of a given schematic never get individually stronger. There is no ship + level dimension: stat formulas are plain values, and per-ship level + scaling (`ship_level_formula`) does not exist (see Action items). Push + scaling on enemy defence stations is the separate, player-triggered + difficulty axis and keeps its level formulas. + +## Unlock & drop pacing + +- **Starting set rule:** the schematics unlocked at game start + (`unlock_at_station_level = -1`) must be exactly enough to reach the + first push unaided — a functioning block loop, small hulls, a basic + weapon, and the salvage loop. Nothing more. +- The `unlock_at_station_level` ladder mirrors the resource phases: + mid-tier hulls/modules/recipes at low station levels, capital content at + higher levels. A schematic must not become available before the chains + its materials need can be unlocked alongside it. +- **No duplicate drops.** Ship and module schematics leave the drop pool + once owned, exactly as assembler recipe schematics already do. There are + no schematic level-ups; player power grows through unlock breadth and + factory scale only, which keeps power-per-threat exact on both sides. + The pool therefore shrinks over a run and late pushes increasingly offer + artifacts — intended: the late game is a race for the win condition. + Per-item progression may return later as Mk2 upgrade recipes (see Open + tasks), never as free level-ups. +- **Artifacts trade power for progress.** Artifact options compete with + schematic picks in the same choice dialog; the artifact chance must be + tuned so that taking one is a real decision (giving up a level-up or + unlock), not automatic in either direction. + +## Scrap & reprocessing economy + +- Scrap is the bridge from combat back into the factory, with two sinks: + **smelting** (same basic materials as ore — the safe, boring option) and + **reprocessing** (probabilistic higher intermediates, including the + late-game input — the gamble that eventually becomes mandatory). +- The reprocessing output pool renormalizes over implicitly unlocked items + (REQ-LOCK-REPROCESSING-POOL), so its output quality improves + automatically as the run progresses. **Rule:** weights are authored for + the *fully unlocked* pool state; early-game behavior falls out of + renormalization for free and needs no separate staging. +- **Rule: ship scrap drops are derived, never authored.** A destroyed ship + drops `threat cost × scrap_per_threat` (a `world.toml` key), with the + threat cost computed from its actual hull plus installed modules + (REQ-MOD-THREAT) — a kitted-out ship drops more scrap than a bare hull + automatically. `ships.toml` carries no scrap value. Defence stations are + the exception: they keep authored `scrap_drop_formula`s, because pushing + rewards are tuned independently of ship production costs. +- Consequence: the threat value of scrap is the constant + `1 / scrap_per_threat`. The min-`scrap_drop` schematic derivation + (REQ-THREAT-SCRAP) and its potential circularity disappear. +- **Rule:** the late-game input's income rate meaningfully gates capital + production. The tuning target is expressed as "capital ships per boss + cycle for a player who fights at parity", not as an absolute rate. + +## Building block economy + +- Building blocks are the only global currency and the early game's + central constraint. The early game is a bootstrap problem: convert the + starting stock into a self-sustaining block loop before the first waves + bite. +- **Rule:** the starting stock suffices for a minimal block loop plus the + first shipyard — with a little slack for beginner mistakes, but not + enough to skip the loop entirely. +- **Rule:** asteroid expansions compete with buildings for the same + currency. Expansion pricing makes "more space" a real alternative to + "more stuff", not an afterthought. + +## Numeric guardrails + +Constraints that every recipe must respect, independent of tuning: + +- **Belt throughput:** belt speed and per-tile capacity cap how fast a + single belt can feed an input. A recipe whose per-cycle inputs cannot be + sustained by one belt per input at 100% duty cycle is a *deliberate* + design (forcing parallel belts/splitters as part of a high-tier puzzle) + — never an accident of quantity choice. +- **Buffer burstiness:** input buffers hold 2× the per-cycle amount + (REQ-MAT-INPUT-BUFFER), so large per-cycle quantities create bursty belt + demand. Low tiers prefer small quantities with short cycles; big-batch + recipes are reserved for high tiers where burstiness is part of the + puzzle. +- **Cycle times scale with tier** monotonically — a higher-tier item never + has a shorter total chain time than a lower-tier item of the same role. + +## Open tasks / future work + +- **Rework `recipes.toml`** once the rules in this document are fixed: the + current tree feels too close to Factorio; apply the thematic-naming rule + and the ratio curve to it (renames and quantity changes, not new items). +- **Balancing pass** (see placeholders in `content_design.md`): set the + `unlock_at_station_level` ladder, real threat costs and + `default_modules`, reprocessing weights, and the threat-rate formulas + according to the rules above. +- **Mk2 upgrade recipes** — the deferred design for per-item progression, + to revisit once the config has stabilized. A duplicate-style drop + unlocks a distinct `*_mk2` item whose recipe consumes the Mk1 item plus + higher-tier parts. This preserves power-per-threat (the extra power is + paid in real production-seconds, since threat is recursive), satisfies + the refactorability rule (the Mk1 line keeps running and feeds one new + assembler), and keeps balancing one-dimensional (no level variable + anywhere). Enemy-side progression happens via `default_modules` + variants per era instead of a level formula. + +## Action items — changes beyond this document + +Agreed changes that require edits to `requirements.md`, the code, and the +configs: + +1. **Derive ship scrap from threat.** Add `scrap_per_threat` to + `world.toml`; remove `[ship.loot].scrap_drop` from `ships.toml`; update + REQ-RES-SCRAP-DROP; replace REQ-THREAT-SCRAP with the constant + `1 / scrap_per_threat`. Station `scrap_drop_formula`s stay. +2. **Remove schematic upgrades.** Owned ship/module schematics leave the + drop pool (REQ-DEF-SCHEMATIC-DROP); drop the new-unlock/level-up + annotation from the choice dialog; remove `player_production_level` + from `ships.toml`, `modules.toml`, and the code paths that increment + and evaluate it (REQ-BLD-SHIPYARD, REQ-MOD-CONFIG). +3. **Remove ship levels entirely.** Delete `ship_level_formula` + (REQ-WAV-SHIP-LEVEL); replace all stat formulas in `ships.toml` and + `modules.toml` with plain values (REQ-SHP-STATS, REQ-MOD-CONFIG, + REQ-MOD-STAT-CALC evaluation rules). Enemy defence stations keep their + station-level formulas — push scaling is unaffected. +4. **Balancing tool follow-up.** Remove the per-ship-entry `level` from + `balancing.toml` and the `L` display format (REQ-BAL-TEAM, + REQ-BAL-CONFIG-GAME, REQ-BAL-UI-WIDGET, REQ-BAL-UI-INSPECT-WINDOW); + station entries keep their level. Ship stats panels no longer evaluate + at a level (REQ-MOD-UI-STATS-PANEL, REQ-UI-SHIP-STATS-PANEL). +5. **Fill unfillable schematic slots with artifacts.** With duplicates + removed, the schematic drop pool can run dry — previously unreachable. + Decision: every slot in the choice dialog that cannot be filled with a + schematic because the eligible pool is exhausted is filled with an + artifact option instead (in addition to any artifact option granted by + the regular artifact roll). A push therefore always awards a full + dialog. Update REQ-DEF-SCHEMATIC-DROP. +6. **Confirm wave scaling carries alone.** With per-ship level scaling + gone, `threat_rate_formula` is the only time-scaling axis; verify the + current `world.toml` values still produce the intended difficulty + curve (the config reportedly already runs with a flat ship level, so + this is likely a review, not a retune).