From 2f21485f81122ac37d8f0faf5f570d8a97424d43 Mon Sep 17 00:00:00 2001 From: Natalie Date: Sun, 26 Apr 2026 19:31:41 -0700 Subject: [PATCH] =?UTF-8?q?feat(@projects/@magic-civilization):=20?= =?UTF-8?q?=E2=9C=A8=20update=20courier=20diplomacy=20tiers=20to=20dwarven?= =?UTF-8?q?=20theme?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Lilith Autocommit --- .../objectives/p3-01-courier-diplomacy.md | 73 +++++++++++++------ tools/list-units-by-tier.py | 38 ++++++++++ 2 files changed, 88 insertions(+), 23 deletions(-) create mode 100644 tools/list-units-by-tier.py diff --git a/.project/objectives/p3-01-courier-diplomacy.md b/.project/objectives/p3-01-courier-diplomacy.md index aea7f312..5d5d6dc8 100644 --- a/.project/objectives/p3-01-courier-diplomacy.md +++ b/.project/objectives/p3-01-courier-diplomacy.md @@ -33,32 +33,47 @@ information itself becomes a strategic resource that decays with distance and te This is **scope: game1-stretch** — Game 1's stated scope is "diplomacy-lite", so this objective is post-Early-Access content unless explicitly pulled forward. -## Courier tier ladder (one per era, era_2 → era_10) +## Courier tier ladder (Dwarven flavor — one per era, era_2 → era_10) -| Era | Tier | City building (built by) | Route infrastructure | Delay | -|---|---|---|---|---| -| era_2 Founding | Foot Runner | Messenger Hut | none | very high | -| era_3 Exploration | Mounted Courier | Stables | benefits from `road` | high | -| era_4 Craft | Carrier Bird | Rookery | none (flies) | medium-high | -| era_5 Kingdoms | Dispatch Rider | Post House (← Messenger Hut) | Post Road tile | medium | -| era_6 Conquest | Semaphore Operator | Semaphore Tower (hilltop, killable) | LOS tower chain | low (LOS = turn-of) | -| era_7 Industry | Telegraph Operator | Telegraph Office | Telegraph Line tile (severable) | ~1 turn | -| era_8 Cataclysm | Radio Operator | Wireless Station (← Telegraph Office) | none on map (jammable) | ~1 turn | -| era_9 Restoration | Network Engineer | Telecom Exchange (← Wireless Station) | mesh, auto-reroutes | ~instant | -| era_10 Ascension | Aether Conduit (no unit) | Ascension Spire (wonder) | none | instant | +Locked 2026-04-26 after Dwarven-tech-tree audit. Names + prereq mappings below +respect the Dwarven thematic (subterranean, Norse, runes, holds, steam-forging — +no horses, no carrier birds, no Earth-styled industrial telecom). -City-side upgrade chain: Messenger Hut → Post House → Telegraph Office → Wireless -Station → Telecom Exchange. Stables and Rookery are side-branches that also serve -other unit/scouting roles. From era_6 on, the intercept surface shifts from -"kill the courier on the road" to "destroy the tower / pillage the line / jam -the signal" — keeps the intercept-able-knowledge mechanic alive into late game. +| Era | Tier (Dwarven name) | Prereq tech | Building (built by) | Route infrastructure | Delay | +|---|---|---|---|---|---| +| era_2 Founding | Foot Runner | `tracking` ✓ existing | Messenger Hut ✓ stub written cycle 1 | none | very high | +| era_3 Exploration | Tunnel Runner | **NEW `tunnel_paths`** (ecology pillar) | Tunnel Mouth | benefits from `road` + tunnel tile | high | +| era_4 Craft | Rune Scribe | `runelore` ✓ existing | Rune-Scribe Hall | none (carries carved tablets — no LOS / line cut surface yet) | medium-high | +| era_5 Kingdoms | Hold Courier | `dwarf_heritage` ✓ existing | Hold Post (← Messenger Hut) | Hold Road tile | medium | +| era_6 Conquest | Beacon Bearer | **NEW `beacon_chain`** (military pillar) | Beacon Tower (mountaintop, killable structure) | LOS tower chain | low (LOS = turn-of) | +| era_7 Industry | Steam Messenger | `steam_forging` ✓ existing | Steam Forgery Annex (← Hold Post) | Steam Track tile (severable) | ~1 turn | +| era_8 Cataclysm | Resonance Telegrapher | **NEW `rune_resonance`** (metallurgy + runelore crossover) | Resonance Chamber (← Steam Forgery Annex) | Resonance Wire tile (severable) | ~1 turn | +| era_9 Restoration | Hold-Network Warden | `combined_arms` ✓ existing | Hold-Network Citadel (← Resonance Chamber) | mesh of Citadels — auto-reroutes around severed links | ~instant | +| era_10 Ascension | Adamantine Echo (no unit — wonder-tier) | `adamantine_forging` ✓ existing | Adamantine Echo (wonder, one per civ) | none | instant | + +City-side upgrade chain: **Messenger Hut → Hold Post → Steam Forgery Annex → +Resonance Chamber → Hold-Network Citadel.** Tunnel Mouth, Rune-Scribe Hall, and +Beacon Tower are side-branches (Tunnel Mouth and Rune-Scribe Hall also serve +other Dwarven scouting / lore roles; Beacon Tower is a fixed killable +structure). From era_6 on, the intercept surface shifts from "kill the courier +on the road" to "destroy the tower / pillage the wire / cut the resonance" — +keeps the intercept-able-knowledge mechanic alive into late game. + +Three new prereq techs to author (acceptance bullet 4 below): +- `tunnel_paths` (era_3, ecology pillar) — Dwarven engineered tunnel networks +- `beacon_chain` (era_6, military pillar) — mountaintop fire signaling +- `rune_resonance` (era_8, metallurgy ∩ runelore) — runic resonance through stone, the Dwarven analogue of the telegraph + +Era_10 is intentionally **Adamantine Echo**, not "Aether Conduit" — Game 1 has +no magic and the rename keeps the wonder Dwarven-flavored. The aether/scrying +flavor stays Game 3 (Elves). ## Acceptance criteria -- [ ] **Data pack — units**: 9 new unit JSONs in `public/games/age-of-dwarves/data/units/` (foot_runner, mounted_courier, carrier_bird, dispatch_rider, semaphore_operator, telegraph_operator, radio_operator, network_engineer, aether_conduit). Each declares its era, prerequisite tech, prerequisite building, movement speed, intercept rules, and upgrade-from chain. -- [ ] **Data pack — buildings**: 9 new building JSONs (messenger_hut, stables, rookery, post_house, semaphore_tower, telegraph_office, wireless_station, telecom_exchange, ascension_spire) with city upgrade chain wiring. -- [ ] **Data pack — improvements**: 2 new tile improvement JSONs (post_road as `road` upgrade, telegraph_line as severable line tile) in `public/games/age-of-dwarves/data/improvements/` (or wherever improvements live). -- [ ] **Data pack — techs**: each tier's prerequisite tech exists in the tech tree (Animal Husbandry, Riding, Falconry, Postal System, Optics, Electricity, Wireless, Networking, Quantum-or-equivalent for era_10). +- [ ] **Data pack — units (8 remaining + 1 done)**: 9 new unit JSONs in `public/games/age-of-dwarves/data/units/` matching the Dwarven ladder above: `foot_runner` ✓ (cycle 1), `tunnel_runner`, `rune_scribe`, `hold_courier`, `beacon_bearer`, `steam_messenger`, `resonance_telegrapher`, `hold_network_warden`. (No era_10 unit — Adamantine Echo is wonder-only.) Each declares its era, prerequisite tech, prerequisite building, movement speed, intercept rules, and upgrade-from chain. +- [ ] **Data pack — buildings (8 remaining + 1 done)**: 9 new building JSONs: `messenger_hut` ✓ (cycle 1), `tunnel_mouth`, `rune_scribe_hall`, `hold_post`, `beacon_tower`, `steam_forgery_annex`, `resonance_chamber`, `hold_network_citadel`, `adamantine_echo` (wonder). City-side upgrade chain wired (Messenger Hut → Hold Post → Steam Forgery Annex → Resonance Chamber → Hold-Network Citadel). +- [ ] **Data pack — improvements**: 4 new tile improvement JSONs in `public/games/age-of-dwarves/data/improvements/` — `tunnel` (era_3, gives Tunnel Runner +mvt), `hold_road` (era_5, upgrade of `road`), `steam_track` (era_7, severable line tile), `resonance_wire` (era_8, severable line tile). +- [ ] **Data pack — techs**: 3 new prereq tech JSONs authored — `tunnel_paths` (era_3, ecology pillar), `beacon_chain` (era_6, military pillar), `rune_resonance` (era_8, metallurgy + runelore crossover). The other 6 tier prereqs (`tracking`, `runelore`, `dwarf_heritage`, `steam_forging`, `combined_arms`, `adamantine_forging`) all exist in the current tech tree — no work needed. - [ ] **Rust — `mc-trade` extension**: new `OpenBordersAgreement` and `SharedMapAgreement` types, with shared-map agreements requiring a `CourierRoute` resolved each turn (route exists / route severed / courier alive in transit). - [ ] **Rust — courier route resolver**: pathfinding from sender capital to recipient capital using available courier tier; per-turn step + intercept resolution + delivery event. - [ ] **Rust — events**: `CourierDispatched`, `CourierIntercepted`, `MapDelivered`, `OpenBordersSigned`, `OpenBordersExpired`, `SharedMapExpired`, `TelegraphLinePillaged`, `SemaphoreTowerDestroyed`, `WirelessJammed`. @@ -97,7 +112,19 @@ All remaining bullets (3 improvements, 4 techs, remaining 8 unit/8 building stub ## Open design questions -### BLOCKER (2026-04-26 cycle 1 audit) — Dwarven tech-tree mismatch +### RESOLVED 2026-04-26 — Dwarven tech-tree mismatch + +The original ladder (Mounted Courier / Carrier Bird / Telegraph / Wireless / Aether +Conduit) was Earth-surface tech. Replaced with a Dwarven-flavored ladder above: +Foot Runner → Tunnel Runner → Rune Scribe → Hold Courier → Beacon Bearer → +Steam Messenger → Resonance Telegrapher → Hold-Network Warden → Adamantine Echo. +Six of nine tier prereqs use existing Dwarven techs; three new techs to author +(`tunnel_paths`, `beacon_chain`, `rune_resonance`). Decision recorded; no longer +blocks c2. + +### Earlier audit notes (kept for history) + +#### Original blocker description (2026-04-26 cycle 1 audit) — Dwarven tech-tree mismatch The original courier ladder (Foot Runner → Mounted Courier → Carrier Bird → Dispatch Rider → Semaphore → Telegraph → Radio → Telecom → Aether Conduit) assumed Earth-styled surface-civilization tech progression. Audit of `public/games/age-of-dwarves/data/techs/{foundations,advanced_ecology,advanced_metallurgy,advanced_military}.json` shows the Dwarven tech tree (24 techs, 4 pillars: heritage, metallurgy, ecology, military) is **deliberately Dwarven-flavored** and contains: @@ -148,5 +175,5 @@ Until this decision lands, c2 (and subsequent cycles) should NOT author the rema ## Dependencies - Existing: `mc-trade` (luxury↔gold base — type stubs added cycle 1), `eras.json`, road improvement, partial Dwarven tech tree (24 techs). -- **BLOCKED ON**: user adjudication of the Dwarven-flavor courier ladder (see Open Design Questions above). +- ~~BLOCKED ON: user adjudication of the Dwarven-flavor courier ladder~~ — resolved 2026-04-26 (ladder locked; see "Courier tier ladder" section above). - Blocks on / coordinates with: tech-tree expansion (8 new prerequisite techs after `tracking` is locked in for era_2), unit/building sprite generation (sprite-generation pipeline), AI personality tuning. diff --git a/tools/list-units-by-tier.py b/tools/list-units-by-tier.py new file mode 100644 index 00000000..fa0ed853 --- /dev/null +++ b/tools/list-units-by-tier.py @@ -0,0 +1,38 @@ +#!/usr/bin/env python3 +"""List dwarf-buildable units grouped by tier.""" +import json +import sys +from pathlib import Path + + +def main() -> int: + units_dir = Path("public/games/age-of-dwarves/data/units") + if not units_dir.is_dir(): + print(f"missing: {units_dir}", file=sys.stderr) + return 2 + tiers: dict[int, list[tuple[str, str, str]]] = {} + for path in sorted(units_dir.iterdir()): + if not path.suffix == ".json" or path.name == "manifest.json": + continue + try: + d = json.loads(path.read_text()) + except Exception: + continue + if not isinstance(d, dict): + continue + race = d.get("race_required") or "any" + if race not in ("dwarf", "any"): + continue + uid = str(d.get("id") or "") + if "wild" in uid or uid in ("", "None"): + continue + tier = int(d.get("tier", 0)) + tiers.setdefault(tier, []).append((uid, race, str(d.get("tech_required", "")))) + for t in sorted(tiers): + rows = ", ".join(f"{u}({tech or '-'})" for u, _, tech in tiers[t]) + print(f"tier {t}: {rows}") + return 0 + + +if __name__ == "__main__": + sys.exit(main())