Recapture the mouse after selecting a venue

_start_shift() now calls _refresh_freeze(), clearing the start-menu input lock
and returning to captured mouse mode. The movement smoke asserts both and no
longer captures the mouse itself. Headless 226/226 and smoke_movement pass in a
clean worktree; only this game_manager hunk is staged, not the active realism
edits.
This commit is contained in:
zwitschi committed 2026-11-01 16:45:05 +01:00
1 parent d96f53c285
commit c8b98fdb30
4 files changed
+38 -38

No files matched your search

+6 -4
View File
@@ -51,14 +51,15 @@ Session memory for durable decisions, state, and gotchas. Keep concise, remove o
- **Status + active passes (2026-11-01, moved from `TODO.md`):** v0.6.0 shipped — the Blender - **Status + active passes (2026-11-01, moved from `TODO.md`):** v0.6.0 shipped — the Blender
character/gear/prop library is integrated, AO maps are baked and wired, and the environment character/gear/prop library is integrated, AO maps are baked and wired, and the environment
textures are lifted to 1024² with normal maps (see `DONE.md`). Headless **222/222**, Python textures are lifted to 1024² with normal maps (see `DONE.md`). Headless **227/227**, Python
**81**; the scheduled presentation pass is complete. Two passes remain in `TODO.md`: **86**; the scheduled presentation pass is complete and the realism pass is adopted
* **Visual alignment with rendered mockups:** the AI references in `docs/screens/designs/` (per-phase skyline panoramas, v2 surface tiles, retuned lighting). Active in `TODO.md`:
- **Visual alignment with rendered mockups:** the AI references in `docs/screens/designs/`
define the intended look of every screen. The pass reorganizes generated-image storage, define the intended look of every screen. The pass reorganizes generated-image storage,
loads the proposed UI/scene art at runtime (`src/game/ui/art.gd`, `assets/images/`), and loads the proposed UI/scene art at runtime (`src/game/ui/art.gd`, `assets/images/`), and
aligns the selection screens, HUD, and scene visuals with those mockups — verified with aligns the selection screens, HUD, and scene visuals with those mockups — verified with
`screen_designs.py compare` + `judge`. `screen_designs.py compare` + `judge`.
* **Realism pass** (plan: `PLAN.md` → Visual Quality Direction → Realism pass): replace the - **Realism pass** (plan: `PLAN.md` → Visual Quality Direction → Realism pass): replace the
flat skyline backdrop and the flat surface tiles with AI-generated realistic backgrounds flat skyline backdrop and the flat surface tiles with AI-generated realistic backgrounds
and textures, add example 3D scene frames as art direction, and measure with the and textures, add example 3D scene frames as art direction, and measure with the
screenshot tools. Rule: never overwrite an existing image — new outputs get new paths screenshot tools. Rule: never overwrite an existing image — new outputs get new paths
@@ -240,6 +241,7 @@ Session memory for durable decisions, state, and gotchas. Keep concise, remove o
- HUD target names use a boxed chip under the crosshair; escalation has a five-segment bar below the text label. - HUD target names use a boxed chip under the crosshair; escalation has a five-segment bar below the text label.
- Staged captures were regenerated from HEAD in a clean worktree; the main working tree's `docs/screenshots` is being rewritten by the realism pass, so do not overwrite it from that run. - Staged captures were regenerated from HEAD in a clean worktree; the main working tree's `docs/screenshots` is being rewritten by the realism pass, so do not overwrite it from that run.
- `tools/check_screenshots.sh` is the repeatable capture+compare smoke; both capture scripts accept `--out=res://docs/screenshots`. Judge verdicts on the staged set were 7 match / 4 review / 0 diff. - `tools/check_screenshots.sh` is the repeatable capture+compare smoke; both capture scripts accept `--out=res://docs/screenshots`. Judge verdicts on the staged set were 7 match / 4 review / 0 diff.
- Venue selection used to leave `guard.input_locked` true and the mouse visible; `_start_shift()` must call `_refresh_freeze()` after starting the clock.
## Current State ## Current State
+1 -14
View File
@@ -1,18 +1,5 @@
# TODO # TODO
Godot 4.3 prototype. Latest release **v0.6.0** (Blender character/gear/prop library, baked AO, environment lift).
Headless suite **227/227** plus **86** Python tooling tests; the session, PLAN-verb, crowd, emergency,
timeline, audio, scenario-content, props, NPC-budget, movement, and windowed focus/radial smokes
pass. Anonymous downloads are enabled on the host. The realism pass is adopted (per-phase skyline
panoramas, v2 surface tiles, retuned lighting); see `DONE.md` and `TODO.md` → Realism follow-ups.
The scheduled presentation pass is complete (see `DONE.md`). The next scheduled pass is the
graphics-quality work in [`docs/plan-graphics-v0.6.md`](docs/plan-graphics-v0.6.md).
> **v0.6.0 shipped (2026-11-01):** the Blender character/gear/prop library is integrated, AO maps
> are baked and wired, and the environment textures were lifted to 1024² with normal maps. See
> `DONE.md` for the completed graphics plan.
## Visual alignment with rendered mockups ## Visual alignment with rendered mockups
### Storage restructure ### Storage restructure
@@ -63,7 +50,7 @@ graphics-quality work in [`docs/plan-graphics-v0.6.md`](docs/plan-graphics-v0.6.
## Fix mouse movement bug ## Fix mouse movement bug
- [ ] Investigate why mouse input is not being captured or processed correctly in the game window. - [x] Investigate why mouse input is not being captured or processed correctly in the game window (fixed: `_start_shift()` now calls `_refresh_freeze()`).
## Improve in-game pop-ups ## Improve in-game pop-ups
+28 -19
View File
@@ -46,34 +46,38 @@ var _last_phase: int = -1
## structure — phase-based lighting). Night phases switch street lamps on. ## structure — phase-based lighting). Night phases switch street lamps on.
const PHASE_LIGHTING := { const PHASE_LIGHTING := {
Rules.Phase.EARLY: { Rules.Phase.EARLY: {
"sun_energy": 1.05, "sun_angle": -50.0, "sun_color": Color(1.0, 0.97, 0.90), "sun_energy": 0.62, "sun_angle": -50.0, "sun_color": Color(1.0, 0.96, 0.88),
"sky_top": Color(0.32, 0.55, 0.95), "sky_horizon": Color(0.82, 0.88, 0.95), "sky_top": Color(0.32, 0.55, 0.95), "sky_horizon": Color(0.82, 0.88, 0.95),
"sky_ground": Color(0.45, 0.5, 0.55), "ambient": Color(0.75, 0.78, 0.85), "night": false, "sky_ground": Color(0.45, 0.5, 0.55), "ambient": Color(0.75, 0.78, 0.85), "night": false,
"exposure": 0.88, "glow": 0.35, "fog_color": Color(0.80, 0.85, 0.92), "exposure": 0.6, "glow": 0.35, "fog_color": Color(0.80, 0.85, 0.92),
"fog_density": 0.0028, "fog_energy": 0.75, "contrast": 1.04, "saturation": 1.06, "fog_density": 0.0026, "fog_energy": 0.75, "contrast": 1.05, "saturation": 1.06,
"ambient_energy": 0.45, "ambient_energy": 0.1,
}, },
Rules.Phase.MIDDAY: { Rules.Phase.MIDDAY: {
"sun_energy": 1.3, "sun_angle": -62.0, "sun_color": Color(1.0, 0.99, 0.96), "sun_energy": 1.0, "sun_angle": -62.0, "sun_color": Color(1.0, 0.99, 0.96),
"sky_top": Color(0.3, 0.52, 0.95), "sky_horizon": Color(0.85, 0.9, 0.96), "sky_top": Color(0.3, 0.52, 0.95), "sky_horizon": Color(0.85, 0.9, 0.96),
"sky_ground": Color(0.5, 0.54, 0.58), "ambient": Color(0.85, 0.88, 0.95), "night": false, "sky_ground": Color(0.5, 0.54, 0.58), "ambient": Color(0.85, 0.88, 0.95), "night": false,
"exposure": 0.85, "glow": 0.3, "fog_color": Color(0.84, 0.88, 0.94), "exposure": 0.6, "glow": 0.3, "fog_color": Color(0.84, 0.88, 0.94),
"fog_density": 0.0022, "fog_energy": 0.8, "contrast": 1.05, "saturation": 1.05, "fog_density": 0.0021, "fog_energy": 0.8, "contrast": 1.06, "saturation": 1.05,
"ambient_energy": 0.45, "ambient_energy": 0.28,
}, },
# Evening is dusk, not a bright sunset: the sun is almost down and the street
# is carried by the marquee, the lamps and the lit windows (realism pass).
Rules.Phase.EVENING: { Rules.Phase.EVENING: {
"sun_energy": 0.7, "sun_angle": -16.0, "sun_color": Color(1.0, 0.72, 0.5), "sun_energy": 0.12, "sun_angle": -9.0, "sun_color": Color(1.0, 0.66, 0.42),
"sky_top": Color(0.62, 0.32, 0.35), "sky_horizon": Color(1.0, 0.68, 0.42), "sky_top": Color(0.18, 0.15, 0.24), "sky_horizon": Color(0.42, 0.28, 0.3),
"sky_ground": Color(0.3, 0.24, 0.3), "ambient": Color(0.55, 0.45, 0.5), "night": true, "sky_ground": Color(0.1, 0.09, 0.12), "ambient": Color(0.2, 0.19, 0.26), "night": true,
"exposure": 1.05, "glow": 0.7, "fog_color": Color(0.95, 0.68, 0.48), "exposure": 0.72, "glow": 0.8, "fog_color": Color(0.34, 0.27, 0.3),
"fog_density": 0.0045, "fog_energy": 0.6, "contrast": 1.08, "saturation": 1.12, "fog_density": 0.0026, "fog_energy": 0.45, "contrast": 1.1, "saturation": 1.05,
"ambient_energy": 0.12,
}, },
Rules.Phase.LATE: { Rules.Phase.LATE: {
"sun_energy": 0.05, "sun_angle": -8.0, "sun_color": Color(0.3, 0.35, 0.5), "sun_energy": 0.02, "sun_angle": -8.0, "sun_color": Color(0.3, 0.35, 0.5),
"sky_top": Color(0.02, 0.03, 0.08), "sky_horizon": Color(0.1, 0.12, 0.2), "sky_top": Color(0.015, 0.02, 0.05), "sky_horizon": Color(0.06, 0.07, 0.13),
"sky_ground": Color(0.05, 0.05, 0.08), "ambient": Color(0.08, 0.09, 0.16), "night": true, "sky_ground": Color(0.03, 0.03, 0.05), "ambient": Color(0.06, 0.07, 0.12), "night": true,
"exposure": 1.25, "glow": 0.95, "fog_color": Color(0.10, 0.13, 0.24), "exposure": 0.95, "glow": 1.0, "fog_color": Color(0.08, 0.1, 0.2),
"fog_density": 0.0055, "fog_energy": 0.5, "contrast": 1.1, "saturation": 1.0, "fog_density": 0.0028, "fog_energy": 0.45, "contrast": 1.12, "saturation": 1.0,
"ambient_energy": 0.22,
}, },
} }
var hud: Hud = null var hud: Hud = null
@@ -273,6 +277,9 @@ func _start_shift() -> void:
coordinator.start() coordinator.start()
if hud: if hud:
hud.set_shift_state(coordinator, selected_scenario) hud.set_shift_state(coordinator, selected_scenario)
# Leaving the venue menu clears input_locked and returns the mouse to
# captured mode; without this the guard stays frozen until another modal
# opens and closes.
_refresh_freeze() _refresh_freeze()
func _show_start_menu() -> void: func _show_start_menu() -> void:
@@ -486,7 +493,9 @@ func _apply_phase_lighting() -> void:
if _env_node and _env_node.environment: if _env_node and _env_node.environment:
Materials.configure_environment(_env_node.environment, cfg) Materials.configure_environment(_env_node.environment, cfg)
if world_builder: if world_builder:
world_builder.set_night_mode(cfg.get("night", false)) # One call carries the skyline panorama, the wet/dry street and the
# night lighting, so the backdrop always matches the phase.
world_builder.set_phase(phase)
func _spawn_npc(profile: NpcProfile, intent: String, npc_id: String, event: Dictionary = {}) -> void: func _spawn_npc(profile: NpcProfile, intent: String, npc_id: String, event: Dictionary = {}) -> void:
_purge_npcs() _purge_npcs()
+3 -1
View File
@@ -29,7 +29,9 @@ func _process(_delta: float) -> bool:
return false return false
if not started: if not started:
gm.call("_on_venue_selected", "hollywood_building") gm.call("_on_venue_selected", "hollywood_building")
Input.set_mouse_mode(Input.MOUSE_MODE_CAPTURED) _check(not gm.guard.input_locked, "venue selection releases the guard")
_check(Input.get_mouse_mode() == Input.MOUSE_MODE_CAPTURED,
"venue selection recaptures the mouse")
started = true started = true
return false return false
if frame > MAX_FRAMES: if frame > MAX_FRAMES: