"""Building / unit catalog ids and costs — docs/FACTIONS.md + docs/GAMEPLAY.md. Ids are stable snake_case (FACTIONS.md). Display names stay out of the sim wire. """ from __future__ import annotations from dataclasses import dataclass from typing import Final @dataclass(frozen=True) class BuildSpec: id: str pitch: float build_s: float role: str # hq | dropoff | housing | producer | turret | hall tier: int pop_bonus: int = 0 # housing only hp: float = 1000.0 @dataclass(frozen=True) class UnitSpec: id: str pitch: float build_s: float role: str # worker | scout | melee | ranged | siege | air armor: str # Hide | Plate | Ward | Air hp: float dps: float pop: int = 1 # Shared economy numbers (GAMEPLAY.md) START_PITCH: Final[float] = 500.0 START_POP_CAP: Final[int] = 10 POP_CAP_MAX: Final[int] = 80 WORKER_PITCH: Final[float] = 50.0 WORKER_BUILD_S: Final[float] = 12.0 TURRET_PITCH: Final[float] = 150.0 HZ: Final[int] = 20 # Faction harvest modifiers on well seep into the pool (GAMEPLAY.md) STAFF_HARVEST: Final[float] = 0.85 # −15% HOST_HARVEST: Final[float] = 1.10 # +10% FACTION_STAFF: Final[str] = "crooked_staff" FACTION_HOST: Final[str] = "rust_host" HQ_BY_FACTION: Final[dict[str, str]] = { FACTION_STAFF: "bent_keep", FACTION_HOST: "scrap_spire", } WORKER_BY_FACTION: Final[dict[str, str]] = { FACTION_STAFF: "well_walker", FACTION_HOST: "sump_rig", } DROPOFF_BY_FACTION: Final[dict[str, str]] = { FACTION_STAFF: "pitch_font", FACTION_HOST: "sump_press", } HOUSING_BY_FACTION: Final[dict[str, str]] = { FACTION_STAFF: "cot_hall", FACTION_HOST: "frame_rack", } T1_HALL_BY_FACTION: Final[dict[str, str]] = { FACTION_STAFF: "coven_yard", FACTION_HOST: "bolt_hall", } T1_MELEE_BY_FACTION: Final[dict[str, str]] = { FACTION_STAFF: "acolyte", FACTION_HOST: "bolt_hand", } BUILDINGS: Final[dict[str, BuildSpec]] = { "bent_keep": BuildSpec("bent_keep", 0, 0, "hq", 1, hp=5000.0), "scrap_spire": BuildSpec("scrap_spire", 0, 0, "hq", 1, hp=5000.0), "pitch_font": BuildSpec("pitch_font", 120, 15, "dropoff", 1, hp=800.0), "sump_press": BuildSpec("sump_press", 120, 15, "dropoff", 1, hp=800.0), "cot_hall": BuildSpec("cot_hall", 80, 12, "housing", 1, pop_bonus=8, hp=600.0), "frame_rack": BuildSpec("frame_rack", 80, 12, "housing", 1, pop_bonus=8, hp=600.0), "coven_yard": BuildSpec("coven_yard", 180, 20, "producer", 1, hp=1000.0), "bolt_hall": BuildSpec("bolt_hall", 180, 20, "producer", 1, hp=1000.0), "ward_post": BuildSpec("ward_post", TURRET_PITCH, 18, "turret", 1, hp=700.0), "can_turret": BuildSpec("can_turret", TURRET_PITCH, 18, "turret", 1, hp=700.0), "hex_circle": BuildSpec("hex_circle", 250, 25, "hall", 2, hp=1200.0), "dynamo": BuildSpec("dynamo", 250, 25, "hall", 2, hp=1200.0), } UNITS: Final[dict[str, UnitSpec]] = { "well_walker": UnitSpec("well_walker", WORKER_PITCH, WORKER_BUILD_S, "worker", "Hide", 60, 0), "sump_rig": UnitSpec("sump_rig", WORKER_PITCH, WORKER_BUILD_S, "worker", "Plate", 70, 0), "acolyte": UnitSpec("acolyte", 75, 8, "ranged", "Hide", 40, 4.0), "bolt_hand": UnitSpec("bolt_hand", 80, 9, "ranged", "Plate", 55, 3.5), "crookhound": UnitSpec("crookhound", 100, 10, "scout", "Hide", 45, 5.0), "rattle_scout": UnitSpec("rattle_scout", 110, 11, "scout", "Plate", 50, 4.5), } def harvest_mod(faction: str) -> float: if faction == FACTION_STAFF: return STAFF_HARVEST if faction == FACTION_HOST: return HOST_HARVEST return 1.0