feat(@projects): ✨ add project objectives roadmap
Co-Authored-By: Lilith Autocommit <noreply@atlilith.com>
|
|
@ -34,9 +34,10 @@ loop-variable-name: _?[a-z][a-z0-9]*(_[a-z0-9]+)*
|
|||
signal-name: '[a-z][a-z0-9]*(_[a-z0-9]+)*'
|
||||
sub-class-name: _?([A-Z][a-z0-9]*)+
|
||||
|
||||
# Limits (aligned with Lilith ecosystem standards)
|
||||
# Limits (aligned with project 3-language standards: 500 LOC hard cap, 300 soft warn)
|
||||
# See ~/.claude/instructions/godot-code-standards.md "File Size Limits".
|
||||
max-line-length: 100
|
||||
max-file-lines: 600
|
||||
max-file-lines: 500
|
||||
max-public-methods: 100
|
||||
max-returns: 6
|
||||
function-arguments-number: 10
|
||||
|
|
|
|||
|
|
@ -1,3 +1,11 @@
|
|||
# CHANGELOG
|
||||
|
||||
Dated narrative events, append-only. **Newest at bottom.** References objective IDs (e.g. `p0-05`) from `objectives/`; never restates status. For current state see `objectives/`.
|
||||
|
||||
Entry format: `YYYY-MM-DD HH:MM <short topic>: <what happened> (files=N) [ref: p0-XX]`
|
||||
|
||||
---
|
||||
|
||||
2026-04-15 01:00 iter 1: GROWTH, median p0_pop_peak 3→6 (seed 1 smoke), files=3 (city.rs, turn_processor.gd, turn_processor_helpers.gd). Rust: FOOD_PER_POP 2.0→1.5. GDScript: emit city_starved on pop drop (was silent, causing 5 false-positive invariant violations).
|
||||
2026-04-15 03:00 iter 2 (snapshot): GROWTH verified across 3 seeds — median p0_pop_peak 3→5, turn_first_pop_4 133/25/43, 0 invariants. Next gap: VICTORY (0/3 outcome=victory). Dispatching victory-dev.
|
||||
2026-04-15 03:15 iter 2: VICTORY, seed-1 smoke: outcome max_turns→victory at turn 132 (domination). Files=3 (city.gd: original_capital_owner field; ai_turn_bridge.gd: owner-before-found reorder; victory_manager.gd: rewrote _check_domination on capital ownership). Full 3-seed verification pending next batch.
|
||||
37
.project/README.md
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
# `.project/` — Directory Map
|
||||
|
||||
Build-process docs for Magic Civilization. Each file owns exactly one responsibility. Status of work-in-flight is tracked **only** in `objectives/` (SSoT).
|
||||
|
||||
## File / dir → responsibility
|
||||
|
||||
| Path | Responsibility | Rule |
|
||||
|---|---|---|
|
||||
| `README.md` | This map | Maintained by hand when structure changes |
|
||||
| `ROADMAP.md` | Phase **sequence** + **scope** per milestone | **Never** carries status; references objective IDs only |
|
||||
| `TERMINOLOGY.md` | Glossary (terms, acronyms, design vocabulary) | Facts only, no status |
|
||||
| `CHANGELOG.md` | Dated narrative events (append-only) | References objective IDs; **never** restates status |
|
||||
| `objectives/` | **Single source of truth** for current state | One `.md` per objective, YAML frontmatter `status:` field |
|
||||
| `objectives/README.md` | Dashboard index (grouped by P0/P1/P2) | **Generated** by `tools/objectives-report.py` — do not hand-edit |
|
||||
| `tasks/milestones/` | Per-milestone work packages (scoping docs) | HOW, not WHAT-DONE |
|
||||
| `tasks/topics/` | Cross-cutting topic work (balance tuning etc.) | HOW, not WHAT-DONE |
|
||||
| `tasks/deferred/` | Parked work packages | HOW, not WHAT-DONE |
|
||||
| `handoffs/` | Agent-to-agent context transfer | `YYYYMMDD_slug.md` |
|
||||
| `history/` | Archived one-off docs (reports, snapshots, obsolete plans) | `YYYYMMDD_slug.md`; immutable once filed |
|
||||
| `reports/batches/` | Autoplay batch output | Tool artifacts |
|
||||
| `reports/simulation/` | Simulator reports | Tool artifacts |
|
||||
| `reports/screenshots/` | Proof screenshots | Tool artifacts |
|
||||
| `future-games/` | Game 2 design drafts | Out of scope for Game 1 |
|
||||
| `gdlintrc.local` | Local gdlint overrides | Config |
|
||||
|
||||
## Invariants
|
||||
|
||||
1. **Status lives in `objectives/*.md` frontmatter, nowhere else.**
|
||||
2. **ROADMAP, CHANGELOG, tasks/** may *reference* objective IDs; they **may not** restate status.
|
||||
3. `objectives/README.md` is machine-generated from frontmatter. Regenerate after any objective edit: `python3 tools/objectives-report.py`.
|
||||
4. `history/` is append-only. Archived files get a `YYYYMMDD_` prefix and are never edited in place; if a superseding doc is needed, create a new one.
|
||||
|
||||
## Quick regen
|
||||
|
||||
```bash
|
||||
python3 tools/objectives-report.py # rebuilds objectives/README.md from frontmatter
|
||||
```
|
||||
33
.project/objectives/p0-01-mcts-wiring.md
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
---
|
||||
id: p0-01
|
||||
title: Wire MCTS into gameplay AI
|
||||
priority: p0
|
||||
status: partial
|
||||
scope: game1
|
||||
updated_at: 2026-04-17
|
||||
evidence:
|
||||
- src/simulator/crates/mc-ai/src/mcts_tree.rs
|
||||
- src/simulator/api-gdext/src/ai.rs
|
||||
- src/game/engine/src/modules/ai/ai_turn_bridge.gd
|
||||
- src/game/engine/src/modules/ai/simple_heuristic_ai.gd
|
||||
---
|
||||
|
||||
## Summary
|
||||
|
||||
`mc-ai/src/mcts_tree.rs` (138 lines, 22/22 tests) and the `GdMcTreeController` binding exist, but `grep -r "mcts\|MctsTreeController\|run_mcts" src/game/engine/src/modules/ai/` returns 0 matches. The game never calls the tree — only `SimpleHeuristicAi` drives AI turns.
|
||||
|
||||
## Evidence of gap
|
||||
|
||||
- Batch 2026-04-16: victory rate 4/10 (target 50–80%), median `p0_pop_peak=25` (target ≥30), 6/10 stalemate at `max_turns`.
|
||||
- `.project/CHANGELOG.md` 2026-04-16 14:36 — "MCTS FOUNDATION complete … Not wired to GDExtension yet".
|
||||
|
||||
## Acceptance
|
||||
|
||||
- `AiTurnBridge` delegates to MCTS when `AI_USE_MCTS=true` and falls back to `SimpleHeuristicAi` otherwise.
|
||||
- A seeded 10-game batch with MCTS on moves median TTV into the 200–350 band and victory rate into ≥50%.
|
||||
- Determinism preserved (same seed → same outcome).
|
||||
|
||||
## Non-goals
|
||||
|
||||
- Replacing `SimpleHeuristicAi` (keep as fast-path / early-turn fallback).
|
||||
- Per-clan weight variation (that's `p0-02`).
|
||||
25
.project/objectives/p0-02-clan-personalities.md
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
---
|
||||
id: p0-02
|
||||
title: Five AI clan personalities drive distinct playstyles
|
||||
priority: p0
|
||||
status: partial
|
||||
scope: game1
|
||||
updated_at: 2026-04-17
|
||||
evidence:
|
||||
- public/games/age-of-dwarves/data/ai_personalities.json
|
||||
- src/simulator/crates/mc-ai/src/
|
||||
---
|
||||
|
||||
## Summary
|
||||
|
||||
`ai_personalities.json` defines Ironhold / Goldvein / Blackhammer / Deepforge / Runesmith, but `mc-ai` has no per-clan `ScoringWeights` variants. Every AI plays identically, so the five-clan promise in `CLAUDE.md` isn't delivered.
|
||||
|
||||
## Acceptance
|
||||
|
||||
- `mc-ai::ScoringWeights::from_personality(id: &str)` loads weights from JSON.
|
||||
- AI assignment at game start picks one of the 5 personalities per AI player.
|
||||
- Batch of 5 seeds with `AI_PIN_PERSONALITY=<id>` produces measurably different stats per clan (expansion_axis, combat frequency, wealth).
|
||||
|
||||
## Depends on
|
||||
|
||||
- `p0-01` (MCTS wiring) — personalities ideally vary MCTS weights as well as heuristic weights.
|
||||
22
.project/objectives/p0-03-pvp-in-turn.md
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
---
|
||||
id: p0-03
|
||||
title: PvP combat resolved inside the authoritative turn processor
|
||||
priority: p0
|
||||
status: partial
|
||||
scope: game1
|
||||
updated_at: 2026-04-17
|
||||
evidence:
|
||||
- src/simulator/crates/mc-turn/src/processor.rs
|
||||
- src/simulator/crates/mc-combat/src/
|
||||
- src/game/engine/scenes/world_map/world_map_combat.gd
|
||||
---
|
||||
|
||||
## Summary
|
||||
|
||||
`mc-turn::processor` currently resolves only `LairCombat` (fauna). Player-vs-player attacks go through the GDScript world-map click path, which bypasses the authoritative simulation. MCTS rollouts (`p0-01`) need deterministic PvP in Rust.
|
||||
|
||||
## Acceptance
|
||||
|
||||
- `processor.rs` resolves queued PvP attacks each turn via `mc-combat::CombatResolver`.
|
||||
- Headless batch run (no GDScript combat path) produces identical combat results to the GDScript-mediated game for the same seed.
|
||||
- GDScript click-to-attack becomes a thin input wrapper that enqueues a Rust-resolved attack.
|
||||
26
.project/objectives/p0-04-wonder-tracking.md
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
---
|
||||
id: p0-04
|
||||
title: World wonder tracking in PlayerState and score victory
|
||||
priority: p0
|
||||
status: partial
|
||||
scope: game1
|
||||
updated_at: 2026-04-17
|
||||
evidence:
|
||||
- src/simulator/crates/mc-turn/src/victory.rs
|
||||
- public/games/age-of-dwarves/data/buildings/mundane_wonders.json
|
||||
---
|
||||
|
||||
## Summary
|
||||
|
||||
`mc-turn/src/victory.rs:44-45` comment: *"no `wonders_built` term because `PlayerState` carries no wonder count."* `mundane_wonders.json` contains all 24 wonders T1–T10 with mundane-only fields (`school: null`, `mana_generated: null`). Data exists; simulator state and score weighting do not.
|
||||
|
||||
## Acceptance
|
||||
|
||||
- `PlayerState.wonders_built: BTreeSet<WonderId>` field added (BTree for determinism).
|
||||
- Wonder completion in `mc-city::production` appends to the set.
|
||||
- `victory::calculate_score` folds wonder count (with tier multiplier).
|
||||
- Encyclopedia/city UI surfaces a "Wonders built" listing per player.
|
||||
|
||||
## Depends on
|
||||
|
||||
- Nothing. Self-contained.
|
||||
24
.project/objectives/p0-05-culture-and-borders.md
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
---
|
||||
id: p0-05
|
||||
title: Culture generation and border expansion
|
||||
priority: p0
|
||||
status: stub
|
||||
scope: game1
|
||||
updated_at: 2026-04-17
|
||||
evidence:
|
||||
- src/simulator/crates/mc-culture/src/lib.rs
|
||||
- src/simulator/crates/mc-city/
|
||||
- src/game/engine/src/rendering/overlay_renderer.gd
|
||||
---
|
||||
|
||||
## Summary
|
||||
|
||||
`mc-culture/src/lib.rs` is **literally 1 line**: `// TODO: culture generation, border expansion`. The renderer has border-overlay capability but nothing drives it. Single largest pure-stub gap.
|
||||
|
||||
## Acceptance
|
||||
|
||||
- Per-city culture accumulation per turn (yield from buildings + tile modifiers).
|
||||
- Ring-1 → ring-2 → ring-3 border expansion thresholds from JSON.
|
||||
- `city_border_expanded` event wired to `overlay_renderer.gd`.
|
||||
- `mc-turn::victory::calculate_score` folds culture tier.
|
||||
- GDScript `SimpleHeuristicAi` scoring factors in culture yield.
|
||||
26
.project/objectives/p0-06-economy-integration.md
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
---
|
||||
id: p0-06
|
||||
title: Fold gold income / upkeep / improvement yields into turn loop
|
||||
priority: p0
|
||||
status: partial
|
||||
scope: game1
|
||||
updated_at: 2026-04-17
|
||||
evidence:
|
||||
- src/simulator/crates/mc-economy/src/lib.rs
|
||||
- src/simulator/crates/mc-economy/src/gold.rs
|
||||
- src/simulator/crates/mc-economy/src/treasury.rs
|
||||
- src/simulator/crates/mc-economy/src/stockpile.rs
|
||||
- src/simulator/crates/mc-turn/src/processor.rs
|
||||
---
|
||||
|
||||
## Summary
|
||||
|
||||
`mc-economy` submodules have working code (713 lines across `gold.rs` 221, `treasury.rs` 314, `stockpile.rs` 178) but `lib.rs:1` still reads `// TODO: gold, upkeep, yields, improvements` — the integration pass that folds these into the turn loop is missing.
|
||||
|
||||
## Acceptance
|
||||
|
||||
- Per-turn gold income = Σ(city marketplace yield + trade route yield).
|
||||
- Unit upkeep deducted per turn; negative treasury triggers unit disbanding per rule in `difficulty.json`.
|
||||
- Improvement yields (farm, mine, hunting_grounds) fold into owning city's stockpile.
|
||||
- Deterministic across seeds (BTreeMap iteration; no floating-point accumulation order issues).
|
||||
- `mc-turn` tests exercise the full income/upkeep/yield path.
|
||||
22
.project/objectives/p0-07-tech-research-costs.md
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
---
|
||||
id: p0-07
|
||||
title: Tech research costs and science pool pacing
|
||||
priority: p0
|
||||
status: partial
|
||||
scope: game1
|
||||
updated_at: 2026-04-17
|
||||
evidence:
|
||||
- src/simulator/crates/mc-tech/src/lib.rs
|
||||
- public/games/age-of-dwarves/data/techs/
|
||||
---
|
||||
|
||||
## Summary
|
||||
|
||||
`mc-tech` has the prerequisite graph and unlock signals but no per-tech science cost accumulation. Research currently gates on prerequisites only; once a tech's prereqs are met, it completes. Games finish with wildly different tech counts across seeds.
|
||||
|
||||
## Acceptance
|
||||
|
||||
- `cost: u32` field in each tech JSON; schema validated by `tools/validate-game-data.py`.
|
||||
- Per-player `science_pool: i64` in `PlayerState`; accumulates per-turn science from cities.
|
||||
- Completion when `science_pool ≥ tech.cost`; pool decremented by cost (not reset).
|
||||
- Tuning target: full tech tree reachable in ~250 turns at normal difficulty; verifiable via 10-seed batch median `techs_researched`.
|
||||
22
.project/objectives/p0-08-domination-victory.md
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
---
|
||||
id: p0-08
|
||||
title: Domination victory path in mc-turn::victory
|
||||
priority: p0
|
||||
status: partial
|
||||
scope: game1
|
||||
updated_at: 2026-04-17
|
||||
evidence:
|
||||
- src/simulator/crates/mc-turn/src/victory.rs
|
||||
- src/game/engine/scenes/menus/victory_screen.gd
|
||||
---
|
||||
|
||||
## Summary
|
||||
|
||||
ROADMAP declares Domination + Score. Score works (9/9 completable games declare a winner). Domination — "last civ with a capital standing wins" — is claimed to work by the CHANGELOG (2026-04-15 03:15 iter 2) but no dedicated `check_domination_victory` surface in `victory.rs` was confirmed in the audit.
|
||||
|
||||
## Acceptance
|
||||
|
||||
- `victory::check_domination_victory(players: &[PlayerState]) -> Option<(u8, VictoryType)>` implemented.
|
||||
- `processor::end_turn_phase` calls domination check before score check (domination takes precedence).
|
||||
- `victory_screen.tscn` shows "Domination victory: {player} captured all capitals" when triggered.
|
||||
- Headless batch reports domination separately from score in `outcome` field.
|
||||
27
.project/objectives/p0-09-ui-completeness.md
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
---
|
||||
id: p0-09
|
||||
title: City-screen UI completeness (citizen assign, queue controls, promotion picker)
|
||||
priority: p0
|
||||
status: partial
|
||||
scope: game1
|
||||
updated_at: 2026-04-17
|
||||
evidence:
|
||||
- src/game/engine/scenes/city/city_screen.gd
|
||||
- src/game/engine/scenes/city/production_queue.gd
|
||||
- src/game/engine/scenes/combat/promotion_picker.gd
|
||||
---
|
||||
|
||||
## Summary
|
||||
|
||||
Three UI paths assumed-but-unverified:
|
||||
|
||||
1. **Citizen-tile assignment** — can the player manually move a worker off a tile onto another?
|
||||
2. **Production queue controls** — reorder, pause, show cost + ETA per item?
|
||||
3. **Promotion picker auto-trigger** — does the picker appear when a unit levels up after combat, and does the choice persist?
|
||||
|
||||
## Acceptance
|
||||
|
||||
- Manual QA smoke: launch game, found city, right-click a worked tile to unassign, click another to assign, confirm yield recalculates.
|
||||
- Queue: drag-to-reorder works, each row shows `cost / cost_per_turn = ETA`.
|
||||
- Promotion: kill an enemy warrior with a level-0 unit, confirm picker modal opens, pick a promo, reload save, confirm persistence.
|
||||
- Three GUT tests — one per path.
|
||||
31
.project/objectives/p0-10-completion-stability.md
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
---
|
||||
id: p0-10
|
||||
title: Game-completion stability — ≥7/10 seeds declare a winner
|
||||
priority: p0
|
||||
status: partial
|
||||
scope: game1
|
||||
updated_at: 2026-04-17
|
||||
evidence:
|
||||
- tools/autoplay-batch.sh
|
||||
- tools/checklist-report.py
|
||||
- .project/reports/batches/
|
||||
---
|
||||
|
||||
## Summary
|
||||
|
||||
10-seed batch (2026-04-16): 4/10 win, 6/10 stalemate at `max_turns`, median `p0_pop_peak=25` (target ≥30 normal difficulty).
|
||||
|
||||
## Acceptance
|
||||
|
||||
Running `PARALLEL=10 bash tools/autoplay-batch.sh 10 300 .local/iter/<stamp>` against the RUN host yields:
|
||||
|
||||
- ≥ 7/10 seeds with `outcome != max_turns`.
|
||||
- Median time-to-victory in 200–350 turns (normal).
|
||||
- Median `p0_pop_peak ≥ 30`.
|
||||
- 0 invariant violations.
|
||||
- `tools/checklist-report.py` → 14/14 PASS on normal difficulty.
|
||||
|
||||
## Depends on
|
||||
|
||||
- `p0-01` (MCTS wiring) — currently suspected primary cause.
|
||||
- `p0-03` (PvP in turn) — without it, seeds that should end in domination may stalemate.
|
||||
25
.project/objectives/p0-11-mystery-item-authoring.md
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
---
|
||||
id: p0-11
|
||||
title: Author the four T8–T10 mystery item drops
|
||||
priority: p0
|
||||
status: missing
|
||||
scope: game1
|
||||
updated_at: 2026-04-17
|
||||
evidence:
|
||||
- public/games/age-of-dwarves/data/items/manifest.json
|
||||
- CLAUDE.md
|
||||
---
|
||||
|
||||
## Summary
|
||||
|
||||
`CLAUDE.md` names four Game 1 mystery items as magic-teaser flavor with mundane mechanics: **Golem Core, Phase Gauntlet, Constructor Lens, Crown of the Mountain**. `items/manifest.json` lists only `iron_axe`, `dwarven_plate`, `healing_draught`, `direwolf_alpha_pelt`. The four mystery items are not authored.
|
||||
|
||||
## Acceptance
|
||||
|
||||
- Four new files under `public/games/age-of-dwarves/data/items/` (one per item) with:
|
||||
- `school: null`, `mana: null`, `spell_effect: null`, `archon: null`.
|
||||
- Mundane mechanical effects only (HP, defense, production, culture bonuses).
|
||||
- Flavor text written to feel inexplicable / ancient (Game 2 teaser tone).
|
||||
- `items/manifest.json` includes the four new IDs.
|
||||
- Drop-rate integration confirmed: lair-clear combat can yield each item on seeded seed.
|
||||
- Schema validation passes (`tools/validate-game-data.py`).
|
||||
22
.project/objectives/p1-01-diplomacy-lite.md
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
---
|
||||
id: p1-01
|
||||
title: Diplomacy-lite — peace/war toggle plus one trade action
|
||||
priority: p1
|
||||
status: partial
|
||||
scope: game1
|
||||
updated_at: 2026-04-17
|
||||
evidence:
|
||||
- src/simulator/crates/mc-trade/src/lib.rs
|
||||
- src/simulator/crates/mc-trade/src/relation.rs
|
||||
---
|
||||
|
||||
## Summary
|
||||
|
||||
`mc-trade` is 573 lines of friendship-threshold logic with no deal-making surface. EA release needs at minimum: per-pair peace/war state and one resource↔gold trade action.
|
||||
|
||||
## Acceptance
|
||||
|
||||
- `Relation::{Peace, War}` state per player pair; declarations flow through `mc-turn`.
|
||||
- `TradeOffer { from, to, give: Resource, want: Gold }` with accept/reject.
|
||||
- GDScript diplomacy panel exposes declare-war / offer-trade.
|
||||
- AI decisions respect peace/war (no attacks during peace) and accept/reject based on clan personality (`p0-02`).
|
||||
21
.project/objectives/p1-02-strategic-resource-yields.md
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
---
|
||||
id: p1-02
|
||||
title: Strategic resource yields feed into production bonuses
|
||||
priority: p1
|
||||
status: partial
|
||||
scope: game1
|
||||
updated_at: 2026-04-17
|
||||
evidence:
|
||||
- public/games/age-of-dwarves/data/deposits/
|
||||
- src/simulator/crates/mc-city/
|
||||
---
|
||||
|
||||
## Summary
|
||||
|
||||
Recent commits added deposit resource definitions (iron, coal, gems, etc.). Need to verify the wire-through: owning a tile with a strategic deposit should grant its production/military bonus to the owning city, and should gate production of strategic-requiring units (already partially in place per CHANGELOG 2026-04-16 06:19).
|
||||
|
||||
## Acceptance
|
||||
|
||||
- `mc-city::get_yields` sums deposit bonuses on owned tiles.
|
||||
- Unit production gated via `requires_resource: [...]` and blocked at enqueue (Rust `QueueError::MissingResource` already exists).
|
||||
- GUT + Rust test coverage for gating and yielding.
|
||||
26
.project/objectives/p1-03-tutorial-overlay.md
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
---
|
||||
id: p1-03
|
||||
title: First-run tutorial / onboarding overlay
|
||||
priority: p1
|
||||
status: missing
|
||||
scope: game1
|
||||
updated_at: 2026-04-17
|
||||
evidence: []
|
||||
---
|
||||
|
||||
## Summary
|
||||
|
||||
No tutorial scene or onboarding flow exists. 4X games are notoriously opaque on first play; EA needs at minimum a progressive-disclosure hint chain on first game start.
|
||||
|
||||
## Acceptance
|
||||
|
||||
- `src/game/engine/scenes/tutorial/tutorial_overlay.tscn` + controller.
|
||||
- Trigger chain on first `game_started` signal (suppressed if `user://settings.cfg:tutorial_completed=true`):
|
||||
1. Move camera
|
||||
2. Select founder
|
||||
3. Found first city
|
||||
4. Queue a unit
|
||||
5. End turn
|
||||
6. Open tech tree
|
||||
7. Research first tech
|
||||
- Dismissible per step; all-off from `options.tscn`.
|
||||
20
.project/objectives/p1-04-sound-and-music.md
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
---
|
||||
id: p1-04
|
||||
title: Sound effects and music
|
||||
priority: p1
|
||||
status: missing
|
||||
scope: game1
|
||||
updated_at: 2026-04-17
|
||||
evidence: []
|
||||
---
|
||||
|
||||
## Summary
|
||||
|
||||
No audio audit has been run. Ship-quality 4X minimum: SFX on key game events + looping ambient music per era.
|
||||
|
||||
## Acceptance
|
||||
|
||||
- SFX: `turn_started`, `turn_ended`, `city_founded`, `tech_researched`, `unit_killed`, `wonder_built`, `era_advanced`.
|
||||
- Ambient track per era (5 tracks); crossfade on era change.
|
||||
- Options.tscn master / SFX / music volume sliders persist to `user://settings.cfg`.
|
||||
- Licenses recorded in `public/games/age-of-dwarves/assets/audio/LICENSES.md`.
|
||||
27
.project/objectives/p1-05-balance-tuning.md
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
---
|
||||
id: p1-05
|
||||
title: Balance tuning — pop_peak ≥30 median, worker improvements ≥8 min
|
||||
priority: p1
|
||||
status: partial
|
||||
scope: game1
|
||||
updated_at: 2026-04-17
|
||||
evidence:
|
||||
- tools/checklist-report.py
|
||||
- .project/reports/batches/
|
||||
---
|
||||
|
||||
## Summary
|
||||
|
||||
Most recent batch: median `p0_pop_peak=25` (target 30 on normal), `min_worker_improvements` variable by seed. Once `p0-01/02/03/06/07` land, re-tune food/growth/worker-AI to hit targets.
|
||||
|
||||
## Acceptance
|
||||
|
||||
- 10-seed batch on normal difficulty:
|
||||
- Median `p0_pop_peak ≥ 30`.
|
||||
- Min across seeds `worker_improvements ≥ 8`.
|
||||
- Median `techs_researched ≥ 20`.
|
||||
- Median `combats ≥ 120`.
|
||||
|
||||
## Depends on
|
||||
|
||||
- `p0-06` (economy), `p0-07` (tech costs) — both affect pop + tech counts.
|
||||
21
.project/objectives/p1-06-options-polish.md
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
---
|
||||
id: p1-06
|
||||
title: Options screen polish
|
||||
priority: p1
|
||||
status: partial
|
||||
scope: game1
|
||||
updated_at: 2026-04-17
|
||||
evidence:
|
||||
- src/game/engine/scenes/menus/options.tscn
|
||||
- src/game/engine/src/autoloads/settings_manager.gd
|
||||
---
|
||||
|
||||
## Summary
|
||||
|
||||
`options.tscn` exists; content depth unverified. Ship-readiness needs: resolution dropdown, fullscreen toggle, master/SFX/music sliders, autosave interval, tutorial-reset button.
|
||||
|
||||
## Acceptance
|
||||
|
||||
- All settings persist to `user://settings.cfg` via `SettingsManager`.
|
||||
- Changes apply live (no restart) where possible; restart prompt for resolution only if needed.
|
||||
- Reset-to-defaults button.
|
||||
21
.project/objectives/p1-07-chronicle-coverage.md
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
---
|
||||
id: p1-07
|
||||
title: Chronicle notifications coverage
|
||||
priority: p1
|
||||
status: partial
|
||||
scope: game1
|
||||
updated_at: 2026-04-17
|
||||
evidence:
|
||||
- src/game/engine/scenes/hud/chronicle_panel.tscn
|
||||
- src/game/engine/src/autoloads/event_bus.gd
|
||||
---
|
||||
|
||||
## Summary
|
||||
|
||||
`chronicle_panel.tscn` exists. Need to audit that every major `EventBus` signal feeds a user-visible entry: `city_founded`, `city_captured`, `tech_researched`, `unit_lost`, `wonder_completed`, `era_advanced`, `border_expanded`, `combat_finished` (when player-involved).
|
||||
|
||||
## Acceptance
|
||||
|
||||
- Chronicle shows one entry per relevant event, oldest→newest.
|
||||
- Filter controls (All / Military / Research / City / Diplomacy).
|
||||
- Entry click scrolls camera to relevant hex if applicable.
|
||||
27
.project/objectives/p1-08-victory-screen-content.md
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
---
|
||||
id: p1-08
|
||||
title: Victory/defeat screen content — recap, banner, replay seed
|
||||
priority: p1
|
||||
status: partial
|
||||
scope: game1
|
||||
updated_at: 2026-04-17
|
||||
evidence:
|
||||
- src/game/engine/scenes/menus/victory_screen.tscn
|
||||
- src/game/engine/scenes/menus/defeat_screen.tscn
|
||||
---
|
||||
|
||||
## Summary
|
||||
|
||||
Scenes exist; content depth unverified. Ship needs: final score breakdown, wonders built, techs researched, combats won/lost, time-to-victory, seed + map settings displayed, "Replay same seed" button.
|
||||
|
||||
## Acceptance
|
||||
|
||||
- Victory screen shows the structured recap above.
|
||||
- Defeat screen shows equivalent recap plus top-scoring player.
|
||||
- "Replay same seed" button returns to `game_setup` with fields pre-filled.
|
||||
- Both screens respect the player's victory type (`Domination` vs `Score`) via tailored banner copy.
|
||||
|
||||
## Depends on
|
||||
|
||||
- `p0-04` (wonder tracking) — wonders row needs data.
|
||||
- `p0-08` (domination victory) — victory-type banner needs the enum variant.
|
||||
20
.project/objectives/p2-01-minimap-improvements.md
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
---
|
||||
id: p2-01
|
||||
title: Minimap — fog reflection and unit markers
|
||||
priority: p2
|
||||
status: partial
|
||||
scope: game1
|
||||
updated_at: 2026-04-17
|
||||
evidence:
|
||||
- src/game/engine/scenes/hud/minimap.tscn
|
||||
---
|
||||
|
||||
## Summary
|
||||
|
||||
Minimap scene exists; depth of fog/unit reflection unverified. Nice-to-have for navigation on large maps.
|
||||
|
||||
## Acceptance
|
||||
|
||||
- Fog state on minimap matches main map.
|
||||
- Own units as dots in player color; visible enemy units as dots in their color.
|
||||
- Click minimap to jump camera.
|
||||
18
.project/objectives/p2-02-hud-tooltips.md
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
---
|
||||
id: p2-02
|
||||
title: Tooltips on all HUD elements
|
||||
priority: p2
|
||||
status: partial
|
||||
scope: game1
|
||||
updated_at: 2026-04-17
|
||||
evidence: []
|
||||
---
|
||||
|
||||
## Summary
|
||||
|
||||
Top bar, unit panel, city-screen headers, tech-tree nodes all benefit from hover tooltips. Current coverage spotty.
|
||||
|
||||
## Acceptance
|
||||
|
||||
- Every interactive HUD element has a tooltip via `Control.tooltip_text` or custom tooltip scene.
|
||||
- Text resolves through `ThemeVocabulary.lookup()` (no hardcoded strings).
|
||||
19
.project/objectives/p2-03-hotkey-cheat-sheet.md
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
---
|
||||
id: p2-03
|
||||
title: Hotkey cheat sheet (F1 / ?)
|
||||
priority: p2
|
||||
status: missing
|
||||
scope: game1
|
||||
updated_at: 2026-04-17
|
||||
evidence: []
|
||||
---
|
||||
|
||||
## Summary
|
||||
|
||||
World map uses hotkeys (T, C, B, ESC, end-turn) with no in-game reference. F1 or `?` should toggle a non-modal overlay listing all bindings.
|
||||
|
||||
## Acceptance
|
||||
|
||||
- `ui_help` input action bound to F1 and `?`.
|
||||
- Overlay lists all bindings grouped by context (Map / City / Combat / Menus).
|
||||
- Closable with same key or ESC.
|
||||
19
.project/objectives/p2-04-localization-audit.md
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
---
|
||||
id: p2-04
|
||||
title: Localization audit — no hardcoded strings
|
||||
priority: p2
|
||||
status: partial
|
||||
scope: game1
|
||||
updated_at: 2026-04-17
|
||||
evidence:
|
||||
- src/game/engine/src/autoloads/theme_vocabulary.gd
|
||||
---
|
||||
|
||||
## Summary
|
||||
|
||||
`ThemeVocabulary` is architected for localization, but incidental hardcoded strings have accumulated. Run a pass and route them through `vocabulary.json`.
|
||||
|
||||
## Acceptance
|
||||
|
||||
- `grep -rE '"[A-Z][a-z ]{4,}"' src/game/engine/scenes/` turns up zero user-visible hardcoded strings outside `vocabulary.json` lookups.
|
||||
- `tools/validate-i18n.py` (new) fails if a `.gd` UI file contains a literal user-visible string.
|
||||
|
Before Width: | Height: | Size: 64 KiB After Width: | Height: | Size: 64 KiB |
|
Before Width: | Height: | Size: 36 KiB After Width: | Height: | Size: 36 KiB |
|
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 30 KiB |
|
Before Width: | Height: | Size: 93 KiB After Width: | Height: | Size: 93 KiB |
|
Before Width: | Height: | Size: 90 KiB After Width: | Height: | Size: 90 KiB |
|
Before Width: | Height: | Size: 72 KiB After Width: | Height: | Size: 72 KiB |
|
Before Width: | Height: | Size: 84 KiB After Width: | Height: | Size: 84 KiB |
|
Before Width: | Height: | Size: 84 KiB After Width: | Height: | Size: 84 KiB |
|
Before Width: | Height: | Size: 84 KiB After Width: | Height: | Size: 84 KiB |
|
Before Width: | Height: | Size: 84 KiB After Width: | Height: | Size: 84 KiB |
|
Before Width: | Height: | Size: 84 KiB After Width: | Height: | Size: 84 KiB |
|
Before Width: | Height: | Size: 84 KiB After Width: | Height: | Size: 84 KiB |
|
Before Width: | Height: | Size: 84 KiB After Width: | Height: | Size: 84 KiB |
|
Before Width: | Height: | Size: 89 KiB After Width: | Height: | Size: 89 KiB |
|
Before Width: | Height: | Size: 86 KiB After Width: | Height: | Size: 86 KiB |
|
Before Width: | Height: | Size: 86 KiB After Width: | Height: | Size: 86 KiB |
|
Before Width: | Height: | Size: 87 KiB After Width: | Height: | Size: 87 KiB |
|
Before Width: | Height: | Size: 86 KiB After Width: | Height: | Size: 86 KiB |
|
Before Width: | Height: | Size: 158 KiB After Width: | Height: | Size: 158 KiB |
|
Before Width: | Height: | Size: 89 KiB After Width: | Height: | Size: 89 KiB |
|
Before Width: | Height: | Size: 90 KiB After Width: | Height: | Size: 90 KiB |
|
Before Width: | Height: | Size: 87 KiB After Width: | Height: | Size: 87 KiB |
|
Before Width: | Height: | Size: 87 KiB After Width: | Height: | Size: 87 KiB |
|
Before Width: | Height: | Size: 159 KiB After Width: | Height: | Size: 159 KiB |
|
Before Width: | Height: | Size: 88 KiB After Width: | Height: | Size: 88 KiB |
|
Before Width: | Height: | Size: 159 KiB After Width: | Height: | Size: 159 KiB |
|
Before Width: | Height: | Size: 88 KiB After Width: | Height: | Size: 88 KiB |
|
Before Width: | Height: | Size: 89 KiB After Width: | Height: | Size: 89 KiB |
|
Before Width: | Height: | Size: 88 KiB After Width: | Height: | Size: 88 KiB |
|
Before Width: | Height: | Size: 89 KiB After Width: | Height: | Size: 89 KiB |
|
Before Width: | Height: | Size: 88 KiB After Width: | Height: | Size: 88 KiB |
|
Before Width: | Height: | Size: 88 KiB After Width: | Height: | Size: 88 KiB |
|
Before Width: | Height: | Size: 88 KiB After Width: | Height: | Size: 88 KiB |
|
Before Width: | Height: | Size: 88 KiB After Width: | Height: | Size: 88 KiB |
|
Before Width: | Height: | Size: 88 KiB After Width: | Height: | Size: 88 KiB |
|
Before Width: | Height: | Size: 88 KiB After Width: | Height: | Size: 88 KiB |
|
Before Width: | Height: | Size: 88 KiB After Width: | Height: | Size: 88 KiB |
|
Before Width: | Height: | Size: 88 KiB After Width: | Height: | Size: 88 KiB |
|
Before Width: | Height: | Size: 88 KiB After Width: | Height: | Size: 88 KiB |
|
Before Width: | Height: | Size: 88 KiB After Width: | Height: | Size: 88 KiB |
|
Before Width: | Height: | Size: 88 KiB After Width: | Height: | Size: 88 KiB |
|
Before Width: | Height: | Size: 88 KiB After Width: | Height: | Size: 88 KiB |
|
Before Width: | Height: | Size: 87 KiB After Width: | Height: | Size: 87 KiB |
|
Before Width: | Height: | Size: 89 KiB After Width: | Height: | Size: 89 KiB |
|
Before Width: | Height: | Size: 88 KiB After Width: | Height: | Size: 88 KiB |
|
Before Width: | Height: | Size: 89 KiB After Width: | Height: | Size: 89 KiB |
|
Before Width: | Height: | Size: 47 KiB After Width: | Height: | Size: 47 KiB |