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
This commit is contained in:
2026-07-03 20:19:24 +02:00
parent 38fd2e4e89
commit 5aa0544cf2
6 changed files with 457 additions and 78 deletions

View File

@@ -57,7 +57,7 @@ fill_color = "#FF8040"
glyph = "Rm" glyph = "Rm"
[module.weapon] [module.weapon]
damage = 10 damage = 17
attack_range_m = 70 attack_range_m = 70
attack_rate_hz = 1.5 attack_rate_hz = 1.5
@@ -76,7 +76,7 @@ fill_color = "#FF8040"
glyph = "Rl" glyph = "Rl"
[module.weapon] [module.weapon]
damage = 40 damage = 70
attack_range_m = 100 attack_range_m = 100
attack_rate_hz = 0.8 attack_rate_hz = 0.8
@@ -94,8 +94,8 @@ fill_color = "#AACC44"
glyph = "Sv" glyph = "Sv"
[module.salvage] [module.salvage]
collection_range_m = 500 collection_range_m = 60
cargo_capacity = 10 cargo_capacity = 20
collection_rate_hz = 0.5 collection_rate_hz = 0.5
@@ -110,7 +110,7 @@ glyph = "Rp"
[module.repair] [module.repair]
repair_rate_hz = 1 repair_rate_hz = 1
repair_amount_hp = 6 repair_amount_hp = 25
repair_range_m = 80 repair_range_m = 80
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------
@@ -158,7 +158,7 @@ fill_color = "#808080"
glyph = "A" glyph = "A"
[module.health] [module.health]
added_hp = 40 added_hp = 640
[[module]] [[module]]

View File

