Commit Graph

266 Commits

Author SHA1 Message Date
b4fa3e6dff Restructure balancing docs into docs/balancing/
Split the cluttered progression_design.md and content_design.md into
separated documents by role:

- docs/balancing/rules.md    - design rules and principles (moved from
                               progression_design.md, which is removed)
- docs/balancing/targets.md  - the chosen base numbers: run shape,
                               factory curve, threat ladder (achieved
                               values adopted), combat anchors, pacing
                               anchors
- docs/balancing/derived.md  - current tuned state of all derived
                               numbers, mirroring the configs
- docs/balancing/process.md  - pass order, tuning discipline learned in
                               arena rounds 1-5, tools, next-round
                               checklist
- docs/balancing/history.md  - chronological record: decisions, numbers
                               pass, calculator bugs, arena rounds,
                               pacing pass
- docs/balancing/README.md   - index, status, open action items (moved
                               from progression_design.md)

content_design.md slims back down to actual content: footprint gating,
hull grids, gating matrix (module names updated to railguns), and the
production tree structure with its fiction - numbers, anchors, arena
logs, and pacing all moved to docs/balancing/. Stale references in the
config comments updated to the new locations.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DyCu8vwChKMbLJQ3xosYEN
2026-07-06 17:15:08 +02:00
dcc6af123f implement cost formula for asteroid expansion 2026-07-04 19:59:29 +02:00
f62b7bb78e Pacing pass: unlock ladder, threat rate, economy values
Replace the everything-at--1 test setup with the real progression:
starting set is exactly drone/frigate/railgun_s/salvager; the ladder
runs destroyer+repair+armor at level 0, supports at 1, the quartz gate
(cruiser, railgun_m, afterburner, chip/hardened shortcuts) at 2,
battlecruiser at 4, battleship+railgun_l at 6, dreadnought at 8,
carrier+drone_hangar at 9, with unlock_requires edges cruiser ->
battlecruiser -> battleship -> dreadnought/carrier and railgun_m ->
railgun_l.

world.toml: threat_rate_formula 2*x + 0.15*x*x (below the player's
achievable military output early, crossing at the late boundary,
overwhelming by cycle ~24), starting_building_blocks 1000 -> 200,
expansion cost 200 -> 400 flat (placeholder until action item 4),
artifact_win_count 3 -> 5 (winning means choosing the artifact over a
schematic five times across ~7 cumulative offers).

Bug fix found during the pass: the building_block recipe carried no
unlock_at_station_level, and since building blocks appear in no
schematic's materials, implicit unlocking could never reach it - the
recipe was silently locked at game start. Now explicitly -1.

All values and derivations documented in content_design.md, "Pacing
pass - first values".

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DyCu8vwChKMbLJQ3xosYEN
2026-07-04 12:49:35 +02:00
27c3a7b65b Combat stats round 6: combat pass converged
Round 5 (with fight durations): TTK anchor validated - mirrors run
22.7/71.2/94.6 s (drone/cruiser/battleship), most fights within
22-72 s, destroyers-vs-dreadnought the accepted 214 s outlier. All
matchups converged: mirrors 5-10%, swarm vs cruisers +15%, frigates
vs battleship +13% (dropped on its own, confirming the noise floor),
dreadnought +3%, glass vs armored +10%, two-to-one 78%, stations 44%.

Two two-round signals actioned per the convergence policy:
battlecruiser hull 2200 -> 2400 (mixed fleet won +20%/+18% twice) and
repair_amount 12 -> 9 (~0.7 HP/s per threat; escorted team held +24%
twice with all frigates surviving). Everything else frozen; further
refinement moves to real-game playtests. Removed the arena
end-condition action item (fixed upstream).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DyCu8vwChKMbLJQ3xosYEN
2026-07-04 12:43:05 +02:00
9ddd622870 fix but where balancing matches did not finish until enemy hq was destroyed 2026-07-04 09:29:13 +02:00
df9f0d5ccd show total time in balancing target arenas 2026-07-04 09:17:32 +02:00
db7a03dc1f Combat stats round 5: final nudges and convergence policy
Round 4: mirrors 0-3%, swarm vs cruisers +7%, glass vs armored
resolved at +3% for armored (armor 1200 confirmed). Noise floor
established at ~+/-10% per single run (battleship margin ignored a
-10% EHP cut; repair drifted 14->24% with no repair changes).

