- 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)
9.5 KiB
9.5 KiB
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 preinstalledgodot-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 (notclass_nameglobals) so scripts compile in headless--scriptruns 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.
ShiftCoordinatorowns anEventBusinstance (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.setuptakes an explicitdoor_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 toLOITERING_DISTANT;tick_return(delta)fires after 20-60s and transitions back toAPPROACH.NpcAvatar._advance_fsmre-targets the door on return. - Perception pass:
NPCController.perceive_guard(distance)returns{noticed, band, reaction}with bandsunaware(>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:
RadioSystemtrackspending_callsand decrementsarrival_delay_sintick; emitsresponder_arrivedwhen a call's delay elapses.RadioSystem.responder_outcome(call)maps danger/weapons → command/restraint/evacuation/arrest.GameManager._on_responder_arrivedspawns aRESPONDERavatar at the entrance and logs the outcome. HUD shows an emergency-radio cooldown label via_update_radio_cooldown. - Wand screening (Joke Shop):
WandScreener(newsrc/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_itemsholds guest items.GameManagerbindsWto_toggle_wand_screeningandA/Dtodecide_wand;decide_accessblocks admission at wand venues untilcontroller.screenedis true.VenueScenario.door_staff_linesholds 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 onNPCController.roll_reaction/apply_player_actionno longer exist;NpcProfile.dialogue_linesis a flatArray[String];GameManageruses_apply_interaction(level, action_name); theTkey is gone. HUDtone_labelremoved andhud.tone_prefixstring deleted from JSON. - Polish/accessibility: venue cycling (
VcyclesVENUE_ORDERand restarts the shift), aim-free targeting (Tabcycles nearby NPCs withinNEARBY_RADIUS), color-coded escalation indicator (Hud.set_escalation), procedural audio (AudioFeedbacknode generates sine tones for confirm/radio/escalation/deny), and a centralizedStringstable (src/core/strings.gd,lookup/fmt) backed bycontent/strings.en.json. NOTE:Strings.getwas renamed toStrings.lookupbecausegetcollides withObject.get. - Newly added: LATE shift phase (start 700s) with a reachability test; PROTESTER archetype + events + colors; CALL_SOMEONE reaction;
DoorStatecore class +Lbinding + visual indicator; flashlight (G, SpotLight3D, perception bonus at evening/late); persistence wired (Save.save_shift_resulton shift end, history + best score on the review screen);NavigationRegion3Dflat navmesh +NavigationAgent3DNPC paths (steps now visual-only); strings moved tores://content/strings.en.json(41 keys, loader keepslookup/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 touser://screenshot.png);godot --path . -s res://src/test/capture_screenshots.gd(staged README gallery shots touser://screenshots/, copied todocs/screenshots/). - Release build verified locally: export templates for 4.3 installed at
~/.local/share/godot/export_templates/4.3.stable/;./tools/build_releases.shproduced Linux/Windows/macOS artifacts for 0.1.0 inbuild/and the Linux binary passed a headless smoke test. Publishing to Gitea still needs a token (seetools/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 andworkflow_dispatch). A repo secretGITEA_TOKENis required for tag releases. The old.github/workflows/ci.ymlwas removed so hosts scanning both paths do not double-run. - Venue cycling:
Vswitches 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.ymlno longer usesactions/cache(the runner can't reach the GitHub cache service; import is fast).GODOT_SILENCE_ROOT_WARNING=1set 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.pyproduces all authored PNGs underassets/textures/(≤1024px, pow2); regenerate after changing the script, then rungodot --headless --importbefore 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 statusbefore committing and leave foreign changes untouched unless asked.
Known Issues / Notes
- RefCounted reference cycle:
NPCControllerholds anFSMthat 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.WeakRefor explicitdispose()). - 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=trueinproject.godot(universal build demands ETC2 ASTC enabled). - Joke Shop
door_staff_linesauthored 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.