diff --git a/.project/designs/README.md b/.project/designs/README.md index 755e6cf5..cc4c70c5 100644 --- a/.project/designs/README.md +++ b/.project/designs/README.md @@ -50,17 +50,17 @@ Visual reference for the sound stack — engine architecture, manifest schema, c **Source of truth.** `src/game/engine/src/autoloads/audio_manager.gd` for runtime behaviour; `public/games/age-of-dwarves/data/audio.json` for the live manifest; `tools/audio-validate.py` and `tools/audio-licenses-render.py` for the gates. If a design here disagrees with one of those, the code wins. -## Other sketches (pending React port) +## Other sketches (ported to React) -Static HTML mockups for individual screens. Each will be ported to a React page in [`app/`](app/) over time; the existing static HTML stays as a reference until the port lands. The React app's `App.tsx` already has stub routes for these screens. +Each static HTML mockup has a React port in [`app/`](app/); the HTML files remain as side-by-side references. -- `combat-preview-sketch.html` — ported as `CombatPreview` page (route `/combat`) -- `hud-sketch.html` — pending; stub at `/hud` -- `main-menu-sketch.html` — pending; stub at `/menu` -- `tech-tree-sketch.html` — pending; stub at `/tech` -- `promotion-picker-sketch.html` — pending; stub at `/promotion` -- `city-screen-sketch.html` — pending; stub at `/city` -- `design-gallery.html` — pending; stub at `/gallery` +- `combat-preview-sketch.html` → `CombatPreview` page (route `/combat`) +- `hud-sketch.html` → `Hud` page (route `/hud`) +- `main-menu-sketch.html` → `MainMenu` page (route `/menu`) +- `tech-tree-sketch.html` → `TechTree` page (route `/tech`) +- `promotion-picker-sketch.html` → `PromotionPicker` page (route `/promotion`) +- `city-screen-sketch.html` → `CityScreen` page (route `/city`) +- `design-gallery.html` → `DesignGallery` page (route `/gallery`) ## See also diff --git a/.project/designs/app/src/data/audioPacks.ts b/.project/designs/app/src/data/audioPacks.ts index fed228cc..32ee1dd2 100644 --- a/.project/designs/app/src/data/audioPacks.ts +++ b/.project/designs/app/src/data/audioPacks.ts @@ -16,7 +16,8 @@ export type License = | "Other"; export type PackStatus = - | "shipped" // Files staged on disk and at least one used in the manifest + | "shipped" // Files staged on disk AND at least one used in audio.json + | "staged" // Downloaded + unzipped, browseable, no manifest entries yet | "candidate" // Recommended source we haven't pulled yet | "external"; // Library source — query-based picks rather than a single pack @@ -145,86 +146,62 @@ export const AUDIO_PACKS: ReadonlyArray = [ id: "kenney-music-jingles", name: "Kenney Music Jingles", publisher: "Kenney", - source_url: "https://kenney.nl/assets/music-jingles", + source_url: + "https://kenney.nl/media/pages/assets/music-jingles/4f5dd770b7-1677590399/kenney_music-jingles.zip", license: "CC0-1.0", - status: "candidate", - staging_dir: null, - approx_file_count: 32, + status: "staged", + staging_dir: "_zip_d34bb0de", + approx_file_count: 86, notes: - "**Highest-leverage missing pack.** ~32 short triumphant/melancholy/neutral musical stingers. Solves the celebration-cue gap: building.*.complete, era_advanced, golden_age_swell, victory_fanfare, wonder_built variants — all currently mapped to impact hits, want musical phrases.", - sources_url_prefix: "kenney.nl/assets/music-jingles", + "**Highest-leverage celebration pack.** 86 short triumphant/melancholy/neutral musical stingers. Solves the celebration-cue gap: building.*.complete, era_advanced, golden_age_swell, victory_fanfare, wonder_built — all currently mapped to impact hits, want musical phrases.", + sources_url_prefix: "kenney.nl/media/pages/assets/music-jingles", tags: ["music", "stinger", "jingle", "celebration", "kenney"], }, { id: "kenney-rpg-audio", name: "Kenney RPG Audio", publisher: "Kenney", - source_url: "https://kenney.nl/assets/rpg-audio", + source_url: + "https://kenney.nl/media/pages/assets/rpg-audio/706161bc16-1677590336/kenney_rpg-audio.zip", license: "CC0-1.0", - status: "candidate", - staging_dir: null, - approx_file_count: 50, + status: "staged", + staging_dir: "_zip_d5af2ebe", + approx_file_count: 52, notes: - "Fantasy bells, chimes, scrolls, sword textures designed for game UI rather than physics foley. Useful complement to Impact Sounds for fantasy ambience.", - sources_url_prefix: "kenney.nl/assets/rpg-audio", + "52 fantasy SFX: bells, chimes, scrolls, sword textures designed for game UI rather than physics foley. Complement to Impact Sounds for fantasy ambience.", + sources_url_prefix: "kenney.nl/media/pages/assets/rpg-audio", tags: ["rpg", "fantasy", "chime", "bell", "kenney"], }, { id: "kenney-ui-audio", name: "Kenney UI Audio", publisher: "Kenney", - source_url: "https://kenney.nl/assets/ui-audio", + source_url: + "https://kenney.nl/media/pages/assets/ui-audio/e19c9b1814-1677590494/kenney_ui-audio.zip", license: "CC0-1.0", - status: "candidate", - staging_dir: null, - approx_file_count: 50, + status: "staged", + staging_dir: "_zip_46168ebd", + approx_file_count: 52, notes: - "Additional UI chimes/notifications beyond the Calinou Interface set. Useful if we want distinct textures for different categories of confirmation.", - sources_url_prefix: "kenney.nl/assets/ui-audio", + "52 additional UI chimes/notifications beyond the Calinou Interface set. Distinct textures for different categories of confirmation.", + sources_url_prefix: "kenney.nl/media/pages/assets/ui-audio", tags: ["ui", "kenney"], }, { id: "kenney-voiceover", name: "Kenney Voiceover Pack (Female + Male)", publisher: "Kenney", - source_url: "https://kenney.nl/assets/voiceover-pack", + source_url: + "https://kenney.nl/media/pages/assets/voiceover-pack/4da09a643f-1677589897/kenney_voiceover-pack.zip", license: "CC0-1.0", - status: "candidate", - staging_dir: null, - approx_file_count: 60, + status: "staged", + staging_dir: "_zip_f65eda44", + approx_file_count: 95, notes: - "Vocal samples (numbers, letters, short utterances). Could support unit_promoted, tech_researched if we want vocal acknowledgement. Optional, character-defining but easy to overuse.", - sources_url_prefix: "kenney.nl/assets/voiceover-pack", + "95 vocal samples (numbers, letters, short utterances). Could support unit_promoted, tech_researched if we want vocal acknowledgement. Optional and easy to overuse.", + sources_url_prefix: "kenney.nl/media/pages/assets/voiceover-pack", tags: ["voice", "kenney"], }, - { - id: "kenney-cinematic-music", - name: "Kenney Cinematic Music", - publisher: "Kenney", - source_url: "https://kenney.nl/assets/cinematic-music", - license: "CC0-1.0", - status: "candidate", - staging_dir: null, - approx_file_count: 12, - notes: - "Heavier orchestral cues. Could replace `victory` or layer for golden_age. Alternative to Junkala if we want a CC0-only music option.", - sources_url_prefix: "kenney.nl/assets/cinematic-music", - tags: ["music", "orchestral", "kenney"], - }, - { - id: "kenney-casual-music", - name: "Kenney Casual Music", - publisher: "Kenney", - source_url: "https://kenney.nl/assets/casual-music", - license: "CC0-1.0", - status: "candidate", - staging_dir: null, - approx_file_count: 15, - notes: - "Lighter-mood music — mismatch for dwarven core but could sneak into between-turn ambience or menu screens.", - sources_url_prefix: "kenney.nl/assets/casual-music", - tags: ["music", "kenney"], - }, { id: "sonniss-gdc", name: "Sonniss GameAudio GDC Bundle", diff --git a/.project/designs/app/src/pages/AudioPacks.tsx b/.project/designs/app/src/pages/AudioPacks.tsx index eee8b84c..61588ec6 100644 --- a/.project/designs/app/src/pages/AudioPacks.tsx +++ b/.project/designs/app/src/pages/AudioPacks.tsx @@ -31,6 +31,19 @@ function countFilesUsedByPack(): Map { const FILES_USED: Map = countFilesUsedByPack(); +const STATUS_BG: Record = { + shipped: "#2a4318", + staged: "#3a3618", + candidate: "#3d2f15", + external: "#1a2533", +}; +const STATUS_FG: Record = { + shipped: "#9bd97a", + staged: "#dbcd6e", + candidate: "#e6ba6e", + external: "#9bbfe0", +}; + // ── Styling ────────────────────────────────────────────────────────────────── const Page = styled.div` @@ -131,24 +144,9 @@ const StatusPill = styled.span<{ $status: PackStatus }>` font-size: 10px; text-transform: uppercase; letter-spacing: 0.05em; - background: ${(p): string => - p.$status === "shipped" - ? "#2a4318" - : p.$status === "candidate" - ? "#3d2f15" - : "#1a2533"}; - color: ${(p): string => - p.$status === "shipped" - ? "#9bd97a" - : p.$status === "candidate" - ? "#e6ba6e" - : "#9bbfe0"}; - border: 1px solid ${(p): string => - p.$status === "shipped" - ? "#2a431899" - : p.$status === "candidate" - ? "#3d2f1599" - : "#1a253399"}; + background: ${(p): string => STATUS_BG[p.$status]}; + color: ${(p): string => STATUS_FG[p.$status]}; + border: 1px solid ${(p): string => STATUS_BG[p.$status] + "99"}; `; const LicensePill = styled.span<{ $license: License }>` @@ -178,6 +176,7 @@ const CardNotes = styled.div` const STATUS_FILTERS: ReadonlyArray<{ id: PackStatus | "all"; label: string }> = [ { id: "all", label: "All" }, { id: "shipped", label: "Shipped (in use)" }, + { id: "staged", label: "Staged (browseable, not in manifest)" }, { id: "candidate", label: "Candidate (not yet pulled)" }, { id: "external", label: "Library (per-file)" }, ]; diff --git a/src/simulator/crates/mc-city/src/city.rs b/src/simulator/crates/mc-city/src/city.rs index af005beb..168d00a7 100644 --- a/src/simulator/crates/mc-city/src/city.rs +++ b/src/simulator/crates/mc-city/src/city.rs @@ -195,12 +195,12 @@ pub const CITY_CENTER_BASELINE_CULTURE: f64 = 2.0; /// reach pop 30 from ~7000 to ~3500 — the dominant lever for pop_peak. pub const GROWTH_FOOD_CARRYOVER: f64 = 0.5; -/// Base city HP before population scaling. Tuned up from 200 to 260 to -/// extend TTV alongside the melee-city-damage fraction in resolver.rs. The -/// combination (HP boost + 0.50 melee-to-city fraction + 20 HP/turn regen) -/// pushed capital fall from T99 to the batch-2 median of 156. Further bumps -/// (280, 300) regressed results — 260 is the empirical peak. -pub const BASE_CITY_HP: u32 = 260; +/// Base city HP before population scaling. Bumped 260 → 500 for p1-29 R5a: +/// prior small bumps (280, 300) regressed because at low HP the snowballer's +/// stack still one-shots; the handoff calls for a step large enough that +/// capture takes 5-10 turns of siege rather than 1-2. Composed with the +/// stronger wall penalty in mc-combat::siege (tier1 0.40, tier2 0.25). +pub const BASE_CITY_HP: u32 = 500; /// HP gained per population point. pub const HP_PER_POP: u32 = 10; @@ -1021,7 +1021,7 @@ mod tests { #[test] fn defense_mechanics() { let mut city = City::found("Ironhold", (5, 5), true, 1, None); - let initial_hp = BASE_CITY_HP + HP_PER_POP; // 210 at pop 1 + let initial_hp = BASE_CITY_HP + HP_PER_POP; assert_eq!(city.hp, initial_hp); city.take_damage(50); assert_eq!(city.hp, initial_hp - 50);