Round-5 nudges for the armor-coupling overshoots: battlecruiser hull
2000 -> 2200, dreadnought/carrier 22500 -> 24000 (two-round
persistent deficit vs destroyers). The battleship's +23% over a pure
frigate fleet is accepted as doctrine texture rather than chased: the
edge is mechanical (range) and the fair anti-capital answer is the
mixed fleet, whose arena is balanced. Convergence policy documented:
act only on two-round signals, +/-20% counts as converged for v1.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DyCu8vwChKMbLJQ3xosYEN
2026-07-04 07:56:52 +02:00
67054f432f Combat stats round 4 from arena round 3 margins
Round 3 (narrow lanes; arena geometry is part of the fixture from
here): dreadnought closed to -11%, battleship improved to +22%, the
drone swarm flipped to +14% over cruisers under full engagement, glass
beat armored for the third consecutive round, mirrors/repair/
two-to-one healthy, stations cracked at 51% by the 3x swarm under the
new geometry (watch, not touched).

Round-4 knobs: armor_plates 1000 -> 1200 (~37 HP/threat; persistent
glass signal, also lifts armor-carrying cruiser/BC/destroyer/DN
loadouts), battlecruiser hull 2500 -> 2000 (net -300 EHP after its
armor gain), battleship 7000 -> 6300 (loadout has no armor, clean
-10%), dreadnought/carrier 19000 -> 22500 (opposing destroyers gain
armor too, so the larger step). Anchors doc notes the emerging shape:
the arena prices capitals as tanks with taxed guns.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DyCu8vwChKMbLJQ3xosYEN
2026-07-04 07:50:50 +02:00
7a9a7a35ad make arenas more narrow to avoid fleets passing each other 2026-07-04 07:47:08 +02:00
f822047b4e Combat stats round 3 from arena round 2 margins
Round 2 (with the new EHP-margin logging): mirrors healthy and the
round-1 side bias was noise; drones-vs-cruisers (10%) and
mixed-vs-battlecruisers (14%) near parity; battleship over at +33%
while dreadnought under at -37%; glass-vs-armored narrowed to 11%
(watch); repair escort fair at 11%; two-to-one decisive; the 3x swarm
now cracks the station set at 13%.

Round-3 knobs: weapon_stabilizer range multiplier 1.5 -> 1.3 (range is
the strongest stat under the orbit AI, and the stabilized battleship
was the one loadout still overperforming), plus per-hull HP trims with
the 15 HP/threat anchor demoted to a prior and per-hull HP documented
as the empirical trim knob: battlecruiser 2700 -> 2500, battleship
7500 -> 7000, dreadnought/carrier 15500 -> 19000.

Action items: mirror-bias and EHP-logging items resolved (the latter
implemented upstream); new item to verify the arena end condition seen
idling in round 1 with all ships dead.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DyCu8vwChKMbLJQ3xosYEN
2026-07-04 07:34:47 +02:00
d9e7dd0fe8 show team EHP in balancing target 2026-07-04 07:27:11 +02:00
4d5b218fec implement logging of arena states 2026-07-04 07:27:11 +02:00
97bafc95c3 Combat stats round 2 from arena round 1 findings
Round 1 findings: concentrated fleets won all four equal-threat
cross-tier matchups flawlessly; glass destroyers beat armored; repair
escort beat raw numbers flawlessly; two stations annihilated a 3x
threat swarm through 200 m approach fire; team 1 won all three mirror
matches (possible sim bias, recorded as action item 6, plus action
item 7 for HP-margin logging).

