diff --git a/.project/designs/design-tokens.json b/.project/designs/design-tokens.json index cd7548df..b9651cda 100644 --- a/.project/designs/design-tokens.json +++ b/.project/designs/design-tokens.json @@ -95,6 +95,68 @@ "$description": "Knowledge-tree — dimmed/requirement accent" } }, + "throne": { + "structure": { + "$value": "#4d3824", + "$type": "color", + "$description": "Throne-room placeholder — structure (background/walls/ceiling/floor)" + }, + "seat": { + "$value": "#8c6b1a", + "$type": "color", + "$description": "Throne-room placeholder — throne + backdrop" + }, + "forge": { + "$value": "#804714", + "$type": "color", + "$description": "Throne-room placeholder — forge display / armory" + }, + "trophy": { + "$value": "#802e1a", + "$type": "color", + "$description": "Throne-room placeholder — trophy wall / honor display" + }, + "shrine": { + "$value": "#334766", + "$type": "color", + "$description": "Throne-room placeholder — shrine / ancestor monument" + }, + "provisions": { + "$value": "#4d6626", + "$type": "color", + "$description": "Throne-room placeholder — brewery / gemstone vault" + }, + "mapTable": { + "$value": "#264d59", + "$type": "color", + "$description": "Throne-room placeholder — map table" + }, + "garden": { + "$value": "#1f522e", + "$type": "color", + "$description": "Throne-room placeholder — garden" + }, + "court": { + "$value": "#665947", + "$type": "color", + "$description": "Throne-room placeholder — court" + }, + "pedestal": { + "$value": "#8c7a33", + "$type": "color", + "$description": "Throne-room placeholder — wonder pedestal" + }, + "special": { + "$value": "#73528c", + "$type": "color", + "$description": "Throne-room placeholder — special decorations" + }, + "default": { + "$value": "#40382e", + "$type": "color", + "$description": "Throne-room placeholder — unmapped layer fallback" + } + }, "background": { "deepest": { "$value": "#171219", diff --git a/.project/objectives/p2-74-ui-dehardcode-to-tokens.md b/.project/objectives/p2-74-ui-dehardcode-to-tokens.md index 2ad84c3d..ffbc998f 100644 --- a/.project/objectives/p2-74-ui-dehardcode-to-tokens.md +++ b/.project/objectives/p2-74-ui-dehardcode-to-tokens.md @@ -87,13 +87,24 @@ always-green. Order by player visibility: HUD/world-map → city → combat → — only `engine/src/` + test dirs are). **Apricot visual proof pending** (no godot import on plum); visual-regression risk ≈0 since state/badge hexes are byte-preserved. +- **Cluster 4** (throne room) — landed. `scenes/menus/throne_room.gd` fully + tokenized: 12 inline `Color()` (the `_layer_to_color` placeholder palette) → 0. + Added `color.throne.*` (12 decoration-category placeholder colours) to + design-tokens.json with exact-hex equivalents (zero visual change); theme + regenerated (`--check` clean). Refactored `_layer_to_color` from a 13-return + if-chain to a const `LAYER_COLOR_TOKENS` dict + 2 returns (DRY; also cleared a + pre-existing `max-returns` gdlint warning). gdlint now **fully clean** on the + file. Verified on plum: JSON valid, theme `--check` clean, all 13 token refs + resolve, 0 `Color()` remain. Apricot visual proof pending (placeholders only + render when a decoration sprite is missing; demo ships copyleft sprites). - **Remaining**: minimap (`scenes/hud/minimap.*`) is **already compliant** — its 23 `Color()` are the documented `TERRAIN_COLORS` game-content exception (Rail-2 follow-up, OOS for this visual pass) + token-seeded `_ready()` fallbacks; `world_map_hud.*` / `weather_visualizer.*` / `encyclopedia_panel.*` already 0. - Genuinely-remaining convertibles: `menus/throne_room.gd` (12), - `world_map/courier_route_overlay.gd` (5), `world_map/arena_playback.gd` (4), - `ui/lens_switcher.gd` (4), `ui/ingame_menu.gd` (4), plus single-literal stragglers. + Genuinely-remaining convertibles: `world_map/courier_route_overlay.gd` (5), + `world_map/arena_playback.gd` (4), `ui/lens_switcher.gd` (4), + `ui/ingame_menu.gd` (4), plus single-literal stragglers + (`world_map_units.gd`, `world_map.gd`, `tile_info_panel.gd`, `arena_overlay.gd`). Precursor scenes `overviews/demographics.gd` (10) / `end_game_stats.gd` (6) / `victory_screen.gd` (2) are Commandment-9 deletion candidates (p2-47/p2-48) — skip tokenizing doomed files. diff --git a/public/games/age-of-dwarves/ui_theme.tres b/public/games/age-of-dwarves/ui_theme.tres index 086c1577..a1925f53 100644 --- a/public/games/age-of-dwarves/ui_theme.tres +++ b/public/games/age-of-dwarves/ui_theme.tres @@ -102,7 +102,7 @@ corner_radius_bottom_left = 2 corner_radius_bottom_right = 2 [resource] -metadata/tokens = "{\"accent.gold\":\"d9a020\",\"accent.goldBright\":\"d9b33f\",\"accent.goldPress\":\"ffd14d\",\"accent.goldResource\":\"f2d133\",\"accent.ping\":\"ffd973\",\"accent.sage\":\"66b866\",\"accent.science\":\"66bfff\",\"background.base\":\"1a1410\",\"background.deepest\":\"171219\",\"background.happiness\":\"0f0d07\",\"background.hud\":\"00000099\",\"background.list\":\"120e1e\",\"background.listSelected\":\"3f2d0d\",\"background.menu\":\"0e0a17\",\"background.overlay\":\"0000009e\",\"background.panel\":\"17121e\",\"background.raised\":\"2a2018\",\"background.surface\":\"221a14\",\"border.divider\":\"99731f80\",\"border.focus\":\"d9b340ff\",\"border.happiness\":\"b39940d9\",\"border.list\":\"4d4014b2\",\"border.listSelected\":\"d9b340cc\",\"border.panel\":\"73591fcc\",\"button.bgHover\":\"331a0d\",\"button.bgNormal\":\"1f1733\",\"button.bgPressed\":\"472f0f\",\"climate.cold\":\"1a4dff\",\"climate.hot\":\"ff260d\",\"climate.textCold\":\"66b3ff\",\"climate.textNeutral\":\"d9e0d9\",\"climate.textWarming\":\"ff731a\",\"climate.warm\":\"26cc40\",\"fog.explored\":\"000000b2\",\"fog.unexplored\":\"1a160fff\",\"guide.bgPrimary\":\"1a1410\",\"guide.bgSecondary\":\"221a14\",\"guide.bgTertiary\":\"2a2018\",\"guide.dwarfAccent\":\"8b6a1a\",\"guide.dwarfPrimary\":\"c07040\",\"guide.dwarfPrimaryDark\":\"8a4a28\",\"guide.dwarfPrimaryLight\":\"e09868\",\"guide.textMuted\":\"7a6048\",\"guide.textPrimary\":\"f0e4d0\",\"guide.textSecondary\":\"b8a078\",\"player.blue\":\"3366ff\",\"player.brown\":\"806659\",\"player.cyan\":\"1accd9\",\"player.gray\":\"999999\",\"player.green\":\"33cc4d\",\"player.magenta\":\"cc4d80\",\"player.navy\":\"4d4d99\",\"player.orange\":\"e6801a\",\"player.purple\":\"b24de6\",\"player.red\":\"e63333\",\"player.sage\":\"66b366\",\"player.yellow\":\"e6cc1a\",\"semantic.diplomacy\":\"e68c73\",\"semantic.goldenAge\":\"ffeb66\",\"semantic.negative\":\"d95940\",\"semantic.positive\":\"66e666\",\"semantic.trade\":\"ccbf73\",\"semantic.warning\":\"e69933\",\"tech.availableBg\":\"d9bf1ae6\",\"tech.availableBorder\":\"ffe64d\",\"tech.currentBg\":\"4d80e6e6\",\"tech.lockedBg\":\"666666b3\",\"tech.lockedBorder\":\"808080\",\"tech.researchedBg\":\"33b333e6\",\"tech.researchedBorder\":\"4de64d\",\"tech.selectedBorder\":\"ffffffff\",\"text.button\":\"e0d199\",\"text.buttonHover\":\"ffeb80\",\"text.buttonPressed\":\"ffffb3\",\"text.disabled\":\"80806680\",\"text.muted\":\"b2b2b2\",\"text.primary\":\"e0d8c8\",\"text.secondary\":\"bfb7a6\",\"text.title\":\"f2d973\",\"unlockAccent.building\":\"8b6914\",\"unlockAccent.dim\":\"ffffff8c\",\"unlockAccent.improvement\":\"4a7c3f\",\"unlockAccent.lens\":\"2d5a8b\",\"unlockAccent.mechanic\":\"6b3fa0\",\"unlockAccent.resource\":\"a0522d\",\"unlockAccent.unit\":\"c9a84c\",\"unlockAccent.wonder\":\"a06a3f\"}" +metadata/tokens = "{\"accent.gold\":\"d9a020\",\"accent.goldBright\":\"d9b33f\",\"accent.goldPress\":\"ffd14d\",\"accent.goldResource\":\"f2d133\",\"accent.ping\":\"ffd973\",\"accent.sage\":\"66b866\",\"accent.science\":\"66bfff\",\"background.base\":\"1a1410\",\"background.deepest\":\"171219\",\"background.happiness\":\"0f0d07\",\"background.hud\":\"00000099\",\"background.list\":\"120e1e\",\"background.listSelected\":\"3f2d0d\",\"background.menu\":\"0e0a17\",\"background.overlay\":\"0000009e\",\"background.panel\":\"17121e\",\"background.raised\":\"2a2018\",\"background.surface\":\"221a14\",\"border.divider\":\"99731f80\",\"border.focus\":\"d9b340ff\",\"border.happiness\":\"b39940d9\",\"border.list\":\"4d4014b2\",\"border.listSelected\":\"d9b340cc\",\"border.panel\":\"73591fcc\",\"button.bgHover\":\"331a0d\",\"button.bgNormal\":\"1f1733\",\"button.bgPressed\":\"472f0f\",\"climate.cold\":\"1a4dff\",\"climate.hot\":\"ff260d\",\"climate.textCold\":\"66b3ff\",\"climate.textNeutral\":\"d9e0d9\",\"climate.textWarming\":\"ff731a\",\"climate.warm\":\"26cc40\",\"fog.explored\":\"000000b2\",\"fog.unexplored\":\"1a160fff\",\"guide.bgPrimary\":\"1a1410\",\"guide.bgSecondary\":\"221a14\",\"guide.bgTertiary\":\"2a2018\",\"guide.dwarfAccent\":\"8b6a1a\",\"guide.dwarfPrimary\":\"c07040\",\"guide.dwarfPrimaryDark\":\"8a4a28\",\"guide.dwarfPrimaryLight\":\"e09868\",\"guide.textMuted\":\"7a6048\",\"guide.textPrimary\":\"f0e4d0\",\"guide.textSecondary\":\"b8a078\",\"player.blue\":\"3366ff\",\"player.brown\":\"806659\",\"player.cyan\":\"1accd9\",\"player.gray\":\"999999\",\"player.green\":\"33cc4d\",\"player.magenta\":\"cc4d80\",\"player.navy\":\"4d4d99\",\"player.orange\":\"e6801a\",\"player.purple\":\"b24de6\",\"player.red\":\"e63333\",\"player.sage\":\"66b366\",\"player.yellow\":\"e6cc1a\",\"semantic.diplomacy\":\"e68c73\",\"semantic.goldenAge\":\"ffeb66\",\"semantic.negative\":\"d95940\",\"semantic.positive\":\"66e666\",\"semantic.trade\":\"ccbf73\",\"semantic.warning\":\"e69933\",\"tech.availableBg\":\"d9bf1ae6\",\"tech.availableBorder\":\"ffe64d\",\"tech.currentBg\":\"4d80e6e6\",\"tech.lockedBg\":\"666666b3\",\"tech.lockedBorder\":\"808080\",\"tech.researchedBg\":\"33b333e6\",\"tech.researchedBorder\":\"4de64d\",\"tech.selectedBorder\":\"ffffffff\",\"text.button\":\"e0d199\",\"text.buttonHover\":\"ffeb80\",\"text.buttonPressed\":\"ffffb3\",\"text.disabled\":\"80806680\",\"text.muted\":\"b2b2b2\",\"text.primary\":\"e0d8c8\",\"text.secondary\":\"bfb7a6\",\"text.title\":\"f2d973\",\"throne.court\":\"665947\",\"throne.default\":\"40382e\",\"throne.forge\":\"804714\",\"throne.garden\":\"1f522e\",\"throne.mapTable\":\"264d59\",\"throne.pedestal\":\"8c7a33\",\"throne.provisions\":\"4d6626\",\"throne.seat\":\"8c6b1a\",\"throne.shrine\":\"334766\",\"throne.special\":\"73528c\",\"throne.structure\":\"4d3824\",\"throne.trophy\":\"802e1a\",\"unlockAccent.building\":\"8b6914\",\"unlockAccent.dim\":\"ffffff8c\",\"unlockAccent.improvement\":\"4a7c3f\",\"unlockAccent.lens\":\"2d5a8b\",\"unlockAccent.mechanic\":\"6b3fa0\",\"unlockAccent.resource\":\"a0522d\",\"unlockAccent.unit\":\"c9a84c\",\"unlockAccent.wonder\":\"a06a3f\"}" Button/colors/font_color = Color(0.878431, 0.819608, 0.6, 1) Button/colors/font_hover_color = Color(1, 0.921569, 0.501961, 1) Button/colors/font_pressed_color = Color(1, 1, 0.701961, 1) diff --git a/src/game/engine/scenes/menus/throne_room.gd b/src/game/engine/scenes/menus/throne_room.gd index 3a634186..5acc5e22 100644 --- a/src/game/engine/scenes/menus/throne_room.gd +++ b/src/game/engine/scenes/menus/throne_room.gd @@ -42,6 +42,30 @@ const DRAW_ORDER: Array = [ "brewery", "map_table", "garden", "court", ] +## Placeholder backdrop colour per decoration layer → design token name. +## Shown only when a decoration sprite is missing. `special_*` layers and any +## unmapped layer fall back to throne.special / throne.default respectively. +const LAYER_COLOR_TOKENS: Dictionary = { + "background": "throne.structure", + "walls": "throne.structure", + "ceiling": "throne.structure", + "floor": "throne.structure", + "throne": "throne.seat", + "throne_backdrop": "throne.seat", + "forge_display": "throne.forge", + "armory": "throne.forge", + "trophy_wall": "throne.trophy", + "honor_display": "throne.trophy", + "shrine": "throne.shrine", + "ancestor_monument": "throne.shrine", + "brewery": "throne.provisions", + "gemstone_vault": "throne.provisions", + "map_table": "throne.mapTable", + "garden": "throne.garden", + "court": "throne.court", + "pedestal": "throne.pedestal", +} + ## Set false when used as the main menu background (hides close button). var show_close: bool = true @@ -182,29 +206,9 @@ func _on_decoration_unhovered() -> void: func _layer_to_color(layer: String) -> Color: - if layer in ["background", "walls", "ceiling", "floor"]: - return Color(0.30, 0.22, 0.14) - if layer in ["throne", "throne_backdrop"]: - return Color(0.55, 0.42, 0.10) - if layer in ["forge_display", "armory"]: - return Color(0.50, 0.28, 0.08) - if layer in ["trophy_wall", "honor_display"]: - return Color(0.50, 0.18, 0.10) - if layer in ["shrine", "ancestor_monument"]: - return Color(0.20, 0.28, 0.40) - if layer in ["brewery", "gemstone_vault"]: - return Color(0.30, 0.40, 0.15) - if layer == "map_table": - return Color(0.15, 0.30, 0.35) - if layer == "garden": - return Color(0.12, 0.32, 0.18) - if layer == "court": - return Color(0.40, 0.35, 0.28) - if layer == "pedestal": - return Color(0.55, 0.48, 0.20) if layer.begins_with("special"): - return Color(0.45, 0.32, 0.55) - return Color(0.25, 0.22, 0.18) + return ThemeAssets.color("throne.special") + return ThemeAssets.color(LAYER_COLOR_TOKENS.get(layer, "throne.default")) func _on_close_pressed() -> void: