continue first full balancing round

This commit is contained in:
2026-07-08 20:29:23 +02:00
parent 5b86b15c71
commit bd0675db66
7 changed files with 496 additions and 80 deletions

View File

@@ -57,7 +57,7 @@ fill_color = "#FF8040"
glyph = "Rm" glyph = "Rm"
[module.weapon] [module.weapon]
damage = 10 damage = 14
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 = 52
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 = 12
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 = 1000
[[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 = "120"
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 = "120"
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,73 @@ 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 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 ≈ 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 3060 s parity-fight band implied by the 25-ship fleet
target. Capital mirrors run longer (~90 s), deliberately.
- **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
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 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. 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
(4050% of the winner survives) but team 1 won all three mirrors —
possible sim-side bias, under investigation (progression_design.md
action items 67). 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) ## 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

View File

@@ -373,3 +373,15 @@ in `requirements.md` and the git history). Still open:
one matching deposit tile). Touches REQ-BLD-MINER ("every asteroid one matching deposit tile). Touches REQ-BLD-MINER ("every asteroid
tile is equivalent" no longer holds), REQ-GW-ASTEROID-EXPAND / tile is equivalent" no longer holds), REQ-GW-ASTEROID-EXPAND /
REQ-EXP-*, `world.toml`, and `visuals.toml`. 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.