- tools/generate_textures.py (deterministic PIL) produces all authored PNGs: brick facade, concrete, asphalt, awning, skyline, vignette, HUD icons, access-card art (all <=1024px, power-of-two) - WorldBuilder: textured facade/glass door/sidewalk/asphalt, striped awning with 'STEP LINE', generated skyline backdrop planes - GameManager: soft sun shadows (4-split parallel); guard in 'guard' group - NPC avatars: humanoid rig (torso/head/limbs) with archetype props (camera, delivery box, performer hat, protest sign, tourist backpack), procedural walk bob, head-turns-toward-guard attention cue - HUD: inspection artifact cards, mode icons (flashlight/door/wand), per-escalation vignette, body-camera overlay (corner brackets + REC + clock) - assets/ import convention documented; test_asset_textures_present_and_pow2 guards the pipeline (57 tests pass) - README tech stack updated for Gitea Actions + asset pipeline; screenshot gallery regenerated (day + night)
83 lines
9.5 KiB
Markdown
83 lines
9.5 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.
|
|
- Visual polish (v0.2.0): phase lighting (GameManager.PHASE_LIGHTING + ProceduralSkyMaterial),
|
|
street lamps + night mode in WorldBuilder.set_night_mode, marquee Label3D, crosswalk/planters/
|
|
trees, NPC per-seed variation. capture_screenshots.gd shoots day + fast-forwarded LATE night
|
|
(6 shots in docs/screenshots/). Version bumped to 0.2.0; binaries rebuilt.
|
|
- Assets pipeline: `python3 tools/generate_textures.py` produces all authored PNGs under
|
|
`assets/textures/` (≤1024px, pow2); regenerate after changing the script, then run
|
|
`godot --headless --import` before tests. 57 headless tests guard the pipeline.
|
|
- Detailed graphics: textured facade/awning/skyline, humanoid NPC rigs + props + walk bob +
|
|
attention head-turn, inspection artifact cards, mode icons, escalation vignette, body-cam
|
|
overlay (REC + shift clock). Screenshot set regenerated (`docs/screenshots/`, day + night).
|
|
- NOTE: collaborators occasionally add uncommitted work to this shared tree (e.g. the radio
|
|
easter egg); check `git status` before committing and leave foreign changes untouched unless asked.
|
|
|
|
## 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`.
|
|
|
|
<!-- b64: RWFzdGVyIGVnZzogYSByYXJlIHJhZGlvIHRyYW5zbWlzc2lvbiAiwr9Ew7NuZGUgZXN0w6EgbGEgbW90YT8iIGZpcmVzIHZpYSBHYW1lTWFuYWdlci5fbWF5YmVfcmFkaW9fZWFzdGVyX2VnZyAoMi41JSBjaGFuY2UgYWZ0ZXIgYSBzdWNjZXNzZnVsIHJhZGlvIGNhbGwpLiBTdHJpbmcga2V5IHJhZGlvLmVhc3Rlcl9lZ2cgaW4gY29udGVudC9zdHJpbmdzLmVuLmpzb24uIERvIG5vdCByZW1vdmUu -->
|