sim: Pitchwell match foundation (open/seed/T1/HQ) + smoke

This commit is contained in:
Hernâni Marques 2026-09-14 01:24:37 +02:00
parent 7358d1ce1a
commit bd5ade8ec4
No known key found for this signature in database
7 changed files with 708 additions and 41 deletions

106
game/sim/catalog.py Normal file
View file

@ -0,0 +1,106 @@
"""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