Knob changes, deliberately few for clean attribution: concentration
tax on m/l gun DPS (railgun_m damage 17 -> 14, railgun_l 70 -> 52),
armor_plates 640 -> 1000 HP (~31 HP/threat: killing removes enemy DPS
while surviving merely delays, so HP must be cheaper than DPS), repair
25 -> 12 HP per cycle (~1 HP/s per threat: in-combat sustain removes
enemy DPS and must be priced like DPS), station range 200 -> 120. Gun
ranges untouched; if concentration still wins flawlessly in round 2,
the range ladder is the next suspect. Anchors and findings documented
in content_design.md; fitted threat values are unaffected by stat
changes, so the arena suite counts stay valid.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DyCu8vwChKMbLJQ3xosYEN
2026-07-04 06:55:43 +02:00
5aa0544cf2 Combat stats pass: anchor-derived stats and canonical arena suite
Derive all combat stats from documented anchors (content_design.md,
'Combat stat anchors'): weapon DPS ~0.6 per threat with a mild size
discount traded for range (railgun m/l damage 17/70), hull HP at 15
per hull threat (drone 60 up to capitals 15500), armor at a 20/threat
premium (armor_plates 640 HP), repair at ~2 HP/s per threat (25 HP per
cycle), salvager range fixed to 60 m with cargo 20, and a monotone
mobility ladder (the placeholder drone was the least agile ship).
Stations anchored to 'a fresh station holds one early parity wave';
enemy level 0 matches the player station and scales per push. HQ 5000
HP. scrap_despawn_seconds 30 -> 120 so capital-sized scrap drops are
collectable.

Rewrite balancing.toml as the canonical 12-arena suite: class mirrors,
equal-threat cross-tier matchups with counts from the verified threat
values, a two-to-one decisiveness check, armored-vs-glass and
repair-escort doctrine matchups, and station assault. The carrier
arena is expected to lose until drone launching exists (hangar is dead
threat) - documented, not stat-compensated.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DyCu8vwChKMbLJQ3xosYEN
2026-07-03 20:19:24 +02:00
38fd2e4e89 Fix ThreatCostCalculator: per-unit division, scrap fallback, fixpoint, staggered-recipe max (action items 6-9)
Four algorithm fixes to bring ThreatCostCalculator.cpp into agreement with
tools/threat_report.py and the newly amended REQ-THREAT-ITEM semantics:

6. Scrap-consuming recipes as threat fallback only. Non-reprocessing recipes
   that take scrap as an input are excluded from an item's threat computation
   whenever at least one scrap-free recipe (miner/smelter/assembler) produces
   that item. Previously the scrap_smelting recipe (1 scrap → 1 iron_ingot)
   would have inflated iron_ingot's threat via the max rule.

7. Per-unit item threat. computeRecipeThreatPerUnit() now divides by the
   recipe's output amount, so multi-output recipes price each unit correctly.
   Example: copper_wire (1 copper_ingot, 1 s, output 2) is now 1.5, not 3.

8. Fixpoint resolution. The resolution loop now alternates the non-reprocessing
   pass and the reprocessing pass until neither makes progress, rather than
   running the reprocessing pass once at the end. Items downstream of
   reprocessing-only items (voidsteel_plate, capital_core, capital hulls,
   drone_hangar_module) now resolve correctly.

9. Max rule across staggered recipes. An item is committed only once every
   eligible recipe producing it is computable, so a shallow shortcut recipe
   (e.g. shortcut_steel_plate: 3 iron_ore → 1 steel_plate, resolvable one
   iteration earlier) cannot undercut the expensive base path. A deadlock
   fallback (require_all_recipes=False) handles potential recipe cycles.

docs/requirements.md: REQ-THREAT-ITEM amended for per-unit division, the
scrap-fallback rule, and order-independence via fixpoint.

