Files
security-game/TODO.md
T
zwitschi 8cf7745c80 Plan remaining gaps in TODO.md after a PLAN/code audit
Control pass (ADRs 0007-0010) stays first. Added the holes the audit found:
venue-correct access artifacts (override_access unread), session shell,
leftover PLAN verbs, crowd rubberneck, emergency aftermath, replay, NPC
poses, real ambience, a few Joke Shop/Studio events, and doc drift.
Host sign-in remains deferred. Generated-asset integration stays out
(already in DONE).
2026-10-31 15:17:02 +01:00

186 lines
9.4 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# TODO
Checked against `PLAN.md`, ADRs 0001–0010, `README.md`, `DONE.md`, and `src/` (Godot 4.3
prototype, release **v0.2.1**, 57 headless tests). Do the control pass first; it unblocks
everything that uses focus or verbs.
Host `REQUIRE_SIGNIN_VIEW` stays deferred.
## Player control, focus ring, and radial action menu
Design: `PLAN.md` → "Player Control, Focus, and Action Menu" and ADRs 0007–0010.
### Locomotion
- [ ] Stop stealing WASD: wand off `W` (wheel + optional `C`); allow/deny `A`/`D` only while
inspect/wand is open; polite direction off `Q` as a required bind.
- [ ] Accel/decel on walk; gravity only when airborne; `floor_snap_length` for the steps.
- [ ] Mouse look only while captured and no modal UI is open. Freeze walk+look while the radial
(and inspect/wand opened from it) is up. Recapture on close.
- [ ] `Esc` closes the top modal first; with nothing open it still toggles mouse capture.
### Focus and head ring
- [ ] Replace the 8 m hairline ray as the primary picker with a focus cone (range ~10 m, head
inside a ~90 px / 10° circle around the crosshair; closest to center wins; occluded heads
skipped). Keep `Tab` as the 12 m cycle.
- [ ] Small grace so walk-bob does not drop focus.
- [ ] Billboarded ring on the focused avatar `Head`; gold idle, brighter while the radial is open;
one at a time. Optional `display_name` under the ring. No internal type name in the world.
- [ ] Add a small screen-center crosshair so the focus circle has a visible origin.
### Radial HUD
- [ ] New `src/game/ui/action_radial.gd` doughnut: open on LMB or `Space` when someone is focused.
Opening click does not pick a slice. Slices (top, clockwise, de-escalation first): raise
hand, point, head shake, polite direction, inspect, wand (grey if no wand), warning, block,
radio assist. Emergency stays on `R` only.
- [ ] Highlight by mouse angle, or `A`/`D` / arrows. Click slice or `Space` confirms. `Esc` / RMB
closes with no action and no recorder event.
- [ ] Inspect / wand / radio slices close the wheel then open the existing panels. Freeze until
that panel closes.
- [ ] Number keys `1`–`6` may remain as closed-menu shortcuts; they must not fire while the wheel
is open.
### NPC display
- [ ] Procedural rig: neck, shoes, hair cap from seed, two eye spheres so the head has a front.
Keep props, height variation, walk bob, notice-head-turn. Collision capsule matches height.
Named `Head` node stays the attach point.
### Input, copy, tests
- [ ] Update `project.godot` input map (`action_menu`, `confirm`, `cancel` includes RMB, wand on
`C`). Update `hud.controls` and the README table + smoke checklist.
- [ ] Headless tests `src/test/tests/test_focus_and_radial.gd`: cone picks the centered head;
highlight wrap; cancel writes no recorder event; `W` does not open wand.
## Access artifacts actually match the venue
`GameManager._artifacts_for` maps `NpcType` → a wristband or free `RECOGNITION`. Joke Shop
events set `override_access` `{has_ticket, has_id}` and nobody reads it, so club guests inspect
as "recognized staff" instead of ID/ticket. Studio counterfeit/follow events have the same hole.
- [ ] Build artifacts from the event (`override_access`, carried items) and the venue policy,
not from `NpcType` alone.
- [ ] Joke Shop: valid ID+ticket, ID without ticket, expired/mismatched/missing ID, no ID when
required. Recognition must not auto-grant on every `AUTHORIZED_GUEST`.
- [ ] Give some guests `carried_items` (keys / belt / phone / prohibited) so wand alerts are not
always clear.
- [ ] Studio: counterfeit wristband/credential and "follow authorized guest" use the scripted
event data, not the generic type map.
- [ ] Headless tests: Joke Shop `guest_no_id` is not granted by recognition; `guest_valid`
grants only with ID+ticket; wand venues still require `controller.screened`.
## Session shell
The game boots into a live 900 s shift. `Save` declares `settings.json` and never uses it.
`V` cycles venues by restarting the shift.
- [ ] Startup menu: pick venue, start shift, quit. Keyboard + click. Replaces `V` as the
player-facing path (`V` may stay as a debug bind).
- [ ] Pause overlay when `Esc` releases the mouse (or a dedicated pause key): resume, restart
shift, settings, quit to menu.
- [ ] Settings: mouse look sensitivity, persist through `Save` / `settings.json`. Load on boot.
- [ ] Shift review "Run another shift" returns to the venue menu, not a silent restart of the
same scenario.
## Remaining PLAN verbs (after the radial exists)
- [ ] Eye contact as a Level 1 action (PLAN / glossary). Distinct from raise-hand.
- [ ] "I recognize this person" is a player decision recorded as evidence, not a pre-attached
artifact on every staff/guest type.
- [ ] Formal warning can activate the body-camera / security-light flag (PLAN Level 2). Overlay
is currently always on; toggling should write an incident event.
- [ ] Blocking stations the guard between the person and the door (PLAN Level 3). Today it only
sends `apply_player_action(BLOCKING)`.
- [ ] "Request reason for entry" as a Level 3 ask, with a short NPC reply from `dialogue_lines`.
## Crowd presentation
`CrowdSystem` is a mood/attention float. PLAN wants people watching, gathering, and panicking.
- [ ] On `aggressive_behavior` / `emergency_responder`, nearby idle NPCs stop and face the
incident (rubberneck). On `crowd_panic`, they move away from the door.
- [ ] Profile a busy entrance with textured materials and props; add LOD or culling for distant
NPCs if frame time drops.
## Emergency aftermath
Responder outcomes (`command` / `restraint` / `evacuation` / `arrest`) are log lines. PLAN also
wants evacuation, a closed street, and an investigation when the call was unjustified.
- [ ] `evacuation` outcome actually clears the entrance (NPCs leave, door stays locked).
- [ ] Unjustified emergency (low danger, no weapon) writes an investigation note on the shift
review and applies the existing false-report / reputation hit.
- [ ] Review copy names the responder outcome, not only battery and crowd %.
## Body-camera replay
- [ ] Shift review: a timeline of recorded incident events (ADR-0005 already stores them).
Scrub or step through; no live 3D replay required in the first version.
## NPC theater
Intents `sit` / `photo` / `film` / `perform` already pick waypoints. Bodies still idle-stand.
- [ ] Sit pose at `steps_end`. Photo: brief raise of the influencer/tourist prop. Performer
stays put and plays the hat/sign. After the ADR-0010 rig pass, not before.
## Audio
`AudioFeedback` is sine beeps. DONE called that "crowd ambience"; it is not.
- [ ] Loop a low crowd bed that rises with `CrowdSystem.mood`.
- [ ] Radio open/close crackle on the existing radio panel, still headless-safe (no-op without
an audio server).
## Accessibility
- [ ] Escalation colors that still read in grayscale (shape or label, not hue alone).
- [ ] HUD font scale in settings.
## Scenario content still missing vs PLAN lists
- [ ] Joke Shop: guest on the reservation list without ID; borrowed/mismatched ID; guest
refuses wand screening; late arrival during a performance.
- [ ] Studio: filming-boundary repeat (influencer ignores a posted line); celebrity-arrival
crowd spike (more rubberneckers, not only one `arrive` spawn).
- [ ] Building: "activate body camera" and "request reason" once those verbs exist, used in
at least one authored event.
## Documentation drift
- [ ] README Development Status: test count is **57**, not 52. "Not yet implemented" should
match this file (control pass, artifact wiring, session shell, replay, crowd presentation).
- [ ] `PLAN.md` Tech Stack / Planned Commands still say GUT and GitHub Actions; the project
uses `src/test/test_runner.gd` and `.gitea/workflows/build.yml`.
- [ ] MEMORY: drop "door_staff_lines not surfaced" (they log through `GameManager`) and the
obsolete "prototype defaults to 300 s" decision.
## Distribution follow-up (host config, deferred)
Verified via API+host credentials (2026-10-31):
- [x] Repo is **public** (`private:false`) and account has admin rights.
- [x] Release `v0.2.1` now carries all five artifacts (portable binaries + NSIS installer +
AppImage) — the two installers were missing after CI publish (script uploaded only the
portables); `tools/publish_release.sh` fixed to include them and re-uploaded via API.
- [ ] **Remaining host setting**: instance-wide `[service] REQUIRE_SIGNIN_VIEW=true` makes
anonymous browsing/downloads redirect to login (API-confirmed repo is public; this is a
server `app.ini` setting, not an API or repo option).
Advised path for the host admin: set `REQUIRE_SIGNIN_VIEW = false` in `app.ini` under
`[service]`, restart Gitea, then verify `curl -sI https://git.allucanget.biz/zwitschi/security-game/releases/tag/v0.2.1`
returns 200 (not a login redirect) and an anonymous asset download succeeds. Alternative:
mirror downloads (Itch.io / GitHub Releases) for anonymous users.
## Open Polish
- [ ] Keep `%` placeholders stable in `Strings.fmt` when adding keys (positional formatting).
## Tooling (when an editor workflow exists)
- [ ] IDE/editor-based GUT integration. Until then the custom headless runner stays.
- [ ] Optional later: author venues as `.tres` resources instead of `ScenarioFactory` functions.
Not required for the control pass.