diff --git a/CHANGELOG.md b/CHANGELOG.md index f1dcb4d..49b358d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,8 @@ Semantic Versioning. ### Fixed - The red event banners are lit from the top down at night instead of reading as flat red cards. +- Hollywood and the TV Studio got the same queue treatment, and the TV Studio's props no longer sit + in the entrance steps. - The Joke Shop has a readable queue: a velvet rope line leading to the check-in podium, a thicker bike-rack barricade on the curb side, and a planter no longer clipping the palm foliage. - Street lamps now throw a warm pool on the pavement instead of dimly washing the whole walkway. diff --git a/MEMORY.md b/MEMORY.md index ed0d81e..9b3baaf 100644 --- a/MEMORY.md +++ b/MEMORY.md @@ -134,6 +134,10 @@ canonical implemented-features list in `docs/project/development-status.md`. multiplier into every `_marquee_emissive` entry, which flattens any gradient. It now reads `mat.get_meta("night_energy", 2.0)`, so a multi-strip panel can keep its top-to-bottom ratio (the event banners: 2.6 → 1.4). +- **`placement_problems()` was only gated for the Joke Shop.** Its test validated one venue's prop + list, so the TV Studio carried six violations (props inside the steps/door exclusion and off the + sidewalk) unnoticed. `test_every_venue_placement_clears_the_sidewalk_and_the_approach` now runs the + validator on all three venues. When adding a venue or a prop, that test is the gate. - **Venue lights must keep `omni_attenuation == 1.0`** — `test_world.test_venue_lights_use_physical_falloff` enforces physical falloff on every Omni/Spot in all three venues, so a "pool" cannot come from sharpening the curve. Use `omni_range` + energy instead: 10 m / energy 8 gives a brighter pool and diff --git a/TODO.md b/TODO.md index 07c38f7..98189a9 100644 --- a/TODO.md +++ b/TODO.md @@ -980,7 +980,12 @@ scorecard source, this milestone is the actionable list. 18 → 22 mm; the old sizes read as wire at 8 m. - [x] **West palm / planter overlap.** The planter box sat under the west palm canopy (palm spans x −15.0…−11.0 there) and the foliage cards clipped its lip; it moved 1.6 m clear. -- [ ] The same queue/set-dressing review for Hollywood and the TV Studio. +- [x] **Hollywood and TV Studio review.** Hollywood: the lone stanchion and single barricade became + a three-post rope line into the check-in podium plus a curb barricade. TV Studio: **six + placement violations** surfaced once the validator was applied to it — three props sat inside + the steps/door exclusion and off the sidewalk at z 4.2–4.4; re-placed into a rope line + + podium + two barricades. `test_every_venue_placement_clears_the_sidewalk_and_the_approach` + now runs the validator on all three venues, so this cannot regress. - [ ] Sidewalk light pool at the Joke Shop: the entrance walkway measures 20.7/255 against 3.0 on the side pavement, so a pool exists but only at the door; the queue area itself is unlit. - [ ] Build one real-photo comparison for street furniture and record the accepted mismatches. diff --git a/docs/assets/3d-model-review.md b/docs/assets/3d-model-review.md index b31093f..5703bc7 100644 --- a/docs/assets/3d-model-review.md +++ b/docs/assets/3d-model-review.md @@ -365,6 +365,17 @@ Readability at 8 m drove the thickness pass: bike-rack frame 22 → 28 mm, bars Measured at night afterwards: the entrance walkway sits at 20.7/255 against 3.0 on the side pavement, so the door pool exists; the queue area itself is still unlit and stays queued as a follow-up. +### Hollywood and the TV Studio + +Hollywood had one stanchion and one barricade, which read as stray street furniture; it now has the +same three-post rope line into the check-in podium, with a barricade on the curb. + +The TV Studio had **never been validated**: `placement_problems()` was only applied to the Joke Shop +in its test, and running it on the studio reported six violations — three props at z 4.2–4.4 sat +inside the steps/door exclusion and outside the sidewalk bounds. They are re-placed as a rope line, +podium and two curb barricades, and `test_every_venue_placement_clears_the_sidewalk_and_the_approach` +now validates all three venues so the gap cannot reopen. + ## Scorecard skeleton Verdicts use `qa-review` semantics: **P0** (blocker: wrong scale, broken normals, budget fail), diff --git a/docs/screenshots/01-venue-overview.png b/docs/screenshots/01-venue-overview.png index dc51dbd..ce8dc80 100644 Binary files a/docs/screenshots/01-venue-overview.png and b/docs/screenshots/01-venue-overview.png differ diff --git a/docs/screenshots/02-targeting-npc.png b/docs/screenshots/02-targeting-npc.png index 52c65ef..f8495ee 100644 Binary files a/docs/screenshots/02-targeting-npc.png and b/docs/screenshots/02-targeting-npc.png differ diff --git a/docs/screenshots/05-late-night-avenue.png b/docs/screenshots/05-late-night-avenue.png index 435062d..25f1f85 100644 Binary files a/docs/screenshots/05-late-night-avenue.png and b/docs/screenshots/05-late-night-avenue.png differ diff --git a/docs/screenshots/06-night-flashlight.png b/docs/screenshots/06-night-flashlight.png index 48200df..ab45a14 100644 Binary files a/docs/screenshots/06-night-flashlight.png and b/docs/screenshots/06-night-flashlight.png differ diff --git a/docs/screenshots/08-escalation-hud.png b/docs/screenshots/08-escalation-hud.png index a7498b5..14d0939 100644 Binary files a/docs/screenshots/08-escalation-hud.png and b/docs/screenshots/08-escalation-hud.png differ diff --git a/docs/screenshots/09-body-camera-timeline.png b/docs/screenshots/09-body-camera-timeline.png index c2713ed..aaeb562 100644 Binary files a/docs/screenshots/09-body-camera-timeline.png and b/docs/screenshots/09-body-camera-timeline.png differ diff --git a/docs/screenshots/11-precision-walk.png b/docs/screenshots/11-precision-walk.png index 91f8824..ff88d5d 100644 Binary files a/docs/screenshots/11-precision-walk.png and b/docs/screenshots/11-precision-walk.png differ diff --git a/docs/screenshots/13-studio-arrival.png b/docs/screenshots/13-studio-arrival.png index 94175ca..0ca36c6 100644 Binary files a/docs/screenshots/13-studio-arrival.png and b/docs/screenshots/13-studio-arrival.png differ diff --git a/docs/screenshots/17-shift-review.png b/docs/screenshots/17-shift-review.png index d5b8436..28520ef 100644 Binary files a/docs/screenshots/17-shift-review.png and b/docs/screenshots/17-shift-review.png differ diff --git a/docs/screenshots/19-radial-menu.png b/docs/screenshots/19-radial-menu.png index d74bbf1..36b4066 100644 Binary files a/docs/screenshots/19-radial-menu.png and b/docs/screenshots/19-radial-menu.png differ diff --git a/docs/screenshots/20-crowd-panic.png b/docs/screenshots/20-crowd-panic.png index d5b0e6f..1f7cb8d 100644 Binary files a/docs/screenshots/20-crowd-panic.png and b/docs/screenshots/20-crowd-panic.png differ diff --git a/docs/screenshots/21-responder-arrival.png b/docs/screenshots/21-responder-arrival.png index 6d2fbd4..f266db4 100644 Binary files a/docs/screenshots/21-responder-arrival.png and b/docs/screenshots/21-responder-arrival.png differ diff --git a/src/game/world_builder.gd b/src/game/world_builder.gd index 0718269..34820ac 100644 --- a/src/game/world_builder.gd +++ b/src/game/world_builder.gd @@ -129,9 +129,13 @@ const VENUE_SPECS := { {"zone": "mid_block", "prop": "round_planter", "x": 12.8, "z": 7.0}, {"zone": "curb", "prop": "a_frame_sign", "x": -9.8, "z": 7.0, "rot": 15.0}, {"zone": "curb", "prop": "traffic_cone", "x": 9.6, "z": 10.0}, - {"zone": "curb", "prop": "crowd_barrier", "x": 3.0, "z": 10.9}, - {"zone": "curb", "prop": "stanchion", "x": -2.6, "z": 10.9}, - {"zone": "entrance", "prop": "security_podium", "x": 8.0, "z": 6.1, "rot": -15.0}, + # Hollywood queue: a rope line into the check-in podium, barricades at the + # curb. The single stanchion and lone barricade read as stray street furniture. + {"zone": "entrance", "prop": "stanchion", "x": 5.4, "z": 7.4}, + {"zone": "entrance", "prop": "stanchion", "x": 6.3, "z": 7.4}, + {"zone": "entrance", "prop": "stanchion", "x": 7.2, "z": 7.4}, + {"zone": "entrance", "prop": "security_podium", "x": 8.4, "z": 6.5, "rot": -95.0}, + {"zone": "curb", "prop": "crowd_barrier", "x": 5.0, "z": 10.4}, ], }, "joke_shop": { @@ -211,11 +215,15 @@ const VENUE_SPECS := { "masonic_facade": true, }, "prop_placements": [ - {"zone": "entrance", "prop": "stanchion", "x": -2.8, "z": 4.4}, - {"zone": "entrance", "prop": "stanchion", "x": 2.8, "z": 4.4}, - {"zone": "entrance", "prop": "crowd_barrier", "x": -5.2, "z": 4.2}, - {"zone": "entrance", "prop": "crowd_barrier", "x": 5.2, "z": 4.2}, - {"zone": "curb", "prop": "security_podium", "x": 4.6, "z": 5.9, "rot": -15.0}, + # Same queue story as the Joke Shop: a rope line west of the approach lane + # into the check-in podium, barricades on the curb. The old placements sat at + # z 4.2-4.4, which is inside the steps/door exclusion and off the sidewalk. + {"zone": "entrance", "prop": "stanchion", "x": 2.6, "z": 7.6}, + {"zone": "entrance", "prop": "stanchion", "x": 3.5, "z": 7.6}, + {"zone": "entrance", "prop": "stanchion", "x": 4.4, "z": 7.6}, + {"zone": "entrance", "prop": "security_podium", "x": 5.6, "z": 6.7, "rot": -95.0}, + {"zone": "curb", "prop": "crowd_barrier", "x": 2.2, "z": 10.4}, + {"zone": "curb", "prop": "crowd_barrier", "x": -5.0, "z": 9.6}, ], }, } diff --git a/src/test/tests/test_world.gd b/src/test/tests/test_world.gd index d8330c2..93960df 100644 --- a/src/test/tests/test_world.gd +++ b/src/test/tests/test_world.gd @@ -96,6 +96,22 @@ func test_joke_shop_uses_the_real_sunset_strip_layout() -> bool: root.free() return a and a2 and b and c and d and e and f and g and g2 and h +## The placement validator was only applied to the Joke Shop, so the TV Studio kept +## three props inside the steps/door zone and off the sidewalk without anyone +## noticing. Every venue is checked now. +func test_every_venue_placement_clears_the_sidewalk_and_the_approach() -> bool: + var problems: Array[String] = [] + for venue in ["hollywood_building", "joke_shop", "tv_studio"]: + var root := Node3D.new() + var builder := WorldBuilder.new(root, venue) + var placements: Array = builder.spec.get("prop_placements", []) + for problem in WorldBuilder.placement_problems(placements): + problems.append("%s: %s" % [venue, problem]) + root.free() + return TestUtils.check(problems.is_empty(), + "every venue's props sit on the sidewalk and clear the approach (%s)" + % ", ".join(problems.slice(0, 5))) + func test_joke_shop_geometry_stays_inside_the_map_budget() -> bool: var root := Node3D.new() var builder := WorldBuilder.new(root, "joke_shop")