diff --git a/TODO.md b/TODO.md index 70dd8a7..35d0e8c 100644 --- a/TODO.md +++ b/TODO.md @@ -51,12 +51,12 @@ screen-design judge before any model/texture changes. No gameplay rules change. ### Screen and terminology inventory -- [ ] Inventory every screen/panel: start menu, venue menu, tutorial, HUD, pause, +- [x] Inventory every screen/panel: start menu, venue menu, tutorial, HUD, pause, settings, Help, inspection, wand, radio/emergency, wheel, shift review, - timeline and campaign/continue screens. -- [ ] Record the canonical terms for admit/deny, allow/refuse, warning/blocking, - assistance/emergency, body camera, shift/review and campaign; remove synonyms - that mean the same action. + timeline and campaign/continue screens. Recorded in `docs/ui-copy.md`. +- [x] Record the canonical terms for admit/refuse, warning/blocking, + assistance/emergency, body camera, shift review and campaign; the current + inspection/wand/radio/review labels use them (see `docs/ui-copy.md`). - [ ] Audit all button labels for verb-first wording, capitalization, ordering, destructive-action confirmation and consistent confirm/cancel placement. - [ ] List every hardcoded player-facing string and route it through @@ -231,7 +231,40 @@ Compatibility/Web parity, deterministic assets and offline CI. and skyline; document accepted trade-offs. - [ ] Update asset docs and the changelog/status with the promoted texture versions. -## Patch 0.9.5 — Integration, performance and judge gate +## Patch 0.9.5 — Map Optimization + +Goal: streamline the maps, refactor geometry to match the images in `docs/screens/concepts`. Only two maps are needed for the major version: `Hollywood Boulevard` and `Joke Shop`. + +### Map 1 — Hollywood Boulevard + +- [ ] Audit and optimize geometry for the Hollywood Boulevard map. +- [ ] Reseach geometry for the real Hollywood Boulevard location "6840 Hollywood Blvd, Hollywood, CA 90028, United States" and create an accurate representation of the building, neighboring structures and streets, building facades, buildings across the street and other relevant elements on the map. +- [ ] Research current imagery and references for Hollywood Boulevard to ensure the map reflects the real-world location accurately. +- [ ] Generate more accurate images using the python AI tools for reference and alignment with the real-world location, save to `docs/screens/concepts/hollywood_boulevard/`. +- [ ] Verify alignment with other `docs/screens/concepts` images of the Hollywood Boulevard map. +- [ ] Remove unnecessary or hidden geometry to improve performance. +- [ ] Ensure texture and material consistency across the map. + +### Map 2 — Joke Shop + +- [ ] Audit and optimize geometry for the Joke Shop map. +- [ ] Research geometry for the real Joke Shop location "8433 Sunset Blvd, West Hollywood, CA 90069, United States" and create an accurate representation of the building, neighboring structures and streets, building facades, buildings across the street and other relevant elements on the map. +- [ ] Research current imagery and references for the Joke Shop to ensure the map reflects the real-world location accurately. +- [ ] Generate more accurate images using the python AI tools for reference and alignment with the real-world location, save to `docs/screens/concepts/joke_shop/`. +- [ ] Verify alignment with other `docs/screens/concepts` images of the Joke Shop. +- [ ] Remove unnecessary or hidden geometry to improve performance. +- [ ] Ensure texture and material consistency across the map. + +### Scenery Change (Day/Night) for Hollywood Boulevard + +- [ ] Capture reference images for Hollywood Boulevard during the day and night. +- [ ] Adjust lighting and environmental settings to match the day/night cycle. +- [ ] Verify that all textures and materials respond correctly to the lighting changes. +- [ ] Ensure that any dynamic elements (e.g., streetlights, signs) behave appropriately for the time of day. +- [ ] Test performance and visual consistency for both day and night scenarios. +- [ ] Offer the day map and the night map as distinct scenarios in the game menu when selecting a location. + +## Patch 0.9.6 — Integration, performance and judge gate Goal: integrate the UI/model/texture patches, prove the combined build on the target paths and leave a clean release-candidate handoff. diff --git a/content/strings.en.json b/content/strings.en.json index f288e60..dea0d5a 100644 --- a/content/strings.en.json +++ b/content/strings.en.json @@ -100,5 +100,13 @@ "tutorial.radio": "Open the assistance radio and submit a short report.", "tutorial.review": "Finish the shift and review what happened.", "tutorial.completed": "Tutorial complete.", + "ui.inspect_actions": "A = admit · D = refuse entry", + "ui.wand_actions": "A = admit · D = refuse entry", + "ui.radio_send_assist": "Send request", + "ui.radio_send_emergency": "Send emergency", + "ui.radio_hold_hint": "Hold the button for %.1fs", + "ui.radio_cancelled": "Call cancelled — hold the button.", + "ui.radio_holding": "Holding… %.0f%%", + "ui.review_return_menu": "Return to menu", "tutorial.skipped": "Tutorial skipped." } diff --git a/docs/README.md b/docs/README.md index d56c798..c1e30a0 100644 --- a/docs/README.md +++ b/docs/README.md @@ -12,6 +12,7 @@ This folder holds the project documentation, visual references and generated QA - [`asset-tooling.md`](asset-tooling.md) — image/model pipelines and screenshot gates - [`development-status.md`](development-status.md) — implemented features and current gaps - [`smoke-checklist.md`](smoke-checklist.md) — manual verification +- [`ui-copy.md`](ui-copy.md) — screen, copy and button inventory - [`RELEASING.md`](RELEASING.md) — export, CI and publishing workflow - [`adr/README.md`](adr/README.md) — architecture decisions diff --git a/docs/ui-copy.md b/docs/ui-copy.md new file mode 100644 index 0000000..7b66098 --- /dev/null +++ b/docs/ui-copy.md @@ -0,0 +1,46 @@ +# UI copy and button inventory + +Status: audit in progress for the 0.9.2 UI polish patch. + +## Screen inventory + +| Screen / panel | Owner | Primary actions | Notes | +| --- | --- | --- | --- | +| Start / venue menu | `start_menu.gd` | Continue shift, choose venue, Help, Settings, Quit | Campaign status and free-play venues share this screen. | +| Tutorial card | `tutorial_overlay.gd` | F1 skip | Non-blocking; no mouse capture. | +| HUD | `hud.gd` | Observe, target, inspect, wheel, radio, flashlight, body camera, door, pause | No interactive controls; must stay mouse-transparent. | +| Action wheel | `action_radial.gd` | Choose de-escalation/access/radio action | Confirm with Space/click; cancel with Esc/RMB. | +| Access inspection | `hud.gd` | A = admit, D = refuse | Real access evidence cards. | +| Wand screening | `hud.gd` | A = admit, D = refuse | Shows alert and carried items. | +| Radio / emergency | `radio_panel.gd` | Send request / hold Send emergency, Cancel | Normal click vs emergency hold. | +| Pause | `pause_overlay.gd` | Resume, restart, Settings, quit to menu | Esc resumes. | +| Settings | `settings_panel.gd` | Apply, Cancel, Replay tutorial, Reset campaign, rebind controls | Destructive reset asks for confirmation. | +| Help | `help_overlay.gd` | Filter controls, Close | Policy card and current bindings. | +| Shift review | `shift_review.gd` | Continue campaign, timeline, return to menu, quit | Campaign next step is shown here. | +| Timeline | `event_timeline.gd` | Previous, Next, Close | Review evidence stepper. | + +## Canonical terms + +- **Admit / refuse** — access decisions. Do not alternate with “allow / deny” or “grant / reject” in player-facing controls. +- **Warning** — Level 2. +- **Blocking** — Level 3 positioning; do not call it “force”. +- **Assistance** — Level 4 radio call; **emergency** is Level 5. +- **Body camera** — always two words. +- **Shift review** — the end-of-shift screen; “review” alone is acceptable in prose. +- **Continue campaign** — advance to the next venue. +- **Return to menu** — leave the review to the venue menu (it does not start a new shift by itself). +- **Send request** — non-emergency assistance; **Send emergency** — emergency call. + +## Button/label issues found + +- HUD inspection and wand used “allow/deny” versus “admit/refuse”; both now use **A = admit · D = refuse entry**. +- Shift review’s old “Run another shift” actually returned to the menu; renamed **Return to menu**. +- Radio emergency action used all-caps while assistance used sentence case; both are now sentence case, with the warning in the panel title/hold hint. +- Normal radio send was previously wired only to the emergency hold handlers; fixed in 0.8.1 and covered by `test_radio_panel.gd`. + +## Remaining audit work + +- Inventory hardcoded player-facing strings screen by screen and move them to `content/strings.en.json`. +- Verify focus/hover/pressed/disabled states with keyboard, gamepad and mouse. +- Test long strings and 1.75x HUD font scale. +- Capture every dialog/button state and run `screen_designs.py compare` plus the pinned judge. diff --git a/src/game/ui/hud.gd b/src/game/ui/hud.gd index a89567d..fd52c62 100644 --- a/src/game/ui/hud.gd +++ b/src/game/ui/hud.gd @@ -299,7 +299,7 @@ func _init() -> void: inspect_meta.modulate = Color(0.8, 0.85, 1.0) ivbox.add_child(inspect_meta) var insp_hint := Label.new() - insp_hint.text = "A = allow entry D = deny entry" + insp_hint.text = Strings.lookup("ui.inspect_actions") insp_hint.add_theme_font_size_override("font_size", 12) insp_hint.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER ivbox.add_child(insp_hint) @@ -343,7 +343,7 @@ func _init() -> void: wand_meta.modulate = Color(0.8, 0.85, 1.0) wvbox.add_child(wand_meta) var wand_hint := Label.new() - wand_hint.text = "A = admit D = refuse entry" + wand_hint.text = Strings.lookup("ui.wand_actions") wand_hint.add_theme_font_size_override("font_size", 12) wvbox.add_child(wand_hint) wand_center.add_child(wand_panel) diff --git a/src/game/ui/radio_panel.gd b/src/game/ui/radio_panel.gd index faa0aaa..fd54e98 100644 --- a/src/game/ui/radio_panel.gd +++ b/src/game/ui/radio_panel.gd @@ -8,6 +8,7 @@ signal submitted(report: Dictionary, emergency: bool) signal cancelled() const Rules := preload("res://src/core/rules.gd") +const Strings := preload("res://src/core/strings.gd") const UiArt := preload("res://src/game/ui/art.gd") var panel: PanelContainer @@ -102,7 +103,7 @@ func _init() -> void: var buttons := HBoxContainer.new() vbox.add_child(buttons) action_button = Button.new() - action_button.text = "Send request" + action_button.text = Strings.lookup("ui.radio_send_assist") action_button.button_down.connect(func(): _start_hold()) action_button.button_up.connect(func(): _stop_hold(false)) action_button.pressed.connect(_on_action_pressed) @@ -138,9 +139,9 @@ func open(controller: Object, emergency: bool, truth: Dictionary) -> void: title.text = "EMERGENCY RADIO" if emergency else "RADIO DISPATCH" weapons_check.button_pressed = truth.get("weapons_seen", false) danger_option.select(truth.get("danger_level", 1)) - hold_hint.text = "Hold the button for %.1fs" % HOLD_NEEDED if emergency else "" + hold_hint.text = Strings.fmt("ui.radio_hold_hint", [HOLD_NEEDED]) if emergency else "" status_label.text = "" - action_button.text = "SEND EMERGENCY" if emergency else "Send request" + action_button.text = Strings.lookup("ui.radio_send_emergency") if emergency else Strings.lookup("ui.radio_send_assist") _holding = false _hold_time = 0.0 visible = true @@ -161,14 +162,14 @@ func _stop_hold(cancelled_early: bool) -> void: if not cancelled_early and _hold_time >= HOLD_NEEDED: _submit() else: - status_label.text = "Call cancelled - must hold the button." + status_label.text = Strings.lookup("ui.radio_cancelled") func _process(delta: float) -> void: if not visible: return if _holding: _hold_time += delta - status_label.text = "Holding... %.0f%%" % (minf(1.0, _hold_time / HOLD_NEEDED) * 100.0) + status_label.text = Strings.fmt("ui.radio_holding", [minf(1.0, _hold_time / HOLD_NEEDED) * 100.0]) if _hold_time >= HOLD_NEEDED: var was := _holding _holding = false diff --git a/src/game/ui/shift_review.gd b/src/game/ui/shift_review.gd index 6467d69..6babb57 100644 --- a/src/game/ui/shift_review.gd +++ b/src/game/ui/shift_review.gd @@ -68,7 +68,7 @@ func _init() -> void: center.add_child(timeline) var restart := Button.new() - restart.text = "Run another shift" + restart.text = Strings.lookup("ui.review_return_menu") restart.pressed.connect(func(): restart_requested.emit()) restart.size_flags_horizontal = Control.SIZE_SHRINK_CENTER center.add_child(restart)