diff --git a/bin/app/data/config/modules.toml b/bin/app/data/config/modules.toml index 6f8979c..b409dab 100644 --- a/bin/app/data/config/modules.toml +++ b/bin/app/data/config/modules.toml @@ -57,7 +57,7 @@ fill_color = "#FF8040" glyph = "Rm" [module.weapon] -damage = 17 +damage = 14 attack_range_m = 70 attack_rate_hz = 1.5 @@ -76,7 +76,7 @@ fill_color = "#FF8040" glyph = "Rl" [module.weapon] -damage = 70 +damage = 52 attack_range_m = 100 attack_rate_hz = 0.8 @@ -110,7 +110,7 @@ glyph = "Rp" [module.repair] repair_rate_hz = 1 -repair_amount_hp = 25 +repair_amount_hp = 12 repair_range_m = 80 # ----------------------------------------------------------------------------- @@ -158,7 +158,7 @@ fill_color = "#808080" glyph = "A" [module.health] -added_hp = 640 +added_hp = 1000 [[module]] diff --git a/bin/app/data/config/stations.toml b/bin/app/data/config/stations.toml index ff5baa4..15af5a8 100644 --- a/bin/app/data/config/stations.toml +++ b/bin/app/data/config/stations.toml @@ -22,7 +22,7 @@ surface_mask = [ level = 1 hp_formula = "3000" damage_formula = "25" -range_m_formula = "200" +range_m_formula = "120" fire_rate_hz_formula = "1" scrap_drop_formula = "40" @@ -33,6 +33,6 @@ surface_mask = [ ] hp_formula = "3000 + 1500*x" damage_formula = "25 + 12*x" -range_m_formula = "200" +range_m_formula = "120" fire_rate_hz_formula = "1.0 + 0.1*x" scrap_drop_formula = "40 + 30*x" diff --git a/docs/content_design.md b/docs/content_design.md index bc51d97..80533df 100644 --- a/docs/content_design.md +++ b/docs/content_design.md @@ -446,24 +446,34 @@ All combat stats derive from a few anchors so that power-per-threat holds by construction; the arena suite in `bin/balancing/data/balancing.toml` verifies it empirically. Change the anchors first, re-derive stats second. -- **Weapon DPS ≈ 0.6 per threat of weapon contribution**, mildly - diminishing with gun size, compensated by the range ladder: - railgun_s 2 dmg × 2.0 Hz = 4.0 DPS at 6.5 threat (0.62), range 50; - railgun_m 17 × 1.5 = 25.5 at 43.5 (0.59), range 70; - railgun_l 70 × 0.8 = 56 at 102 (0.55), range 100. +- **Weapon DPS per threat pays a concentration tax that grows with gun + size**: railgun_s 2 dmg × 2.0 Hz = 4.0 DPS at 6.5 threat (0.62), + range 50; railgun_m 14 × 1.5 = 21 at 43.5 (0.48), range 70; + railgun_l 52 × 0.8 = 41.6 at 102 (0.41), range 100. Arena round 1 + (see below) showed that at equal threat, concentrated fleets win + flawlessly with a flat-ish DPS curve — concentration itself (focus + survivability, range, no losses-to-attrition of own DPS) is worth + paying for, so bigger guns get less raw DPS per threat. - **Hull HP = 15 per threat of hull contribution** (incl. ship base time): drone 60, frigate 300, destroyer 550, cruiser 1500, battlecruiser 2700, battleship 7500, dreadnought/carrier 15500. -- **Armor HP = 20 per threat** — a premium over hull HP because armor is - pure HP with no capability: armor_plates adds 640 HP at 32 threat. +- **Armor HP ≈ 31 per threat** — a strong premium over hull HP (15) + because armor is pure HP with no capability, and fights snowball: + killing enemies removes their DPS, while surviving merely delays — + so a point of HP must be cheaper than a point of DPS. + armor_plates adds 1000 HP at 32 threat (arena round 1: at 640 the + all-guns destroyer beat the armored one). - **TTK check:** a mirror cruiser duel (51 DPS vs 2140 EHP) lasts ~42 s — inside the 30–60 s parity-fight band implied by the 25-ship fleet target. Capital mirrors run longer (~90 s), deliberately. -- **Repair ≈ 2 HP/s per threat:** repair_tool heals 25 HP × 1 Hz at 13 - threat. Salvager: collection range 60 (was a nonsensical 500, beyond - any sensor), cargo 20, 0.5 collections/s. `scrap_despawn_seconds` - raised 30 → 120: a capital kill drops hundreds of scrap collected one - per cycle, so 30 s despawned nearly everything. +- **Repair ≈ 1 HP/s per threat:** repair_tool heals 12 HP × 1 Hz at 13 + threat (arena round 1: at 2 HP/s-per-threat the escorted team won + flawlessly — in-combat sustain effectively removes enemy DPS and must + be priced like DPS, not like HP). Salvager: collection range 60 (was + a nonsensical 500, beyond any sensor), cargo 20, 0.5 collections/s. + `scrap_despawn_seconds` raised 30 → 120: a capital kill drops + hundreds of scrap collected one per cycle, so 30 s despawned nearly + everything. - **Mobility ladder is monotone in size** — small = fast and nimble (drone 45 m/s, 60 accel) down to capitals (10 m/s, 8 accel); the old placeholder had the drone as the least agile ship. Sensor ranges keep @@ -474,14 +484,29 @@ verifies it empirically. Change the anchors first, re-derive stats second. — so modifiers pay off on gun-heavy big hulls and are a waste on small ones. Kept at ×1.2/×1.2/(×1.5 range, ×0.8 rate) deliberately. - **Stations:** a fresh player station (3000 HP, 25 dmg × 1 Hz, - range 200) holds one early parity wave unaided; the enemy station at + range 120) holds one early parity wave unaided; the enemy station at level 0 matches it exactly and scales per push level - (+1500 HP, +12 dmg, +0.1 Hz per level). HQ 5000 HP. + (+1500 HP, +12 dmg, +0.1 Hz per level). HQ 5000 HP. Range reduced + from 200 in round 1: at 200 (4× a small gun's range) two stations + annihilated a 3× threat swarm through approach fire alone — range, + not HP, is the station dominance lever. - **Known imbalance, accepted:** the carrier loses its equal-threat arena until the drone-launching capability exists — the hangar is 224 threat of dead weight. Do not compensate with stats; fix by implementing drones. +**Arena round 1 results (2026-07-04):** mirrors snowball as expected +(40–50% of the winner survives) but team 1 won all three mirrors — +possible sim-side bias, under investigation (progression_design.md +action items 6–7). All four equal-threat cross-tier matchups were +flawless wins for the concentrated side; glass destroyers beat armored; +repair escort beat raw numbers flawlessly; two stations shrugged off a +3× threat swarm. Round-2 knob changes: concentration tax on m/l gun +DPS (17→14, 70→52 damage), armor 640→1000, repair 25→12, station range +200→120. Gun ranges deliberately untouched — if concentrated fleets +still win flawlessly in round 2, the range ladder (kiting) is the next +suspect, ahead of further DPS cuts. + ## Balancing targets (first pass, July 2026) The six root numbers for the balancing pass. Every derived value (threat diff --git a/docs/progression_design.md b/docs/progression_design.md index 6e9fb17..564f941 100644 --- a/docs/progression_design.md +++ b/docs/progression_design.md @@ -373,3 +373,15 @@ in `requirements.md` and the git history). Still open: one matching deposit tile). Touches REQ-BLD-MINER ("every asteroid tile is equivalent" no longer holds), REQ-GW-ASTEROID-EXPAND / REQ-EXP-*, `world.toml`, and `visuals.toml`. +6. **Investigate team-1 bias in balancing arenas.** In arena round 1 + (July 2026), team 1 won all three mirror matches with large margins + (8/20, 3/6, 1/2 survivors). Re-run mirrors repeatedly; if team 1 + wins consistently, find and fix the asymmetry (spawn geometry, tick + processing order, target-selection tie-breaking). Mirror matches + must be statistically symmetric or every arena result carries a + side-dependent error. +7. **Log remaining HP in the balancing arena results.** Win/loss alone + hides the margin ("1/1 battleship" can mean 95% or 5% HP left). Add + the surviving entities' remaining HP fraction (or a per-team total + EHP percentage) to the arena end state, so equal-threat matchups can + be tuned toward near-draws quantitatively.