docs/progression_design.md: action items 6-9 removed (completed); remaining
items 1-5 renumbered unchanged.

tools/threat_report.py: NOTE updated — C++ now matches Python semantics.

bin/test/data/config/recipes.toml: four minimal test recipes added (one per
fix: scrap_iron, dual_wire, downstream_product, staggered_item_{cheap,expensive}).

src/test/ThreatCostCalculatorTest.cpp: four new TEST_CASEs covering each fix.

Expected values with the live config (bin/app/data/config) verified by
threat_report.py: iron_ingot 2, copper_wire 1.5, steel_plate 7, control_chip
12, voidsteel_plate 141, capital_core 240; fitted ships 10.5/47/99/233.5/
354.5/722.5/1491.5/1436.5. All 378 test cases pass.
2026-07-03 18:45:39 +02:00
d889b79658 Write the v2 production tree into the config files
recipes.toml: full v2 rewrite - iron/copper/quartz mining, smelting
incl. the value-losing scrap sink, reprocessing (4 scrap / 4 s,
voidsteel at 20% of the full pool), tiered intermediates, hulls,
module prefabs, and the three drop-only shortcut recipes.

modules.toml: lasers renamed to railguns (implementation unchanged),
prefab materials and numbers-pass production times; combat stats stay
placeholders for the arena pass.

ships.toml: hull-item materials, numbers-pass base production times,
and geometry-validated default_modules loadouts for every ship (waves
now spawn armed).

visuals.toml: item entries for the new palette (quartz, silicon,
copper_coil, control_chip, capacitor_bank, hardened_steel,
ceramic_plate, voidsteel, voidsteel_plate, railgun modules); retired
titanium/alloy/laser items removed.

world.toml: scrap_per_threat = 0.25 per the numbers pass.

threat_report.py: commit an item's threat only once every eligible
recipe is computable - the previous first-resolved-wins behavior let
shortcut recipes underprice items (same flaw exists in
ThreatCostCalculator, recorded as action item 9). Verified: all
default_modules placements valid, verify_recipes and verify_layouts
pass, and the report reproduces the numbers-pass tables exactly
(fitted: 10.5/47/99/233.5/354.5/722.5/1491.5/1436.5). Doc tables
updated for the three geometry-corrected loadouts.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DyCu8vwChKMbLJQ3xosYEN
2026-07-03 17:05:19 +02:00
b9e70ba83a Add tools/threat_report.py (action item 7)
Reads recipes/ships/modules/world.toml and reports per-item threat
values, module contributions, hull-only and fitted ship threats
(default_modules), producer:consumer ratio tables, and belt
feasibility against the single-belt cap.

Implements the agreed design semantics: per-unit threat (recipe threat
divided by output amount), the scrap-fallback rule, and fixpoint
resolution through reprocessing-only items. Running it against the
current configs surfaced two ThreatCostCalculator deviations, recorded
as new action items: multi-output recipes are double-priced (no
per-unit division), and items downstream of reprocessing-only items
never resolve, underestimating capital hull threat.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DyCu8vwChKMbLJQ3xosYEN
2026-07-03 16:47:40 +02:00
3aefc05118 Scrap-consuming recipes as threat fallback, not excluded
Refine the REQ-THREAT-ITEM fix per review: recipes taking scrap as
input participate in an item threat computation only when no
scrap-free recipe produces that item, mirroring the existing
reprocessing-path rule instead of a blanket exclusion.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DyCu8vwChKMbLJQ3xosYEN
2026-07-03 16:34:06 +02:00
fe7703d5c3 Add first numbers pass for the v2 production tree
content_design.md: full recipe quantities and durations computed with
a recursive threat calculator - economy constants (scrap_per_threat
0.25, reprocessing 4 scrap / 4 s, voidsteel at threat 100), per-item
threat values, module contributions, and fitted ship threats vs the
ladder (96-124%, smooth ~x2-per-class curve). Checks recorded: ratio
curve realized (t1 1:1, t2 2:3, t3 strange), belt feasibility under
the single-belt cap, block at 4 threat implying ~18 blocks average
building cost for the 4-minute doubling target, and a small-end
deviation note recommending ladder adjustment over chain thinning.