@@ -31,14 +31,14 @@ materials = [{item = "drone_hull", amount = 1}]
production_time_seconds = 1 production_time_seconds = 1
[ship.health] [ship.health]
hp = 3 hp = 60
[ship.movement] [ship.movement]
speed_mps = 40 speed_mps = 45
main_acceleration_mpss = 2 main_acceleration_mpss = 60
maneuvering_acceleration_mpss = 1 maneuvering_acceleration_mpss = 30
angular_acceleration_radpss = 12.56 angular_acceleration_radpss = 12
max_rotation_speed_radps = 6.28 max_rotation_speed_radps = 6
[ship.sensor] [ship.sensor]
sensor_range_m = 150 sensor_range_m = 150
@@ -66,12 +66,12 @@ materials = [{item = "frigate_hull", amount = 1}]
production_time_seconds = 2 production_time_seconds = 2
[ship.health] [ship.health]
hp = 30 hp = 300
[ship.movement] [ship.movement]
speed_mps = 30 speed_mps = 35
main_acceleration_mpss = 50 main_acceleration_mpss = 45
maneuvering_acceleration_mpss = 25 maneuvering_acceleration_mpss = 22
angular_acceleration_radpss = 8 angular_acceleration_radpss = 8
max_rotation_speed_radps = 4 max_rotation_speed_radps = 4
@@ -102,12 +102,12 @@ materials = [{item = "destroyer_hull", amount = 1}]
production_time_seconds = 3 production_time_seconds = 3
[ship.health] [ship.health]
hp = 50 hp = 550
[ship.movement] [ship.movement]
speed_mps = 25 speed_mps = 30
main_acceleration_mpss = 40 main_acceleration_mpss = 35
maneuvering_acceleration_mpss = 20 maneuvering_acceleration_mpss = 18
angular_acceleration_radpss = 6 angular_acceleration_radpss = 6
max_rotation_speed_radps = 3 max_rotation_speed_radps = 3
@@ -139,12 +139,12 @@ materials = [{item = "cruiser_hull", amount = 1}]
production_time_seconds = 4 production_time_seconds = 4
[ship.health] [ship.health]
hp = 120 hp = 1500
[ship.movement] [ship.movement]
speed_mps = 20 speed_mps = 24
main_acceleration_mpss = 30 main_acceleration_mpss = 25
maneuvering_acceleration_mpss = 15 maneuvering_acceleration_mpss = 12
angular_acceleration_radpss = 4 angular_acceleration_radpss = 4
max_rotation_speed_radps = 2 max_rotation_speed_radps = 2
@@ -179,12 +179,12 @@ materials = [{item = "battlecruiser_hull", amount = 1}]
production_time_seconds = 5 production_time_seconds = 5
[ship.health] [ship.health]
hp = 180 hp = 2700
[ship.movement] [ship.movement]
speed_mps = 18 speed_mps = 20
main_acceleration_mpss = 25 main_acceleration_mpss = 20
maneuvering_acceleration_mpss = 12 maneuvering_acceleration_mpss = 10
angular_acceleration_radpss = 3 angular_acceleration_radpss = 3
max_rotation_speed_radps = 1.5 max_rotation_speed_radps = 1.5
@@ -222,12 +222,12 @@ materials = [{item = "battleship_hull", amount = 1}]
production_time_seconds = 6 production_time_seconds = 6
[ship.health] [ship.health]
hp = 350 hp = 7500
[ship.movement] [ship.movement]
speed_mps = 14 speed_mps = 15
main_acceleration_mpss = 18 main_acceleration_mpss = 14
maneuvering_acceleration_mpss = 8 maneuvering_acceleration_mpss = 7
angular_acceleration_radpss = 2 angular_acceleration_radpss = 2
max_rotation_speed_radps = 1 max_rotation_speed_radps = 1
@@ -267,12 +267,12 @@ materials = [{item = "dreadnought_hull", amount = 1}]
production_time_seconds = 8 production_time_seconds = 8
[ship.health] [ship.health]
hp = 800 hp = 15500
[ship.movement] [ship.movement]
speed_mps = 8 speed_mps = 10
main_acceleration_mpss = 10 main_acceleration_mpss = 8
maneuvering_acceleration_mpss = 5 maneuvering_acceleration_mpss = 4
angular_acceleration_radpss = 1 angular_acceleration_radpss = 1
max_rotation_speed_radps = 0.5 max_rotation_speed_radps = 0.5
@@ -308,12 +308,12 @@ materials = [{item = "carrier_hull", amount = 1}]
production_time_seconds = 8 production_time_seconds = 8
[ship.health] [ship.health]
hp = 700 hp = 15500
[ship.movement] [ship.movement]
speed_mps = 9 speed_mps = 10
main_acceleration_mpss = 10 main_acceleration_mpss = 8
maneuvering_acceleration_mpss = 5 maneuvering_acceleration_mpss = 4
angular_acceleration_radpss = 1 angular_acceleration_radpss = 1
max_rotation_speed_radps = 0.5 max_rotation_speed_radps = 0.5

View File

