- Drop actions/cache@v4 from the checks job: the Gitea runner cannot reach GitHub's cache service (/twirp/...CacheService timeouts, ~2min retries); Godot import is fast enough without it. Add GODOT_SILENCE_ROOT_WARNING=1. - Document the cache situation and re-enable path in docs/RELEASING.md - VenueScenario.door_staff_line(context, rng): seeded-random venue lines - GameManager logs id/ticket/wand-check, refusal, and prohibited-item lines from the venue scenario (Joke Shop flavor) during inspection/screening - Test coverage: all Joke Shop contexts, unknown contexts, empty venues, deterministic seeded picks (54 tests pass)
69 lines
8.2 KiB
Markdown
69 lines
8.2 KiB
Markdown
# MEMORY
|
|
|
|
Session memory for durable decisions, state, and gotchas. Keep concise, remove obsolete entries.
|
|
|
|
## Decisions
|
|
|
|
- Engine: Godot 4.3 stable (official editor build, `~/.local/bin/godot`). The system's preinstalled `godot-runner` (4.7.2, Fedora) cannot load projects from arbitrary paths because it was compiled without path overrides; use the official editor binary instead.
|
|
- Language: GDScript. All cross-file references use explicit `preload()` constants (not `class_name` globals) so scripts compile in headless `--script` runs without the editor's class cache.
|
|
- Test framework deviation: the project uses a custom minimal headless test runner (`src/test/test_runner.gd`) instead of GUT, because GUT needs the editor plugin. CI runs it with `--headless`.
|
|
- Eventing: no autoload signal bus. `ShiftCoordinator` owns an `EventBus` instance (`src/core/event_bus.gd`) passed to subsystems; subsystems emit only when a bus is assigned. Autoloads at parse time are unreliable under `--script`.
|
|
- Static signals are not available in Godot 4.3 GDScript ("Expected func or var after static") — do not use them.
|
|
- GDScript lambdas capture local variables **by value**; mutating a captured local inside a lambda does not affect the outer variable. Use member functions for accumulators in tests.
|
|
- Prototype shift duration defaults to 300 s for testing; production targets 10-15 minutes per PLAN.md.
|
|
- RNG: NPC reactions and event scheduling are seedable for deterministic tests.
|
|
|
|
## Current State
|
|
|
|
- Core simulation, three scenarios, headless tests (**52 passing**), and a first-person prototype with interaction HUD, access inspection, radio (assist + emergency hold-to-confirm), debug overlay, and shift review are implemented and green.
|
|
- NPC avatars now walk to per-intent waypoints (`VenueScenario.waypoint_for_intent`): enter/trespass/deliver/arrive → entrance, photo/film/perform/wander/roam → sidewalk, sit → steps_end. `NpcAvatar.setup` takes an explicit `door_position`.
|
|
- Returning-trespasser behavior: `NpcProfile.return_probability` (trespasser 0.6, mental-crisis 0.4, others 0). `NPCController._maybe_schedule_return()` moves a directed-away NPC to `LOITERING_DISTANT`; `tick_return(delta)` fires after 20-60s and transitions back to `APPROACH`. `NpcAvatar._advance_fsm` re-targets the door on return.
|
|
- Perception pass: `NPCController.perceive_guard(distance)` returns `{noticed, band, reaction}` with bands `unaware` (>6m), `aware` (2-6m), `near` (<2m). Near + temperament ≥0.6 → ARGUE, else COMPLY. `GameManager._perception_pass()` feeds real guard distance each physics tick and logs first-time notice.
|
|
- Responder dispatch: `RadioSystem` tracks `pending_calls` and decrements `arrival_delay_s` in `tick`; emits `responder_arrived` when a call's delay elapses. `RadioSystem.responder_outcome(call)` maps danger/weapons → command/restraint/evacuation/arrest. `GameManager._on_responder_arrived` spawns a `RESPONDER` avatar at the entrance and logs the outcome. HUD shows an emergency-radio cooldown label via `_update_radio_cooldown`.
|
|
- Wand screening (Joke Shop): `WandScreener` (new `src/core/wand_screener.gd`) classifies carried items as prohibited (`weapon/knife/gun/blade`) vs false-alarm (`keys/belt/phone/coins/watch/buckle`) vs clear. `NpcProfile.carried_items` holds guest items. `GameManager` binds `W` to `_toggle_wand_screening` and `A`/`D` to `decide_wand`; `decide_access` blocks admission at wand venues until `controller.screened` is true. `VenueScenario.door_staff_lines` holds venue-specific door-staff dialogue (Joke Shop has id/ticket/wand/refusal/prohibited lines).
|
|
- Design change (2026-10-31): the selectable dialogue tone-of-voice system was **removed**.
|
|
`Rules.Tone`/`TONE_NAMES`, `NpcProfile.tone_modifiers`, and the tone param on
|
|
`NPCController.roll_reaction/apply_player_action` no longer exist; `NpcProfile.dialogue_lines`
|
|
is a flat `Array[String]`; `GameManager` uses `_apply_interaction(level, action_name)`;
|
|
the `T` key is gone. HUD `tone_label` removed and `hud.tone_prefix` string deleted from JSON.
|
|
- Polish/accessibility: venue cycling (`V` cycles `VENUE_ORDER` and restarts the shift), aim-free
|
|
targeting (`Tab` cycles nearby NPCs within `NEARBY_RADIUS`), color-coded escalation indicator
|
|
(`Hud.set_escalation`), procedural audio (`AudioFeedback` node generates sine tones for
|
|
confirm/radio/escalation/deny), and a centralized `Strings` table (`src/core/strings.gd`, `lookup`/`fmt`)
|
|
backed by `content/strings.en.json`. NOTE: `Strings.get` was renamed to `Strings.lookup` because
|
|
`get` collides with `Object.get`.
|
|
- Newly added: LATE shift phase (start 700s) with a reachability test; PROTESTER archetype + events + colors; CALL_SOMEONE reaction; `DoorState` core class + `L` binding + visual indicator; flashlight (`G`, SpotLight3D, perception bonus at evening/late); persistence wired (`Save.save_shift_result` on shift end, history + best score on the review screen); `NavigationRegion3D` flat navmesh + `NavigationAgent3D` NPC paths (steps now visual-only); strings moved to `res://content/strings.en.json` (41 keys, loader keeps `lookup`/`fmt`); `export_presets.cfg` (Linux/Windows/macOS) + `tools/build_releases.sh` + `docs/RELEASING.md`; README Downloads section.
|
|
- Run tests: `godot --headless --path . --script res://src/test/test_runner.gd`
|
|
- Boot check: `godot --headless --path . --quit-after 120`
|
|
- Screenshot tools: `godot --path . -s res://src/test/take_screenshot.gd` (single shot to `user://screenshot.png`); `godot --path . -s res://src/test/capture_screenshots.gd` (staged README gallery shots to `user://screenshots/`, copied to `docs/screenshots/`).
|
|
- Release build verified locally: export templates for 4.3 installed at `~/.local/share/godot/export_templates/4.3.stable/`; `./tools/build_releases.sh` produced Linux/Windows/macOS artifacts for 0.1.0 in `build/` and the Linux binary passed a headless smoke test. Publishing to Gitea still needs a token (see `tools/publish_release.sh`, `docs/RELEASING.md`).
|
|
- CI: the repo now carries a **Gitea Actions** workflow at `.gitea/workflows/build.yml` (checks on
|
|
push/PR; full export + artifact upload + optional release publish on tags and `workflow_dispatch`).
|
|
A repo secret `GITEA_TOKEN` is required for tag releases. The old `.github/workflows/ci.yml` was
|
|
removed so hosts scanning both paths do not double-run.
|
|
- Venue cycling: `V` switches Hollywood Blvd → The Joke Shop → TV Studio and restarts the shift.
|
|
- Venue door-staff dialogue: `VenueScenario.door_staff_line(context, rng)` and GameManager logging
|
|
(id/ticket/wand-check, refusal, prohibited-item) — Joke Shop flavor.
|
|
- CI cache: `.gitea/workflows/build.yml` no longer uses `actions/cache` (the runner can't reach
|
|
the GitHub cache service; import is fast). `GODOT_SILENCE_ROOT_WARNING=1` set on jobs.
|
|
Logs live in `.gitea/logs/` after each run.
|
|
|
|
## Known Issues / Notes
|
|
|
|
- RefCounted reference cycle: `NPCController` holds an `FSM` that holds a back-reference to its owner, so test suites report "resources still in use at exit". Benign (process exit), but worth breaking later (e.g. `WeakRef` or explicit `dispose()`).
|
|
- Headless (dummy renderer) logs "Parameter m is null" from `mesh_get_surface_count`; it does not occur with a real GL driver and does not affect logic.
|
|
- Steps are visual-only (no collider) so NPCs can path to the entrance; the guard spawns on the landing so it never needs to climb.
|
|
- Persistence tests write into the real `user://shift_results.json` (harmless local pollution of the demo history).
|
|
- macOS export required `rendering/textures/vram_compression/import_etc2_astc=true` in `project.godot` (universal build demands ETC2 ASTC enabled).
|
|
- Joke Shop `door_staff_lines` authored but not yet surfaced in the prototype UI (tracked in TODO).
|
|
|
|
## Open Questions
|
|
|
|
- Whether the responder avatar should be playable/controllable or purely scripted.
|
|
- Localization target languages beyond English.
|
|
- macOS notarization approach for broad distribution.
|
|
|
|
## Plan vs TODO Gaps (evaluated 2026-10-31, all resolved)
|
|
|
|
All previously identified gaps are now implemented and covered by tests/smoke items: PROTESTER archetype, door lock/secure, flashlight, CALL_SOMEONE reaction, LATE phase fix, shift-result persistence, NavigationAgent3D movement, and JSON-backed localization. Remaining backlog lives in `TODO.md`.
|