progression_design.md: two new action items - amend REQ-THREAT-ITEM to
exclude scrap-consuming recipes from item threat (the max rule would
otherwise inflate basic materials via the scrap smelting recipe), and
port the calculator to tools/threat_report.py.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DyCu8vwChKMbLJQ3xosYEN
2026-07-03 15:05:40 +02:00
72b38df0dd Draft the v2 production tree structure
Add the tree structure draft to the v2 decisions section: mined and
smelted items, reprocessing pool, intermediates per tier with ratio
classes and archetypes, hull and module recipes as input lists, the
resolved m+ hull gate (hardened_steel plus control_chip), shortcut
recipe candidates, and a refactorability spot-check. Quantities and
durations are deferred to the numbers pass against the threat ladder.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DyCu8vwChKMbLJQ3xosYEN
2026-07-03 14:26:29 +02:00
c7a168f4a9 Record production tree v2 decisions and resource deposit rules
progression_design.md: rewrite the resource phases around the four
decided inputs (two mined everywhere, one deposit-gated mid resource,
one scrap-only late input), add the Resource deposits rule set
(freedom first / geography later, deposits only in expansions, patch
area as throughput cap, deterministic content, binary mining), note
the dual gating of the mid resource, and add the deposit-layer action
item.

content_design.md: mark the first-pass tree as superseded and record
the v2 decisions — iron/copper/quartz/voidsteel with their fiction
(M-type asteroid, quartz geodes, battle-forged voidsteel), titanium
dropped with its gating role moved to electronics and possibly a
quality-steel step, the material palette fingerprints, and the
laser-to-railgun rename with lasers reserved as a future weapon type.
Update the balancing target phase boundaries accordingly.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DyCu8vwChKMbLJQ3xosYEN
2026-07-03 13:54:24 +02:00
a6451f2bdf Add balancing targets section to content_design.md
Record the six root numbers for the balancing pass: run length (win
within ~2 h game time, cycle 20-24), phase boundaries, factory size
curve, fitted threat-cost ladder, swarm fleet size (~25 ships), and
block economy roots (bootstrap, doubling time, expansion cadence).
Derived values are always re-derived from these roots, never patched
directly.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DyCu8vwChKMbLJQ3xosYEN
2026-07-03 11:30:43 +02:00
493208d230 Add growth curve rules to the building block economy
Diagnose that player output equals building count, so the growth
curve must be shaped by the block and space economy: escalating
expansion costs (formula of expansions purchased) as the long-run
curve, a designed doubling time for the block feedback loop, and an
explicit rule that growth is limited by economy, never by
construction waiting. Note the HQ intake ceiling and add the
condensed-building-block idea to future work, plus an action item
for the expansion cost formula.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DyCu8vwChKMbLJQ3xosYEN
2026-07-03 10:50:42 +02:00
4098e40c8c Sync progression_design.md with implemented action items
Prune completed action items 1-4 and 8 (scrap-from-threat, schematic
upgrade and ship level removal, balancing tool cleanup, unlock
prerequisites), renumber the remaining three, and update stale
cross-references: cite REQ-LOCK-PREREQ and unlock_requires, reflect
that REQ-THREAT-SCRAP is now the 1/scrap_per_threat constant, and
drop the obsolete level-up wording from the artifact rule.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DyCu8vwChKMbLJQ3xosYEN
2026-07-03 09:44:53 +02:00
730cd3bdf3 refinement 2026-07-03 08:36:33 +02:00
437ac97355 Rewrite progression_design.md as rules/principles document
Turn the rough draft into structured rules for the production tree,
progression pacing, and balancing: resource phases, ratio curve,
shortcut recipes, refactorability, cost archetypes, threat model,
drop pacing, scrap/block economies, and numeric guardrails.