@@ -1,10 +1,18 @@
# stations.toml
#
# Combat-pass anchors (see docs/content_design.md, "Combat stat anchors"):
# a fresh player defence station holds one early parity wave unaided; the
# enemy station at level 0 matches the player station exactly and scales
# with the push level x. Station scrap drops stay authored (pushing rewards
# are tuned independently of ship production costs, REQ-RES-SCRAP-DROP).
[hq] [hq]
surface_mask = [ surface_mask = [
"AAA", "AAA",
"AAA", "AAA",
"AAA", "AAA",
] ]
hp_formula = "1000" hp_formula = "5000"
[player_station] [player_station]
surface_mask = [ surface_mask = [
@@ -12,19 +20,19 @@ surface_mask = [
"SS", "SS",
] ]
level = 1 level = 1
hp_formula = "300" hp_formula = "3000"
damage_formula = "5" damage_formula = "25"
range_m_formula = "200" range_m_formula = "200"
fire_rate_hz_formula = "1" fire_rate_hz_formula = "1"
scrap_drop_formula = "10" scrap_drop_formula = "40"
[enemy_station] [enemy_station]
surface_mask = [ surface_mask = [
"SS", "SS",
"SS", "SS",
] ]
hp_formula = "300 + 150*x" hp_formula = "3000 + 1500*x"
damage_formula = "2 + 1*x" damage_formula = "25 + 12*x"
range_m_formula = "200" range_m_formula = "200"
fire_rate_hz_formula = "1.0 + 0.2*x" fire_rate_hz_formula = "1.0 + 0.1*x"
scrap_drop_formula = "10 + 5*x" scrap_drop_formula = "40 + 30*x"

View File

@@ -2,7 +2,7 @@
height_tiles = 40 height_tiles = 40
refund_percentage = 100 refund_percentage = 100
starting_building_blocks = 1000 starting_building_blocks = 1000
scrap_despawn_seconds = 30 scrap_despawn_seconds = 120
scrap_per_threat = 0.25 scrap_per_threat = 0.25
tile_size_m = 10 tile_size_m = 10
belt_speed_mps = 20 belt_speed_mps = 20

View File

@@ -1,67 +1,396 @@
# balancing.toml — canonical arena suite for the combat stats pass.
#
# Ship counts are chosen so both teams have (near-)equal total threat,
# using the verified fitted threat values from tools/threat_report.py:
# drone 10.5, frigate 47, destroyer 99, cruiser 233.5,
# battlecruiser 354.5, battleship 722.5, dreadnought 1491.5,
# carrier 1436.5, glass destroyer (8 small guns) 92, repair drone 17.
# Module arrays mirror the ships' default_modules loadouts unless a
# doctrine variant is the point of the arena.
#
# Expectations: mirror matches and equal-threat cross-tier matchups should
# be near-draws (power-per-threat rule); the two-to-one arena must be a
# decisive win for the larger team. "Cruisers vs carrier" is EXPECTED to be
# a loss for the carrier until the drone-launching capability exists — the
# hangar is 224 threat of dead weight.
# --- mirrors (sanity: symmetric outcomes, fight duration in the 30-60 s band) ---
[[arena]] [[arena]]
name = "Fighters vs Sniper" name = "Mirror: drones 20v20"
height_tiles = 20 height_tiles = 30
player_buffer_width_tiles = 10 player_buffer_width_tiles = 10
contest_zone_width_tiles = 60 contest_zone_width_tiles = 50
enemy_buffer_width_tiles = 10 enemy_buffer_width_tiles = 10
[[arena.team]] [[arena.team]]
name = "Alpha" name = "Alpha"
[[arena.team.ship]] [[arena.team.ship]]
schematic = "drone" schematic = "drone"
count = 5 count = 20
modules = [ modules = [
{type = "laser_cannon_s", x = 1, y = 1, rotation = "east"}, {type = "railgun_s", x = 0, y = 0, rotation = "east"},
] ]
[[arena.team]] [[arena.team]]
name = "Beta" name = "Beta"
[[arena.team.ship]] [[arena.team.ship]]
schematic = "drone" schematic = "drone"
count = 2 count = 20
modules = [ modules = [
{type = "laser_cannon_s", x = 1, y = 1, rotation = "east"}, {type = "railgun_s", x = 0, y = 0, rotation = "east"},
{type = "weapon_stabilizer", x = 1, y = 1, rotation = "east"},
{type = "weapon_stabilizer", x = 1, y = 1, rotation = "east"},
{type = "weapon_upgrade", x = 1, y = 1, rotation = "east"},
{type = "sensor_booster", x = 1, y = 1, rotation = "east"},
{type = "sensor_booster", x = 1, y = 1, rotation = "east"},
] ]
[[arena]] [[arena]]
name = "Fighters vs Supported" name = "Mirror: cruisers 6v6"
height_tiles = 20 height_tiles = 30
player_buffer_width_tiles = 10 player_buffer_width_tiles = 10
contest_zone_width_tiles = 60 contest_zone_width_tiles = 50
enemy_buffer_width_tiles = 10 enemy_buffer_width_tiles = 10
[[arena.team]] [[arena.team]]
name = "Fighters" name = "Alpha"
[[arena.team.ship]] [[arena.team.ship]]
schematic = "drone" schematic = "cruiser"
count = 5 count = 6
modules = [ modules = [
{type = "laser_cannon_s", x = 1, y = 1, rotation = "east"}, {type = "railgun_m", x = 0, y = 1, rotation = "east"},
{type = "railgun_m", x = 2, y = 1, rotation = "east"},
{type = "armor_plates", x = 1, y = 0, rotation = "east"},
{type = "maneuvering_thrusters", x = 1, y = 3, rotation = "east"},
] ]
[[arena.team]] [[arena.team]]
name = "Supported" name = "Beta"
[[arena.team.ship]] [[arena.team.ship]]
schematic = "drone" schematic = "cruiser"
count = 3 count = 6
modules = [ modules = [
{type = "laser_cannon_s", x = 1, y = 1, rotation = "east"}, {type = "railgun_m", x = 0, y = 1, rotation = "east"},
{type = "railgun_m", x = 2, y = 1, rotation = "east"},
{type = "armor_plates", x = 1, y = 0, rotation = "east"},
{type = "maneuvering_thrusters", x = 1, y = 3, rotation = "east"},
] ]
[[arena]]
name = "Mirror: battleships 2v2"
height_tiles = 30
player_buffer_width_tiles = 10
contest_zone_width_tiles = 50
enemy_buffer_width_tiles = 10
[[arena.team]]
name = "Alpha"
[[arena.team.ship]]
schematic = "battleship"
count = 2
modules = [
{type = "railgun_l", x = 1, y = 0, rotation = "east"},
{type = "railgun_m", x = 1, y = 3, rotation = "east"},
{type = "railgun_m", x = 3, y = 3, rotation = "east"},
{type = "weapon_stabilizer", x = 4, y = 1, rotation = "east"},
{type = "railgun_s", x = 4, y = 0, rotation = "east"},
{type = "railgun_s", x = 0, y = 1, rotation = "east"},
]
[[arena.team]]
name = "Beta"
[[arena.team.ship]]
schematic = "battleship"
count = 2
modules = [
{type = "railgun_l", x = 1, y = 0, rotation = "east"},
{type = "railgun_m", x = 1, y = 3, rotation = "east"},
{type = "railgun_m", x = 3, y = 3, rotation = "east"},
{type = "weapon_stabilizer", x = 4, y = 1, rotation = "east"},
{type = "railgun_s", x = 4, y = 0, rotation = "east"},
{type = "railgun_s", x = 0, y = 1, rotation = "east"},
]
# --- equal-threat cross-tier matchups (power-per-threat: expect near-draws) ---
[[arena]]
name = "Drone swarm vs cruisers (462 vs 467)"
height_tiles = 30
player_buffer_width_tiles = 10
contest_zone_width_tiles = 50
enemy_buffer_width_tiles = 10
[[arena.team]]
name = "Swarm"
[[arena.team.ship]]
schematic = "drone"
count = 44
modules = [
{type = "railgun_s", x = 0, y = 0, rotation = "east"},
]
[[arena.team]]
name = "Cruisers"
[[arena.team.ship]]
schematic = "cruiser"
count = 2
modules = [
{type = "railgun_m", x = 0, y = 1, rotation = "east"},
{type = "railgun_m", x = 2, y = 1, rotation = "east"},
{type = "armor_plates", x = 1, y = 0, rotation = "east"},
{type = "maneuvering_thrusters", x = 1, y = 3, rotation = "east"},
]
[[arena]]
name = "Frigates vs battleship (705 vs 723)"
height_tiles = 30
player_buffer_width_tiles = 10
contest_zone_width_tiles = 50
enemy_buffer_width_tiles = 10
[[arena.team]]
name = "Frigates"
[[arena.team.ship]]
schematic = "frigate"
count = 15
modules = [
{type = "railgun_s", x = 1, y = 0, rotation = "east"},
{type = "railgun_s", x = 2, y = 1, rotation = "east"},
{type = "maneuvering_thrusters", x = 0, y = 1, rotation = "east"},
]
[[arena.team]]
name = "Battleship"
[[arena.team.ship]]
schematic = "battleship"
count = 1
modules = [
{type = "railgun_l", x = 1, y = 0, rotation = "east"},
{type = "railgun_m", x = 1, y = 3, rotation = "east"},
{type = "railgun_m", x = 3, y = 3, rotation = "east"},
{type = "weapon_stabilizer", x = 4, y = 1, rotation = "east"},
{type = "railgun_s", x = 4, y = 0, rotation = "east"},
{type = "railgun_s", x = 0, y = 1, rotation = "east"},
]
[[arena]]
name = "Destroyers vs dreadnought (1485 vs 1492)"
height_tiles = 40
player_buffer_width_tiles = 10
contest_zone_width_tiles = 50
enemy_buffer_width_tiles = 10
[[arena.team]]
name = "Destroyers"
[[arena.team.ship]]
schematic = "destroyer"
count = 15
modules = [
{type = "railgun_s", x = 0, y = 0, rotation = "east"},
{type = "railgun_s", x = 2, y = 0, rotation = "east"},
{type = "railgun_s", x = 4, y = 0, rotation = "east"},
{type = "armor_plates", x = 0, y = 1, rotation = "east"},
{type = "sensor_booster", x = 3, y = 1, rotation = "east"},
]
[[arena.team]]
name = "Dreadnought"
[[arena.team.ship]]
schematic = "dreadnought"
count = 1
modules = [
{type = "railgun_l", x = 0, y = 1, rotation = "east"},
{type = "railgun_l", x = 4, y = 1, rotation = "east"},
{type = "railgun_l", x = 8, y = 1, rotation = "east"},
{type = "armor_plates", x = 3, y = 0, rotation = "east"},
{type = "armor_plates", x = 5, y = 0, rotation = "east"},
{type = "armor_plates", x = 2, y = 4, rotation = "east"},
{type = "armor_plates", x = 7, y = 4, rotation = "east"},
{type = "railgun_s", x = 7, y = 0, rotation = "east"},
]
[[arena]]
name = "Cruisers vs carrier (1401 vs 1437, carrier expected to lose)"
height_tiles = 40
player_buffer_width_tiles = 10
contest_zone_width_tiles = 50
enemy_buffer_width_tiles = 10
[[arena.team]]
name = "Cruisers"
[[arena.team.ship]]
schematic = "cruiser"
count = 6
modules = [
{type = "railgun_m", x = 0, y = 1, rotation = "east"},
{type = "railgun_m", x = 2, y = 1, rotation = "east"},
{type = "armor_plates", x = 1, y = 0, rotation = "east"},
{type = "maneuvering_thrusters", x = 1, y = 3, rotation = "east"},
]
[[arena.team]]
name = "Carrier"
[[arena.team.ship]]
schematic = "carrier"
count = 1
modules = [
{type = "drone_hangar", x = 2, y = 0, rotation = "east"},
{type = "railgun_m", x = 3, y = 2, rotation = "east"},
{type = "railgun_m", x = 6, y = 2, rotation = "east"},
{type = "armor_plates", x = 0, y = 1, rotation = "east"},
{type = "armor_plates", x = 8, y = 1, rotation = "east"},
{type = "sensor_booster", x = 3, y = 4, rotation = "east"},
]
[[arena]]
name = "Mixed mid vs battlecruisers (1394 vs 1418)"
height_tiles = 40
player_buffer_width_tiles = 10
contest_zone_width_tiles = 50
enemy_buffer_width_tiles = 10
[[arena.team]]
name = "Mixed"
[[arena.team.ship]]
schematic = "destroyer"
count = 7
modules = [
{type = "railgun_s", x = 0, y = 0, rotation = "east"},
{type = "railgun_s", x = 2, y = 0, rotation = "east"},
{type = "railgun_s", x = 4, y = 0, rotation = "east"},
{type = "armor_plates", x = 0, y = 1, rotation = "east"},
{type = "sensor_booster", x = 3, y = 1, rotation = "east"},
]
[[arena.team.ship]]
schematic = "cruiser"
count = 3
modules = [
{type = "railgun_m", x = 0, y = 1, rotation = "east"},
{type = "railgun_m", x = 2, y = 1, rotation = "east"},
{type = "armor_plates", x = 1, y = 0, rotation = "east"},
{type = "maneuvering_thrusters", x = 1, y = 3, rotation = "east"},
]
[[arena.team]]
name = "Battlecruisers"
[[arena.team.ship]]
schematic = "battlecruiser"
count = 4
modules = [
{type = "railgun_m", x = 0, y = 0, rotation = "east"},
{type = "railgun_m", x = 4, y = 0, rotation = "east"},
{type = "railgun_m", x = 2, y = 1, rotation = "east"},
{type = "armor_plates", x = 2, y = 3, rotation = "east"},
{type = "railgun_s", x = 1, y = 2, rotation = "east"},
{type = "railgun_s", x = 4, y = 2, rotation = "east"},
]
# --- asymmetric checks ---
[[arena]]
name = "Two to one (must be decisive)"
height_tiles = 30
player_buffer_width_tiles = 10
contest_zone_width_tiles = 50
enemy_buffer_width_tiles = 10
[[arena.team]]
name = "Six"
[[arena.team.ship]]
schematic = "frigate"
count = 6
modules = [
{type = "railgun_s", x = 1, y = 0, rotation = "east"},
{type = "railgun_s", x = 2, y = 1, rotation = "east"},
{type = "maneuvering_thrusters", x = 0, y = 1, rotation = "east"},
]
[[arena.team]]
name = "Three"
[[arena.team.ship]]
schematic = "frigate"
count = 3
modules = [
{type = "railgun_s", x = 1, y = 0, rotation = "east"},
{type = "railgun_s", x = 2, y = 1, rotation = "east"},
{type = "maneuvering_thrusters", x = 0, y = 1, rotation = "east"},
]
[[arena]]
name = "Armored vs glass destroyers (1188 vs 1196)"
height_tiles = 30
player_buffer_width_tiles = 10
contest_zone_width_tiles = 50
enemy_buffer_width_tiles = 10
[[arena.team]]
name = "Armored"
[[arena.team.ship]]
schematic = "destroyer"
count = 12
modules = [
{type = "railgun_s", x = 0, y = 0, rotation = "east"},
{type = "railgun_s", x = 2, y = 0, rotation = "east"},
{type = "railgun_s", x = 4, y = 0, rotation = "east"},
{type = "armor_plates", x = 0, y = 1, rotation = "east"},
{type = "sensor_booster", x = 3, y = 1, rotation = "east"},
]
[[arena.team]]
name = "Glass"
[[arena.team.ship]]
schematic = "destroyer"
count = 13
modules = [
{type = "railgun_s", x = 0, y = 0, rotation = "east"},
{type = "railgun_s", x = 2, y = 0, rotation = "east"},
{type = "railgun_s", x = 4, y = 0, rotation = "east"},
{type = "railgun_s", x = 0, y = 1, rotation = "east"},
{type = "railgun_s", x = 1, y = 1, rotation = "east"},
{type = "railgun_s", x = 2, y = 1, rotation = "east"},
{type = "railgun_s", x = 3, y = 1, rotation = "east"},
{type = "railgun_s", x = 4, y = 1, rotation = "east"},
]
[[arena]]
name = "Repair escort vs raw numbers (444 vs 444)"
height_tiles = 30
player_buffer_width_tiles = 10
contest_zone_width_tiles = 50
enemy_buffer_width_tiles = 10
[[arena.team]]
name = "Escorted"
[[arena.team.ship]]
schematic = "frigate"
count = 8
modules = [
{type = "railgun_s", x = 1, y = 0, rotation = "east"},
{type = "railgun_s", x = 2, y = 1, rotation = "east"},
{type = "maneuvering_thrusters", x = 0, y = 1, rotation = "east"},
]
[[arena.team.ship]]
schematic = "drone"
count = 4
modules = [
{type = "repair_tool", x = 0, y = 0, rotation = "east"},
]
[[arena.team]]
name = "Raw"
[[arena.team.ship]]
schematic = "frigate"
count = 9
modules = [
{type = "railgun_s", x = 1, y = 0, rotation = "east"},
{type = "railgun_s", x = 2, y = 1, rotation = "east"},
{type = "maneuvering_thrusters", x = 0, y = 1, rotation = "east"},
]
[[arena.team.ship]] [[arena.team.ship]]
schematic = "drone" schematic = "drone"
count = 2 count = 2
modules = [ modules = [
{type = "repair_tool", x = 1, y = 1, rotation = "east"}, {type = "railgun_s", x = 0, y = 0, rotation = "east"},
] ]
[[arena]] [[arena]]
name = "Stations and Ships" name = "Station assault (2 stations + 105 vs 315)"
height_tiles = 60 height_tiles = 60
player_buffer_width_tiles = 15 player_buffer_width_tiles = 15
contest_zone_width_tiles = 40 contest_zone_width_tiles = 40
@@ -71,9 +400,9 @@ enemy_buffer_width_tiles = 15
name = "Fortified" name = "Fortified"
[[arena.team.ship]] [[arena.team.ship]]
schematic = "drone" schematic = "drone"
count = 3 count = 10
modules = [ modules = [
{type = "laser_cannon_s", x = 1, y = 1, rotation = "east"}, {type = "railgun_s", x = 0, y = 0, rotation = "east"},
] ]
[[arena.team.station]] [[arena.team.station]]
type = "player_station" type = "player_station"
@@ -90,7 +419,7 @@ enemy_buffer_width_tiles = 15
name = "Swarm" name = "Swarm"
[[arena.team.ship]] [[arena.team.ship]]
schematic = "drone" schematic = "drone"
count = 8 count = 30
modules = [ modules = [
{type = "laser_cannon_s", x = 1, y = 1, rotation = "east"}, {type = "railgun_s", x = 0, y = 0, rotation = "east"},
] ]

View File

@@ -440,6 +440,48 @@ typical loadouts double as the `default_modules` for enemy waves):
scrap-free recipe produces that item, mirroring the reprocessing-path scrap-free recipe produces that item, mirroring the reprocessing-path
rule (see progression_design.md action items). rule (see progression_design.md action items).
### Combat stat anchors — first pass
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.
- **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.
- **TTK check:** a mirror cruiser duel (51 DPS vs 2140 EHP) lasts ~42 s —
inside the 3060 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.
- **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
the existing 150→350 ladder; all weapon ranges stay below sensor
ranges.
- **Weapon modifiers are capital economy:** ×1.2 damage at 22.5 threat
beats adding a gun once a ship carries more than ~68 threat of weapons
— 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
level 0 matches it exactly and scales per push level
(+1500 HP, +12 dmg, +0.1 Hz per level). HQ 5000 HP.
- **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.
## Balancing targets (first pass, July 2026) ## Balancing targets (first pass, July 2026)
The six root numbers for the balancing pass. Every derived value (threat The six root numbers for the balancing pass. Every derived value (threat