Includes agreed decisions: ship scrap derived from threat via a
scrap_per_threat key, no duplicate schematic drops (Mk2 upgrade
recipes deferred to future work), removal of ship levels, and an
action-item list for the follow-up requirements/code changes.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DyCu8vwChKMbLJQ3xosYEN
2026-07-03 08:36:33 +02:00
41081620f0 add first draft 2026-07-03 08:36:33 +02:00
6ea0655eaf implement unlock dependencies 2026-07-03 08:35:45 +02:00
58d4586d00 update concept.md 2026-07-02 21:36:42 +02:00
18e732ae99 Remove schematic upgrades and module and ship levels 2026-07-02 21:32:36 +02:00
81b1c7a66b Derive ship scrap drop from threat 2026-07-02 21:30:38 +02:00
5bc581bcb8 write replays next to the executable 2026-07-01 22:43:04 +02:00
0a7e9a34ef Add artifact win condition (#3)
Reviewed-on: #3
Co-authored-by: Malte Langkabel <malte.langkabel@gmail.com>
Co-committed-by: Malte Langkabel <malte.langkabel@gmail.com>
2026-07-01 20:27:29 +00:00
d74ba5bfad Replay: deterministic record & playback (#4)
Add deterministic record/playback for a run.

Recording captures `(seed, config hash, ordered tick-tagged commands)` and re-simulates on playback — no state snapshots. `DotaFactory.exe --replay <file>` re-plays a recorded run view-only with manual speed/pause.

Reviewed-on: #4
Co-authored-by: Malte Langkabel <malte.langkabel@gmail.com>
Co-committed-by: Malte Langkabel <malte.langkabel@gmail.com>
2026-07-01 19:20:08 +00:00
cf68ac2862 Fix selected construction site border not being drawn (#2)
Fixes a bug where the selected construction site was not drawn with a border.

Reviewed-on: #2
Co-authored-by: Malte Langkabel <malte.langkabel@gmail.com>
Co-committed-by: Malte Langkabel <malte.langkabel@gmail.com>
2026-06-29 20:09:10 +00:00
b301db2008 increase refund rate because altering the factory shall not be punishing 2026-06-23 22:11:30 +02:00
31a8915b0f update keyboard shortcuts 2026-06-23 22:09:26 +02:00
f818c90af0 draw ghost in semi-transparent building color 2026-06-23 21:29:38 +02:00
577927ef70 fix bug where splitter filters were not taken over to blueprint 2026-06-23 21:08:46 +02:00
d271d65678 allow to set the recipe already for construction sites 2026-06-22 22:15:56 +02:00
e5017ab3c5 fix issue where construction sites could be placed outside of game world and add tests 2026-06-22 21:13:01 +02:00
59688e6532 fix issue where scrolling while drawing selection box did not update selection box size 2026-06-22 21:10:38 +02:00
c7218c7c1e Replace recipe/schematic dropdowns with button and selection dialog 2026-06-22 21:07:36 +02:00
c43225b6fa fix issue where beams were also disappearing while the game was paused 2026-06-21 22:09:25 +02:00
405206211e fix issue where right-click did not exit demolish mode 2026-06-21 21:56:40 +02:00
3d577a11db fix bug where recipe combo stayed visible when construction site was selected 2026-06-21 21:54:15 +02:00
a472ec196c cargo component refactoring 2026-06-21 21:49:46 +02:00
665060bcd2 Merge pull request 'fix issue where repair behavior targets enemy HQ in balancing target' (#1) from fix_repair_targeting into master
Reviewed-on: #1
2026-06-19 19:44:28 +00:00
4818997164 fix issue where repair behavior targets enemy HQ in balancing target 2026-06-19 21:36:04 +02:00
9573b9789a change repair_tool application and add beams for salvager and repair_tool 2026-06-19 21:15:47 +02:00