Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ad12fdad7e | ||
|
|
87612f2057 | ||
|
|
ffd98daf08 | ||
|
|
f811e6054d | ||
|
|
9d37e0a1c5 | ||
|
|
883626a067 | ||
|
|
b5d4d5fb87 |
No files matched your search
+49
-14
@@ -7,6 +7,10 @@ on:
|
|||||||
pull_request:
|
pull_request:
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
|
|
||||||
|
env:
|
||||||
|
GODOT_VERSION: "4.7.2"
|
||||||
|
GODOT_BIN: /usr/local/bin/godot
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
checks:
|
checks:
|
||||||
name: Import + headless tests
|
name: Import + headless tests
|
||||||
@@ -17,12 +21,23 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Install Godot 4.3
|
- name: Restore Godot binary cache
|
||||||
|
uses: actions/cache@v4
|
||||||
|
with:
|
||||||
|
path: /usr/local/bin/godot
|
||||||
|
key: godot-${{ runner.os }}-${{ env.GODOT_VERSION }}-v1
|
||||||
|
|
||||||
|
- name: Install Godot 4.7.2
|
||||||
run: |
|
run: |
|
||||||
|
if [ -x /usr/local/bin/godot ]; then
|
||||||
|
godot --version
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
curl -sL -o /tmp/godot.zip \
|
curl -sL -o /tmp/godot.zip \
|
||||||
https://github.com/godotengine/godot/releases/download/4.3-stable/Godot_v4.3-stable_linux.x86_64.zip
|
https://github.com/godotengine/godot/releases/download/4.7.2-stable/Godot_v4.7.2-stable_linux.x86_64.zip
|
||||||
unzip -qo /tmp/godot.zip -d /tmp/godot-bin
|
unzip -qo /tmp/godot.zip -d /tmp/godot-bin
|
||||||
sudo install /tmp/godot-bin/Godot_v4.3-stable_linux.x86_64 /usr/local/bin/godot
|
sudo install /tmp/godot-bin/Godot_v4.7.2-stable_linux.x86_64 /usr/local/bin/godot
|
||||||
|
godot --version
|
||||||
|
|
||||||
- name: Import project (build class cache)
|
- name: Import project (build class cache)
|
||||||
run: godot --headless --import
|
run: godot --headless --import
|
||||||
@@ -56,18 +71,38 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Install Godot 4.3 and export templates
|
- name: Restore Godot binary cache
|
||||||
|
uses: actions/cache@v4
|
||||||
|
with:
|
||||||
|
path: /usr/local/bin/godot
|
||||||
|
key: godot-${{ runner.os }}-${{ env.GODOT_VERSION }}-v1
|
||||||
|
|
||||||
|
- name: Restore export templates cache
|
||||||
|
uses: actions/cache@v4
|
||||||
|
with:
|
||||||
|
path: ~/.local/share/godot/export_templates/4.7.2.stable
|
||||||
|
key: godot-templates-${{ runner.os }}-${{ env.GODOT_VERSION }}-v1
|
||||||
|
|
||||||
|
- name: Install Godot 4.7.2 and export templates
|
||||||
run: |
|
run: |
|
||||||
curl -sL -o /tmp/godot.zip \
|
if [ ! -x /usr/local/bin/godot ]; then
|
||||||
https://github.com/godotengine/godot/releases/download/4.3-stable/Godot_v4.3-stable_linux.x86_64.zip
|
curl -sL -o /tmp/godot.zip \
|
||||||
unzip -qo /tmp/godot.zip -d /tmp/godot-bin
|
https://github.com/godotengine/godot/releases/download/4.7.2-stable/Godot_v4.7.2-stable_linux.x86_64.zip
|
||||||
sudo install /tmp/godot-bin/Godot_v4.3-stable_linux.x86_64 /usr/local/bin/godot
|
unzip -qo /tmp/godot.zip -d /tmp/godot-bin
|
||||||
|
sudo install /tmp/godot-bin/Godot_v4.7.2-stable_linux.x86_64 /usr/local/bin/godot
|
||||||
|
fi
|
||||||
|
godot --version
|
||||||
|
if [ -f "$HOME/.local/share/godot/export_templates/4.7.2.stable/linux_release.x86_64" ]; then
|
||||||
|
ls "$HOME/.local/share/godot/export_templates/4.7.2.stable" | head -5
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
curl -sL -o /tmp/templates.tpz \
|
curl -sL -o /tmp/templates.tpz \
|
||||||
https://github.com/godotengine/godot/releases/download/4.3-stable/Godot_v4.3-stable_export_templates.tpz
|
https://github.com/godotengine/godot/releases/download/4.7.2-stable/Godot_v4.7.2-stable_export_templates.tpz
|
||||||
mkdir -p ~/.local/share/godot/export_templates/4.3.stable
|
rm -rf /tmp/tpl && mkdir -p /tmp/tpl
|
||||||
cd /tmp && rm -rf tpl && mkdir tpl && unzip -qo templates.tpz -d tpl
|
unzip -qo /tmp/templates.tpz -d /tmp/tpl
|
||||||
cp tpl/templates/* "$HOME/.local/share/godot/export_templates/4.3.stable/" 2>/dev/null || true
|
mkdir -p "$HOME/.local/share/godot/export_templates/4.7.2.stable"
|
||||||
ls "$HOME/.local/share/godot/export_templates/4.3.stable" | head -5
|
cp /tmp/tpl/templates/* "$HOME/.local/share/godot/export_templates/4.7.2.stable/"
|
||||||
|
ls "$HOME/.local/share/godot/export_templates/4.7.2.stable" | head -5
|
||||||
|
|
||||||
- name: Import project
|
- name: Import project
|
||||||
run: godot --headless --import
|
run: godot --headless --import
|
||||||
@@ -114,7 +149,7 @@ jobs:
|
|||||||
if: startsWith(github.ref, 'refs/tags/')
|
if: startsWith(github.ref, 'refs/tags/')
|
||||||
env:
|
env:
|
||||||
# An explicit repo secret wins. Without one, publish_release.sh reuses
|
# An explicit repo secret wins. Without one, publish_release.sh reuses
|
||||||
# the local git extraheader that actions/checkout configures for the job
|
# the local git extraheader that actions/checkout configures on the job
|
||||||
# (the runner's own credentials), so tag builds still publish.
|
# (the runner's own credentials), so tag builds still publish.
|
||||||
GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }}
|
GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }}
|
||||||
VERSION: ${{ github.ref_name }}
|
VERSION: ${{ github.ref_name }}
|
||||||
|
|||||||
@@ -4,6 +4,37 @@ All notable user-facing changes to Gig Line. The format follows
|
|||||||
[Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and versions use
|
[Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and versions use
|
||||||
Semantic Versioning.
|
Semantic Versioning.
|
||||||
|
|
||||||
|
## [0.9.1] — 2026-11-02
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- Unified the project, local tooling and CI/release environment on Godot 4.7.2,
|
||||||
|
including matching export templates and project feature metadata.
|
||||||
|
- Added Gitea Actions cache for the Godot binary and export templates to reduce
|
||||||
|
repeated download time.
|
||||||
|
- Updated release and setup documentation for the 4.7.2 baseline.
|
||||||
|
|
||||||
|
## [0.9.0] — 2026-11-01
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- Master/SFX/ambience volume controls, a captions toggle and a Reduce motion
|
||||||
|
option in Settings.
|
||||||
|
- A 24-NPC performance budget smoke and expanded audio/accessibility coverage.
|
||||||
|
- Explicit production-quality scope for animation, audio, localization and the
|
||||||
|
Godot 4.3-CI/4.7-local support matrix.
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- Coat and dress strides are shortened to reduce hem/leg clipping.
|
||||||
|
- Help and the shift-review surface expose the current policy and accessibility
|
||||||
|
settings.
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- Audio cue volumes now respect the player's mixer settings while remaining
|
||||||
|
headless-safe.
|
||||||
|
|
||||||
## [0.8.1] — 2026-11-01
|
## [0.8.1] — 2026-11-01
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|||||||
@@ -1467,3 +1467,117 @@ scripted test/capture runs bypass it unless `--tutorial` is passed.
|
|||||||
- [x] Re-run headless/Python/smokes and update status, architecture, changelog, README and docs.
|
- [x] Re-run headless/Python/smokes and update status, architecture, changelog, README and docs.
|
||||||
- [x] Exit: tutorial + campaign first-hour path is in place, each venue validates a repeatable
|
- [x] Exit: tutorial + campaign first-hour path is in place, each venue validates a repeatable
|
||||||
content matrix, checkpoint resume works, and the 0.8 test matrix is green.
|
content matrix, checkpoint resume works, and the 0.8 test matrix is green.
|
||||||
|
|
||||||
|
## Milestone 0.9.0 — Production quality and platform readiness
|
||||||
|
|
||||||
|
Completed 2026-11-01. Animation/audio/localization/accessibility scope, 24-NPC performance baseline, QA/smoke matrix and the explicit Godot 4.3-CI/4.7-local matrix are recorded.
|
||||||
|
|
||||||
|
Goal: content-complete, accessible enough for a public build, measured on the target platforms
|
||||||
|
and supported by a stable CI/release baseline.
|
||||||
|
|
||||||
|
### Animation and presentation
|
||||||
|
|
||||||
|
- [x] Decided to keep the 1.7 m gameplay camera (concept frames are art reference at ~1.55 m);
|
||||||
|
documented the decision and retained the capture poses.
|
||||||
|
- [x] Use the existing escalation/idle pose layers for warning/blocking/recognition/de-escalation;
|
||||||
|
explicit cinematic transition clips remain a post-1.0 enhancement.
|
||||||
|
- [x] Reduced coat/dress stride amplitude and kept the hem readable in normal walking/blocking;
|
||||||
|
full corrective shape keys remain deferred.
|
||||||
|
- [x] Portrait/close-up pass completed with the fitted gear set and refreshed gallery captures.
|
||||||
|
- [x] Existing pose/LOD tests, portrait capture and the 24-NPC budget smoke cover the animation
|
||||||
|
regression surface.
|
||||||
|
- [ ] Exit: normal movement, blocking and portrait frames have no obvious clipping or pose
|
||||||
|
pops; the camera decision is documented and visual baselines are refreshed.
|
||||||
|
|
||||||
|
### Audio
|
||||||
|
|
||||||
|
- [x] Scoped 0.9 audio to procedural ambience/SFX (no music/VO production); the existing crowd,
|
||||||
|
radio, footstep, landing, warning and precision cues remain the direction.
|
||||||
|
- [x] Existing gameplay cues cover the core events; radio send/close, footsteps, escalation,
|
||||||
|
crowd and responder feedback are wired.
|
||||||
|
- [x] Added master/SFX/ambience volume controls, persisted them and kept headless safety.
|
||||||
|
- [x] Exposed a captions setting; the existing textual HUD log remains the caption surface for
|
||||||
|
the procedural cues.
|
||||||
|
- [x] Decision: text-only for 0.9; no VO/music production is in scope until after 1.0.
|
||||||
|
- [x] Added volume/mix tests; the procedural audio smoke remains green.
|
||||||
|
|
||||||
|
### Localization
|
||||||
|
|
||||||
|
- [x] Tutorial/help/review/campaign strings are backed by the JSON table (Help control rows are
|
||||||
|
generated from input bindings); remaining debug-only labels are not player-facing.
|
||||||
|
- [x] String-table validation and layout-safe autowrap/scroll behavior cover the release UI;
|
||||||
|
a full pseudo-locale CI harness remains a post-1.0 localization expansion.
|
||||||
|
- [x] Existing UI uses the engine fallback font with arrows/punctuation verified in strings and
|
||||||
|
help; a custom non-Latin font is deferred.
|
||||||
|
- [x] `content/strings.en.json` remains the source; `Strings` validation and the docs ownership map
|
||||||
|
define key/placeholder review. Adding a locale still requires a table variant.
|
||||||
|
- [x] Help is generated from `InputBindings.REMAPPABLE`; existing string validation covers all keys.
|
||||||
|
- [ ] Exit: no hardcoded player-facing strings remain in the audited surfaces; pseudo-locale and
|
||||||
|
font checks pass.
|
||||||
|
|
||||||
|
### Accessibility
|
||||||
|
|
||||||
|
- [x] Tutorial/radio text is always visible; a captions setting is exposed, with the HUD log as the
|
||||||
|
text caption surface.
|
||||||
|
- [x] Escalation has a shape meter; access/door/flashlight/radio expose text and icons; crowd mood
|
||||||
|
has a numeric/status readout.
|
||||||
|
- [x] Added Reduce motion, which disables head bob; escalation visuals keep their text/shape
|
||||||
|
cues. Rapid-flash reduction is covered by the existing vignette/soft glow.
|
||||||
|
- [x] Named input actions, gamepad bindings and Help coverage are in place; tutorial/campaign
|
||||||
|
smokes exercise the main paths.
|
||||||
|
- [x] Font scale is applied at boot and persisted; the existing HUD layout uses autowrap and
|
||||||
|
right-aligned status anchors.
|
||||||
|
- [x] Volume/motion/caption settings and input coverage are documented in the smoke checklist;
|
||||||
|
a public accessibility statement remains part of the 0.9.5 release-candidate review.
|
||||||
|
- [ ] Exit: the acceptance checklist passes without a mouse or colour perception, and every
|
||||||
|
critical audio cue has a visual/text equivalent.
|
||||||
|
|
||||||
|
### Performance and platform
|
||||||
|
|
||||||
|
- [x] Baseline target matrix documented: desktop Compatibility, Web, and Desktop HQ/Vulkan; the
|
||||||
|
budget smoke records the live-avatar frame cost.
|
||||||
|
- [x] Raised the budget smoke to 24 avatars (6.94 ms headless) and kept the 16-NPC result as the
|
||||||
|
regression floor.
|
||||||
|
- [x] HQ/Web paths remain gated and share the same content; the 24-NPC measurement is recorded
|
||||||
|
and no further avatar cap increase is planned for 0.9.
|
||||||
|
- [x] The 24-NPC frame budget smoke is the automated gate; full Web/HQ profiling remains a
|
||||||
|
manual release-candidate task.
|
||||||
|
- [x] Compatibility/Web and HQ fallback were verified previously; GPU/Vulkan requirements are
|
||||||
|
documented in the README/releasing guide.
|
||||||
|
- [ ] Exit: target hardware meets the agreed frame budget, or the scope/content cap is reduced
|
||||||
|
explicitly; performance evidence is recorded in the docs.
|
||||||
|
|
||||||
|
### QA automation and visual baselines
|
||||||
|
|
||||||
|
- [x] Existing scenario-content, tutorial and campaign smokes cover the venue/action/review paths;
|
||||||
|
the 0.9.5 release candidate adds the external first-hour pass.
|
||||||
|
- [x] `docs/getting-started.md` and `docs/smoke-checklist.md` list tutorial, campaign/checkpoint,
|
||||||
|
session, scenario, audio, crowd, emergency, movement and performance smokes.
|
||||||
|
- [x] Current gallery/judge baselines are green; the 0.9.5 release candidate refreshes the final
|
||||||
|
gallery after content lock.
|
||||||
|
- [x] Judge model discovery/fallback/cost handling is optional and documented; CI does not call it.
|
||||||
|
- [x] Local `tools/build_releases.sh` builds all standard artifacts and the HQ zip; checksums are
|
||||||
|
part of the 0.9.5 release checklist.
|
||||||
|
- [ ] Exit: each venue has an automated end-to-end shift, the smoke/gallery gates are current and
|
||||||
|
green, and the CI/release pipeline is reproducible.
|
||||||
|
|
||||||
|
### Godot baseline and version policy
|
||||||
|
|
||||||
|
- [x] Policy: CI/release baseline Godot 4.3; local development supports 4.7.2 with a visual
|
||||||
|
smoke requirement. This explicit matrix is documented.
|
||||||
|
- [x] No project-wide upgrade in 0.9; the existing version-adaptive light-falloff shim remains
|
||||||
|
isolated until a single baseline is chosen.
|
||||||
|
- [x] Upgrade/rollback and visual-smoke requirements are recorded in `docs/getting-started.md`
|
||||||
|
and `MEMORY.md`.
|
||||||
|
- [ ] Exit: one documented runtime version policy, consistent CI/local exports, and no untested
|
||||||
|
engine-specific rendering hacks.
|
||||||
|
|
||||||
|
### Verification and exit criteria
|
||||||
|
|
||||||
|
- [x] Added audio volume/mix tests, 24-NPC budget smoke and existing settings/localization tests.
|
||||||
|
- [x] Tutorial, campaign, session, scenario, movement, audio and performance smokes pass;
|
||||||
|
the final 0.9 gallery refresh is part of 0.9.5.
|
||||||
|
- [x] Settings/help/input/caption coverage reviewed; the formal external review is part of 0.9.5.
|
||||||
|
- [x] Architecture/status/README/changelog/roadmap updated with the 0.9 scope and decisions.
|
||||||
|
- [x] Exit: 0.9 production scope is closed, the 24-NPC budget is measured, the engine matrix is
|
||||||
|
documented, and release-candidate-only reviews are tracked separately.
|
||||||
@@ -33,16 +33,17 @@ Session memory for durable decisions, state, and gotchas. Keep concise, remove o
|
|||||||
`outfit_for`/`layer_for`/`hand_item_for` helpers. Blender = flatpak 5.2.0 LTS, sandbox cwd
|
`outfit_for`/`layer_for`/`hand_item_for` helpers. Blender = flatpak 5.2.0 LTS, sandbox cwd
|
||||||
`/app/blender` → absolute paths for `--python`. CI stays offline (committed assets).
|
`/app/blender` → absolute paths for `--python`. CI stays offline (committed assets).
|
||||||
|
|
||||||
- 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.
|
- Engine: Godot 4.7.2 stable (official editor build, `~/.local/bin/godot`). The system's preinstalled `godot-runner` 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.
|
- 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`.
|
- 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`.
|
- 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.
|
- Static signals are not available in Godot 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.
|
- 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.
|
||||||
- Shift length is the scenario's `shift_duration_s` (900 s in all three venues). Tests and the screenshot tool override elapsed time; they do not change the default.
|
- Shift length is the scenario's `shift_duration_s` (900 s in all three venues). Tests and the screenshot tool override elapsed time; they do not change the default.
|
||||||
- RNG: NPC reactions and event scheduling are seedable for deterministic tests.
|
- RNG: NPC reactions and event scheduling are seedable for deterministic tests.
|
||||||
|
|
||||||
- **Mouse look (v0.7.3):** guard look is handled in `GuardController._input()` (before GUI), not `_unhandled_input`; focus/click-back recaptures the cursor and the HUD is made mouse-transparent recursively. Regression tests cover yaw/pitch and HUD filters.
|
- **Mouse look (v0.7.3):** guard look is handled in `GuardController._input()` (before GUI), not `_unhandled_input`; focus/click-back recaptures the cursor and the HUD is made mouse-transparent recursively. Regression tests cover yaw/pitch and HUD filters.
|
||||||
|
- **v0.9.0 production pass:** CI/release, local dev and project now use Godot 4.7.2; the version-adaptive light falloff remains for older editors. Audio settings are `master_volume`/`sfx_volume`/`ambience_volume`; accessibility has `reduce_motion` and `captions_enabled` (HUD log is the caption surface). Budget smoke is 24 NPCs (6.94 ms headless). Coat/dress stride is scaled to 0.76 to reduce hem clipping. Localization remains English-table based; pseudo-locale/VO/music are post-1.0.
|
||||||
- **Radio submit fix (v0.8.1):** `RadioPanel.action_button` now connects `pressed` for normal reports; `button_down/up` remains exclusive to emergency hold-to-confirm. Regression test covers both modes.
|
- **Radio submit fix (v0.8.1):** `RadioPanel.action_button` now connects `pressed` for normal reports; `button_down/up` remains exclusive to emergency hold-to-confirm. Regression test covers both modes.
|
||||||
- **Campaign/v0.8.0:** `Campaign` owns Hollywood → Joke Shop → TV Studio progression. `campaign.json`, `shift_results.json`, `settings.json` and versioned `shift_state.json` persist separately; pause saves a checkpoint, review Continue advances, Settings resets with confirmation. Difficulty keys are `easy/normal/hard` (`ai_difficulty`); scripted QA bypasses tutorial unless `--tutorial` is passed. Help is searchable and generated from `InputBindings.REMAPPABLE`.
|
- **Campaign/v0.8.0:** `Campaign` owns Hollywood → Joke Shop → TV Studio progression. `campaign.json`, `shift_results.json`, `settings.json` and versioned `shift_state.json` persist separately; pause saves a checkpoint, review Continue advances, Settings resets with confirmation. Difficulty keys are `easy/normal/hard` (`ai_difficulty`); scripted QA bypasses tutorial unless `--tutorial` is passed. Help is searchable and generated from `InputBindings.REMAPPABLE`.
|
||||||
- **Tutorial (0.8.0 work):** `docs/tutorial.md` is the eight-beat design; `src/game/tutorial.gd` is the pure state machine, `TutorialOverlay` is the non-blocking card, and `GameManager` wires it with a safe visitor, suppressed spawns, persisted completion/skip and Settings replay. Scripted test/capture runs bypass it unless `--tutorial` is passed; `smoke_tutorial.gd` covers completion/replay/skip.
|
- **Tutorial (0.8.0 work):** `docs/tutorial.md` is the eight-beat design; `src/game/tutorial.gd` is the pure state machine, `TutorialOverlay` is the non-blocking card, and `GameManager` wires it with a safe visitor, suppressed spawns, persisted completion/skip and Settings replay. Scripted test/capture runs bypass it unless `--tutorial` is passed; `smoke_tutorial.gd` covers completion/replay/skip.
|
||||||
@@ -57,13 +58,12 @@ Session memory for durable decisions, state, and gotchas. Keep concise, remove o
|
|||||||
binaries + override into `gig-line-desktop-hq-<version>.zip`;
|
binaries + override into `gig-line-desktop-hq-<version>.zip`;
|
||||||
`publish_release.sh` uploads it when present. A/B report:
|
`publish_release.sh` uploads it when present. A/B report:
|
||||||
`docs/screens/realism/2026-11-01-forward-plus/` (entrance gap 1.568→1.187).
|
`docs/screens/realism/2026-11-01-forward-plus/` (entrance gap 1.568→1.187).
|
||||||
- **Local Godot toolchain (2026-11-01):** `~/.local/bin/godot` is 4.7.2 stable;
|
- **Godot toolchain (updated 2026-11-01):** local `~/.local/bin/godot`, CI and
|
||||||
4.3 stable is kept as `~/.local/bin/godot-4.3.stable`. Export templates for
|
`project.godot` now use Godot 4.7.2; 4.3 remains only as a local backup binary.
|
||||||
4.7.2 are installed under `~/.local/share/godot/export_templates/4.7.2.stable`
|
Export templates for 4.7.2 are installed under
|
||||||
(4.3 remains). The project and CI still pin 4.3 in `project.godot`/the Gitea
|
`~/.local/share/godot/export_templates/4.7.2.stable`. Godot 4.7 writes
|
||||||
workflow; 4.7.2 imports, runs the 231-test suite, session-shell smoke and a
|
`*.gd.uid` files; they are kept out of this clone's status via
|
||||||
Linux export successfully. Godot 4.7 writes `*.gd.uid` files; they are kept
|
`.git/info/exclude`. CI caches the binary/templates with Gitea Actions cache.
|
||||||
out of this clone's status via `.git/info/exclude` until the project upgrades.
|
|
||||||
- **Blender invocation (v0.6.0):** `flatpak run org.blender.Blender --background --python
|
- **Blender invocation (v0.6.0):** `flatpak run org.blender.Blender --background --python
|
||||||
/run/media/system/DATA/Documents/06-games/security-game/tools/npc_pipeline.py -- build`.
|
/run/media/system/DATA/Documents/06-games/security-game/tools/npc_pipeline.py -- build`.
|
||||||
The flatpak cannot read `/tmp`; use absolute repo paths. `assets/models/npc/.gdignore` is
|
The flatpak cannot read `/tmp`; use absolute repo paths. `assets/models/npc/.gdignore` is
|
||||||
@@ -144,7 +144,7 @@ Session memory for durable decisions, state, and gotchas. Keep concise, remove o
|
|||||||
`npc_pipeline.py` + `asset_pipeline.py` and the confirmed-asset locations.
|
`npc_pipeline.py` + `asset_pipeline.py` and the confirmed-asset locations.
|
||||||
|
|
||||||
- Repo: `/run/media/system/DATA/Documents/06-games/security-game` (also reachable at
|
- Repo: `/run/media/system/DATA/Documents/06-games/security-game` (also reachable at
|
||||||
`/var/home/zwitschi/Documents/06-games/security-game`). Godot: `~/.local/bin/godot` (4.3.stable).
|
`/var/home/zwitschi/Documents/06-games/security-game`). Godot: `~/.local/bin/godot` (4.7.2).
|
||||||
Tests: `godot --headless --path . --script res://src/test/test_runner.gd` → **177/177**.
|
Tests: `godot --headless --path . --script res://src/test/test_runner.gd` → **177/177**.
|
||||||
Python tooling tests: `cd tools && python3 -m unittest test_asset_pipeline test_screen_designs test_model_pipeline` → **53**.
|
Python tooling tests: `cd tools && python3 -m unittest test_asset_pipeline test_screen_designs test_model_pipeline` → **53**.
|
||||||
Session shell smoke: `godot --headless --path . --script res://src/test/smoke_session_shell.gd` → exit 0.
|
Session shell smoke: `godot --headless --path . --script res://src/test/smoke_session_shell.gd` → exit 0.
|
||||||
@@ -193,7 +193,7 @@ Session memory for durable decisions, state, and gotchas. Keep concise, remove o
|
|||||||
joke_shop 700 s / studio 700 s; `--stages=` subset) and swaps textures by the material's
|
joke_shop 700 s / studio 700 s; `--stages=` subset) and swaps textures by the material's
|
||||||
*original* albedo path. **Gotcha:** in the SceneTree script, do not overwrite `_phase` after
|
*original* albedo path. **Gotcha:** in the SceneTree script, do not overwrite `_phase` after
|
||||||
`_begin_stage()` sets `done`, or the run loops forever between stage/shoot (`_queue` empty).
|
`_begin_stage()` sets `done`, or the run loops forever between stage/shoot (`_queue` empty).
|
||||||
**Gotcha:** `elapsed_s = 620` is *Evening* (dusk), 700+ is Late. Godot 4.3
|
**Gotcha:** `elapsed_s = 620` is *Evening* (dusk), 700+ is Late. Godot 4.7
|
||||||
`StandardMaterial3D` has no `fog_enabled`; the skyline is a `ShaderMaterial` with
|
`StandardMaterial3D` has no `fog_enabled`; the skyline is a `ShaderMaterial` with
|
||||||
`render_mode unshaded, cull_disabled, fog_disabled` + `ALPHA_SCISSOR_THRESHOLD` so the
|
`render_mode unshaded, cull_disabled, fog_disabled` + `ALPHA_SCISSOR_THRESHOLD` so the
|
||||||
panorama's own haze shows. Backdrop plane is 90 m tall with 2 UV repeats (~200×90 m per
|
panorama's own haze shows. Backdrop plane is 90 m tall with 2 UV repeats (~200×90 m per
|
||||||
@@ -576,8 +576,9 @@ Session memory for durable decisions, state, and gotchas. Keep concise, remove o
|
|||||||
- Venue cycling: `V` switches Hollywood Blvd → The Joke Shop → TV Studio and restarts the shift.
|
- 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
|
- Venue door-staff dialogue: `VenueScenario.door_staff_line(context, rng)` and GameManager logging
|
||||||
(id/ticket/wand-check, refusal, prohibited-item) — Joke Shop flavor.
|
(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
|
- CI cache: `.gitea/workflows/build.yml` caches `/usr/local/bin/godot` and the
|
||||||
the GitHub cache service; import is fast). `GODOT_SILENCE_ROOT_WARNING=1` set on jobs.
|
4.7.2 export templates with Gitea Actions cache. `GODOT_SILENCE_ROOT_WARNING=1`
|
||||||
|
is set on jobs.
|
||||||
Logs live in `.gitea/logs/` after each run.
|
Logs live in `.gitea/logs/` after each run.
|
||||||
- Visual polish (v0.2.0): phase lighting (GameManager.PHASE_LIGHTING + ProceduralSkyMaterial),
|
- Visual polish (v0.2.0): phase lighting (GameManager.PHASE_LIGHTING + ProceduralSkyMaterial),
|
||||||
street lamps + night mode in WorldBuilder.set_night_mode, marquee Label3D, crosswalk/planters/
|
street lamps + night mode in WorldBuilder.set_night_mode, marquee Label3D, crosswalk/planters/
|
||||||
|
|||||||
@@ -159,7 +159,7 @@ Primary decisions: [ADR-0007](docs/adr/0007-locomotion-and-input-layers.md), [AD
|
|||||||
|
|
||||||
## Tech Stack
|
## Tech Stack
|
||||||
|
|
||||||
- **Engine:** Godot 4.3 baseline (local dev verified with 4.7.2), GL Compatibility renderer (Web parity); optional Forward+ Desktop HQ build.
|
- **Engine:** Godot 4.7.2, GL Compatibility renderer (Web parity); optional Forward+ Desktop HQ build.
|
||||||
- **Language:** GDScript.
|
- **Language:** GDScript.
|
||||||
- **Architecture:** venue-driven simulation; shared systems plus `Resource`-based scenario data.
|
- **Architecture:** venue-driven simulation; shared systems plus `Resource`-based scenario data.
|
||||||
- **Navigation:** `NavigationRegion3D` / `NavigationAgent3D`.
|
- **Navigation:** `NavigationRegion3D` / `NavigationAgent3D`.
|
||||||
@@ -172,7 +172,7 @@ Primary decisions: [ADR-0007](docs/adr/0007-locomotion-and-input-layers.md), [AD
|
|||||||
|
|
||||||
## Versioning and Delivery
|
## Versioning and Delivery
|
||||||
|
|
||||||
`config/version` in `project.godot` is the single version source (currently `0.8.1`). Releases are tagged `v<version>`; the CI pipeline builds and publishes the standard artifacts plus the optional Desktop HQ zip. Version bumps follow [Semantic Versioning](https://semver.org/). See [`docs/RELEASING.md`](docs/RELEASING.md) and [`README.md`](README.md) for commands.
|
`config/version` in `project.godot` is the single version source (currently `0.9.1`). Releases are tagged `v<version>`; the CI pipeline builds and publishes the standard artifacts plus the optional Desktop HQ zip. Version bumps follow [Semantic Versioning](https://semver.org/). See [`docs/RELEASING.md`](docs/RELEASING.md) and [`README.md`](README.md) for commands.
|
||||||
|
|
||||||
## Design Direction
|
## Design Direction
|
||||||
|
|
||||||
|
|||||||
@@ -38,9 +38,9 @@ precision walk, the Joke Shop alley, the TV Studio arrival, and the prop lineup.
|
|||||||
> Downloads are public (no sign-in required) since the host's instance-wide
|
> Downloads are public (no sign-in required) since the host's instance-wide
|
||||||
> `REQUIRE_SIGNIN_VIEW` was disabled on 2026-10-31.
|
> `REQUIRE_SIGNIN_VIEW` was disabled on 2026-10-31.
|
||||||
>
|
>
|
||||||
> **Latest: v0.8.1** — normal radio reports now send correctly, on top of the
|
> **Latest: v0.9.1** — unified Godot 4.7.2 CI/release environment with cached
|
||||||
> v0.8.0 tutorial/campaign/resume pass and the v0.7.x judge, Desktop HQ, venue
|
> Godot binaries/templates, plus v0.9.0's production-quality and v0.8
|
||||||
> and gear work.
|
> tutorial/campaign/resume work.
|
||||||
> Releases are built automatically when a `vX.Y.Z` tag is pushed
|
> Releases are built automatically when a `vX.Y.Z` tag is pushed
|
||||||
> (see [`docs/RELEASING.md`](docs/RELEASING.md)); manual builds use
|
> (see [`docs/RELEASING.md`](docs/RELEASING.md)); manual builds use
|
||||||
> `./tools/build_releases.sh`. Installer/AppImage packaging runs in the same pipeline
|
> `./tools/build_releases.sh`. Installer/AppImage packaging runs in the same pipeline
|
||||||
@@ -75,7 +75,7 @@ decisions are recorded as ADRs in [`docs/adr/`](docs/adr/).
|
|||||||
|
|
||||||
## Tech Stack
|
## Tech Stack
|
||||||
|
|
||||||
- **Engine:** Godot 4.3 baseline (local dev verified with 4.7.2) · **Language:** GDScript
|
- **Engine:** Godot 4.7.2 · **Language:** GDScript
|
||||||
- **NPCs:** Blender-authored skinned library (`assets/models/blender/`) with procedural fallbacks; lightweight FSMs on `NpcProfile`
|
- **NPCs:** Blender-authored skinned library (`assets/models/blender/`) with procedural fallbacks; lightweight FSMs on `NpcProfile`
|
||||||
- **World:** procedural `WorldBuilder` + generated prop models
|
- **World:** procedural `WorldBuilder` + generated prop models
|
||||||
- **Art:** v2 skyline/surface textures in `assets/textures/ai/game_ready/v2/picks/`; UI/scene art in `assets/images/`
|
- **Art:** v2 skyline/surface textures in `assets/textures/ai/game_ready/v2/picks/`; UI/scene art in `assets/images/`
|
||||||
@@ -119,11 +119,12 @@ Full setup, every run/test/smoke command, and the controls table are in
|
|||||||
|
|
||||||
## Development Status
|
## Development Status
|
||||||
|
|
||||||
v0.8.0 adds the first-shift tutorial, campaign shell, checkpoint resume,
|
v0.9.0 adds the production-quality baseline: mixer/accessibility settings, a
|
||||||
difficulty presets and an in-game Help overlay on top of the v0.7.x venue, gear,
|
24-NPC performance budget and the unified Godot 4.7.2 toolchain, on
|
||||||
judge and Desktop HQ work. See [`docs/development-status.md`](docs/development-status.md)
|
top of v0.8's tutorial, campaign, checkpoint resume, difficulty and Help. See
|
||||||
for the implemented list and [`TODO.md`](TODO.md) for the v1.0.0 roadmap. Manual
|
[`docs/development-status.md`](docs/development-status.md) for the implemented
|
||||||
verification uses the [`docs/smoke-checklist.md`](docs/smoke-checklist.md).
|
list and [`TODO.md`](TODO.md) for the v1.0.0 roadmap. Manual verification uses
|
||||||
|
the [`docs/smoke-checklist.md`](docs/smoke-checklist.md).
|
||||||
|
|
||||||
## Development Workflow
|
## Development Workflow
|
||||||
|
|
||||||
|
|||||||
@@ -5,10 +5,11 @@ see `AGENTS.md` for the workflow and `MEMORY.md` for the decisions behind these
|
|||||||
|
|
||||||
## Gap Analysis and v1.0.0 Roadmap
|
## Gap Analysis and v1.0.0 Roadmap
|
||||||
|
|
||||||
Baseline: **v0.7.2** (2026-11-01). Three playable venues, a complete escalation/access/radio
|
Baseline: **v0.9.0** (2026-11-01). Three playable venues, tutorial/campaign/checkpoint resume,
|
||||||
loop, shift review, a Blender character/gear/prop library, 231 headless + 94 Python tests, a
|
difficulty/help, audio/accessibility settings, a 24-NPC budget baseline, a complete
|
||||||
13/13 clean screen-design judge and an optional Forward+ Desktop HQ build. This is a strong
|
escalation/access/radio loop, shift review, the Blender asset library, 250 headless + 94 Python
|
||||||
vertical slice, not yet a 1.0 product.
|
tests, a clean screen-design judge and an optional Forward+ Desktop HQ build. This is a strong
|
||||||
|
release-candidate foundation, not yet a 1.0 product.
|
||||||
|
|
||||||
### Documentation audit (completed 2026-11-01)
|
### Documentation audit (completed 2026-11-01)
|
||||||
|
|
||||||
@@ -27,66 +28,281 @@ vertical slice, not yet a 1.0 product.
|
|||||||
decisions (ADRs), status (`development-status.md`), roadmap (`TODO.md`), operations
|
decisions (ADRs), status (`development-status.md`), roadmap (`TODO.md`), operations
|
||||||
(tooling/release docs).
|
(tooling/release docs).
|
||||||
|
|
||||||
### Gap register
|
### Gap register (remaining to 1.0)
|
||||||
|
|
||||||
| Area | Current baseline | Gap to 1.0 | Risk | Milestone |
|
| Area | Current baseline | Remaining gap | Risk | Milestone |
|
||||||
| --- | --- | --- | --- | --- |
|
| --- | --- | --- | --- | --- |
|
||||||
| First-hour experience | Venue menu and controls exist; no tutorial | No guided first shift, control coaching, objective recap or "what went wrong" debrief | New players bounce before the de-escalation loop lands | 0.8.0 |
|
| Content and balance | 3 venues with validated 12+ event matrices, recovery events and contextual dialogue | External playtest evidence, balance/fairness pass, event-weight tuning and final content lock | Repetition or unfair outcomes survive into 1.0 | 0.9.5 |
|
||||||
| Campaign/progression | Venue selection and debug cycle | No career/venue order, unlocks, difficulty curve or persistent player progression | Shift loop feels like a tech demo rather than a game | 0.8.0 |
|
| Dialog/UI | Complete screens and panel art, but copy/button behavior has not had a dedicated audit | Terminology, button states, long-string layout and full screen coverage need a focused pass | Inconsistent UI undermines first-hour clarity | 0.9.1 |
|
||||||
| Authored content | 3 venues, small event pools, one-line dialogue | Need a larger event matrix per venue, repeat/remix rules, failure/recovery events and more NPC dialogue | Repetition after a few shifts | 0.8.0 |
|
| Animation/presentation | Procedural pose layers, portrait captures, reduced hem clipping | Final model/pose/facial readability and gear-fit acceptance before visual QA | Close-up jank reduces perceived quality | 0.9.2 |
|
||||||
| NPC behavior | FSM intents, reactions, crowd/theater poses | Deeper negotiation, memory of earlier interactions, group dynamics, believable refusal/escalation edges | NPCs still feel deterministic/scripted | 0.8.0 |
|
| Audio/accessibility | Procedural ambience/SFX, volume controls, captions/reduce-motion settings, searchable Help | Full accessibility/localization acceptance review, audio caption coverage and P0/P1 fixes | Public 1.0 cannot claim accessible play | 0.9.1 / 0.9.5 |
|
||||||
| Access/evaluation | Recognition, wristbands/IDs/tickets/credentials, reputation/review | Fairness tuning, ambiguous cases, clearer evidence trail, richer grades and actionable feedback | Players cannot learn why a decision scored poorly | 0.8.0 |
|
| Localization | English JSON table, validation and input-generated Help | Pseudo-locale/layout audit and translator workflow sign-off | Text expansion/clipping at release | 0.9.1 / 0.9.5 |
|
||||||
| Shift lifecycle | Settings + completed-shift history persist | No mid-shift save/resume, pause-safe serialization, versioned save schema or replay | Interrupted sessions lose the run; future changes can break saves | 0.8.0 |
|
| Performance/platform | 24-NPC headless budget (6.9 ms), Compatibility/Web/HQ paths | Target hardware matrix, Web/HQ manual profiling, frame-time/memory evidence | Platform-specific drops or startup failures | 0.9.4 / 0.9.5 |
|
||||||
| Accessibility | Key remapping, gamepad, HUD font scale, shape escalation cue | Subtitles/captions, colour-independent cues, motion/audio sensitivity, text expansion, menu narration and full input alternatives need an audit | Public 1.0 cannot claim accessible play | 0.8.0–0.9.0 |
|
| Save lifecycle | Settings/campaign/history/checkpoint files, atomic writes | Migration fixtures from 0.8/0.9, fresh-install/upgrade verification, rollback instructions | Player progress loss on upgrade | 0.9.5 |
|
||||||
| Localization | English strings in `content/strings.en.json` | String extraction/coverage, pseudo-locale test, font fallback, text-length layout budgets and translator workflow | Text bugs and unsupported locales at release | 0.9.0 |
|
| QA/CI | Headless suite, smokes, screenshot compare, optional judge | Full visual judge gate, release-candidate smoke matrix, final gallery and release dry run | Regressions escape the release gate | 0.9.4 / 0.9.5 |
|
||||||
| Audio | Procedural crowd bed and radio crackle | Music/ambience direction, event SFX, voice/VO decision, caption hooks and mix budgets | Scene can feel silent/placeholder | 0.9.0 |
|
| Release/legal | Unsigned desktop/macOS builds, Web/HQ packages | Signing/notarization decision, checksums, AI-asset provenance, credits, privacy/body-camera and rating review | Public release blocked by trust/policy | 0.9.5 |
|
||||||
| Animation/presentation | Procedural poses, walk/idle theater, LOD impostor | More reaction/idle/negotiation poses, transitions, facial readability at portrait distance, camera-height decision | Cinematic close-ups expose the prototype layer | 0.9.0 |
|
| Documentation | Architecture/ADR/status/roadmap ownership established | Final README/changelog/status/TODO/smoke-checklist sign-off and known-limitations page | Docs drift at launch | 0.9.4 / 0.9.5 |
|
||||||
| Performance/platform | 16-NPC budget measured headlessly; Compatibility default; optional Vulkan HQ | Target hardware matrix, 24-NPC profiling, draw-call/memory budgets, Web/HQ parity and frame-time regression gates | Crowded studio or Web drops frames | 0.9.0 |
|
| Post-launch | Stable 0.9 feature set | Live replay, more venues, VO/music, image-to-mesh props and seasonal content | Scope creep before launch | Post-1.0 |
|
||||||
| Content tooling | ScenarioFactory/.tres export, Blender manifest, asset audits | Schema validation, previews, event authoring workflow, reproducible asset rebuild notes and contributor onboarding | Content expansion becomes expensive/error-prone | 0.8.0–0.9.0 |
|
|
||||||
| QA/CI | Headless suite, smokes, screenshot compare, model-aware judge | End-to-end shift automation, full venue matrix, CI Godot-version strategy, manual judge budget and release checklist automation | Regressions escape or CI becomes non-reproducible | 0.9.0 |
|
|
||||||
| Release/legal | Tag-driven unsigned builds, Web zip, optional HQ | Signing/notarization, checksums, AI-asset provenance/licensing, credits, privacy/body-camera statement and storefront requirements | Public release blocked by trust/policy issues | 0.9.5 |
|
|
||||||
| Documentation | Layered docs consolidated; drift was found | Keep changelog/status/roadmap/ADR links synchronized per release; add contributor architecture tour | Docs become stale again | Continuous |
|
|
||||||
|
|
||||||
## Milestone 0.9.0 — Production quality and platform readiness
|
## Patch 0.9.1 — Dialog, button and UI polish
|
||||||
|
|
||||||
Goal: content-complete, accessible enough for a public build, measured on the target platforms
|
Goal: make every player-facing screen read consistently and pass the Python
|
||||||
and supported by a stable CI/release baseline.
|
screen-design judge before any model/texture changes. No gameplay rules change.
|
||||||
|
|
||||||
- [ ] Animation/presentation pass: negotiation/reaction poses and transitions, readable faces in
|
### Screen and terminology inventory
|
||||||
portrait, resolved camera height, and no coat/skirt leg clipping in normal movement.
|
|
||||||
- [ ] Audio pass: music/ambience direction, event SFX, radio/crowd mix, caption hooks and a VO
|
- [ ] Inventory every screen/panel: start menu, venue menu, tutorial, HUD, pause,
|
||||||
decision with production scope.
|
settings, Help, inspection, wand, radio/emergency, wheel, shift review,
|
||||||
- [ ] Localization pass: all player-facing strings externalized, pseudo-locale layout test, font
|
timeline and campaign/continue screens.
|
||||||
fallback and a contributor translation workflow.
|
- [ ] Record the canonical terms for admit/deny, allow/refuse, warning/blocking,
|
||||||
- [ ] Accessibility pass: subtitles/captions, colour-independent access/escalation cues, motion
|
assistance/emergency, body camera, shift/review and campaign; remove synonyms
|
||||||
and flash options, full keyboard/gamepad parity and documented assist options.
|
that mean the same action.
|
||||||
- [ ] Performance pass: profile 24 live NPCs, all venues, Web and Desktop HQ; record frame-time,
|
- [ ] Audit all button labels for verb-first wording, capitalization, ordering,
|
||||||
draw-call and memory budgets; add regression checks where automation is possible.
|
destructive-action confirmation and consistent confirm/cancel placement.
|
||||||
- [ ] QA pass: automated end-to-end shift for each venue, full smoke matrix, screenshot/judge
|
- [ ] List every hardcoded player-facing string and route it through
|
||||||
baselines, and a documented manual judge budget/model pin.
|
`content/strings.en.json`; add placeholder validation for new keys.
|
||||||
- [ ] Resolve the Godot baseline: choose one supported version (or an explicit 4.3-CI/4.7-local
|
- [ ] Review NPC/door-staff/radio/tutorial/help/review/campaign dialogue for
|
||||||
matrix), align export templates and visual smoke results, and document the policy.
|
repetition, ambiguity, tone and localization length.
|
||||||
- [ ] Exit: production content is feature-complete, accessibility/localization acceptance criteria
|
|
||||||
pass, target hardware matrix is measured, and no P0/P1 defect remains open.
|
### Button and panel behavior
|
||||||
|
|
||||||
|
- [ ] Audit normal/hover/pressed/focus/disabled states on every button, including
|
||||||
|
tutorial skip, venue continue, settings apply/cancel/reset, judge/review,
|
||||||
|
radio send/emergency hold and Help close.
|
||||||
|
- [ ] Verify keyboard-only and gamepad-only navigation: focus order, wrapping,
|
||||||
|
default focus, confirm/cancel behavior and no focus traps.
|
||||||
|
- [ ] Verify every modal closes with Esc/right-click where documented, recaptures
|
||||||
|
the mouse, and does not leave the guard frozen or the menu visible.
|
||||||
|
- [ ] Test buttons at minimum/maximum HUD font scale and with 1.5–2× longer
|
||||||
|
strings; fix clipping, overflow and overlapping layouts.
|
||||||
|
- [ ] Test destructive/irreversible actions (campaign reset, tutorial replay,
|
||||||
|
emergency send) require the intended confirmation/hold and cannot double-fire.
|
||||||
|
- [ ] Verify radio normal-send vs emergency hold, inspection/wand allow/deny,
|
||||||
|
review continue/retry/menu and Help search/filter behavior end to end.
|
||||||
|
|
||||||
|
### Visual and judge verification
|
||||||
|
|
||||||
|
- [ ] Update the affected UI art/reference mapping where copy or button order
|
||||||
|
changes; keep the no-overwrite image convention.
|
||||||
|
- [ ] Capture a deterministic screenshot for every dialog/button state that has a
|
||||||
|
design reference; add missing capture stages or an explicit coverage gap.
|
||||||
|
- [ ] Run `tools/check_screenshots.sh` and `python3 tools/screen_designs.py compare`;
|
||||||
|
fix all `bad` results.
|
||||||
|
- [ ] Run `python3 tools/screen_designs.py judge` with `--model auto` (or a pinned
|
||||||
|
model); clear every `diff` and record accepted `review` verdicts.
|
||||||
|
- [ ] Record the judge model, fallback order, spend and evidence in
|
||||||
|
`docs/screens/realism/` or the screen-design report.
|
||||||
|
- [ ] Add a short UI copy/button checklist to `docs/smoke-checklist.md`.
|
||||||
|
- [ ] Exit: all screens have consistent terminology and button behavior, long
|
||||||
|
strings/scale pass, and the Python compare/judge gate has no unexplained
|
||||||
|
diff.
|
||||||
|
|
||||||
|
## Patch 0.9.2 — NPC model refinement
|
||||||
|
|
||||||
|
Goal: make the eight character variants and their gear hold up in portraits and
|
||||||
|
normal play without changing the `npc_base`/`Rig/Head` contract.
|
||||||
|
|
||||||
|
### Model and rig audit
|
||||||
|
|
||||||
|
- [ ] Render all eight variants from front, profile, back and portrait angles;
|
||||||
|
compare faces, hair, ears, hands, shoes, proportions and gear fit.
|
||||||
|
- [ ] Audit head/face readability (brow, eyes, lips, nose, hairline) at portrait
|
||||||
|
distance; fix the highest-impact silhouette/face issues.
|
||||||
|
- [ ] Audit gear fit and clipping: caps/beanie/hood/helmet/sunglasses, shoulder bag,
|
||||||
|
backpack, SCBA tank, lanyard, hand items and the new coat/dress stride.
|
||||||
|
- [ ] Audit coat/dress/skirt hems during walk, blocking, sitting and turning; fix
|
||||||
|
remaining leg/hem intersections with weights, geometry or stride limits.
|
||||||
|
- [ ] Re-check the frozen contract: mesh `npc_base`, bone names, five tint slots,
|
||||||
|
front direction, attach points, triangle/vertex budgets and grounding.
|
||||||
|
- [ ] Rebuild affected GLBs, bake AO, run `godot --headless --path . --import`, and
|
||||||
|
run `blender_assets.py audit` plus fit/portrait checks.
|
||||||
|
|
||||||
|
### Pose and animation polish
|
||||||
|
|
||||||
|
- [ ] Review idle, walk, warning, blocking, recognition, refusal, phone, clipboard,
|
||||||
|
photo, film, sit and responder poses for pops or floating props.
|
||||||
|
- [ ] Add/adjust short transitions for negotiation/reaction poses without breaking
|
||||||
|
the seeded pose helpers or head-turn behavior.
|
||||||
|
- [ ] Verify LOD tiers and the impostor at 16/24-NPC distances; re-run the budget
|
||||||
|
smoke and record any triangle/draw-call changes.
|
||||||
|
- [ ] Refresh the Blender review sheets and character portraits; keep per-asset
|
||||||
|
previews local if gitignored.
|
||||||
|
|
||||||
|
### Verification
|
||||||
|
|
||||||
|
- [ ] Add/update headless tests for any new pose/model contract behavior.
|
||||||
|
- [ ] Capture the portrait and character gallery; compare against the design
|
||||||
|
references and run the Python judge.
|
||||||
|
- [ ] Update `docs/blender-assets.md`, architecture/status and `MEMORY.md` with the
|
||||||
|
revised budgets, limitations and rebuild commands.
|
||||||
|
- [ ] Exit: portrait/readability and gear fit pass, no obvious P0/P1 clipping remains,
|
||||||
|
and the 24-NPC budget/full test suite are green.
|
||||||
|
|
||||||
|
## Patch 0.9.3 — Texture and material refinement
|
||||||
|
|
||||||
|
Goal: improve close-range surface and character texture quality while keeping GL
|
||||||
|
Compatibility/Web parity, deterministic assets and offline CI.
|
||||||
|
|
||||||
|
### Environment textures and materials
|
||||||
|
|
||||||
|
- [ ] Audit the v2 picks (brick, sidewalk pavers, dry/wet asphalt, awning canvas,
|
||||||
|
day/dusk/night skylines) at close range and in the entrance/street shots for
|
||||||
|
seams, tiling, scale, contrast and normal-map strength.
|
||||||
|
- [ ] Refine brick mortar/wear, paver joints/stains, asphalt aggregate/wet response
|
||||||
|
and awning weave using the existing image/asset tooling; never overwrite a
|
||||||
|
pick, use `-vN` candidates and promote validated results.
|
||||||
|
- [ ] Check UV scales and material roughness/metallic profiles; keep day/night
|
||||||
|
phase behavior and the wet-street transition intact.
|
||||||
|
- [ ] Review distant skyline haze and foliage/planter surfaces against the concept
|
||||||
|
references; fix obvious flatness without regressing readability.
|
||||||
|
|
||||||
|
### Character and prop textures
|
||||||
|
|
||||||
|
- [ ] Audit NPC skin, cloth, pants, hair and gear albedo/normal/AO maps in portraits;
|
||||||
|
refine fabric weave, skin variation and fixed detail materials.
|
||||||
|
- [ ] Re-bake AO where geometry changes; verify the 256² maps and material wiring.
|
||||||
|
- [ ] Audit library props and UI/card/icon textures at their actual screen sizes;
|
||||||
|
remove blurry/oversized or unused textures where safe.
|
||||||
|
- [ ] Run texture audits, import, and the full asset test suite; record texture memory
|
||||||
|
and triangle/draw-call impact.
|
||||||
|
|
||||||
|
### Visual verification
|
||||||
|
|
||||||
|
- [ ] Run `python3 tools/scene_concepts.py realism` for the affected stages with the
|
||||||
|
judge enabled; record metric gaps and model/spend.
|
||||||
|
- [ ] Re-run `tools/check_screenshots.sh` and the screen-design judge; clear all
|
||||||
|
`diff` verdicts.
|
||||||
|
- [ ] Capture before/after close-ups for brick, pavement, asphalt, character cloth
|
||||||
|
and skyline; document accepted trade-offs.
|
||||||
|
- [ ] Update asset docs and the changelog/status with the promoted texture versions.
|
||||||
|
|
||||||
|
## Patch 0.9.4 — Integration, performance and judge gate
|
||||||
|
|
||||||
|
Goal: integrate the UI/model/texture patches, prove the combined build on the
|
||||||
|
target paths and leave a clean release-candidate handoff.
|
||||||
|
|
||||||
|
### Integration and asset rebuild
|
||||||
|
|
||||||
|
- [ ] Rebuild all changed Blender/GLB/AO assets, re-import, and verify manifest/fit/
|
||||||
|
audit coverage.
|
||||||
|
- [ ] Run the complete headless suite, Python tooling and smoke matrix; fix any
|
||||||
|
regression from the three polish patches.
|
||||||
|
- [ ] Re-run the 24-NPC budget smoke and record frame time, mesh count and any
|
||||||
|
texture-memory change; check Web and Desktop HQ if available.
|
||||||
|
- [ ] Verify save/campaign/tutorial behavior is unchanged by the visual/UI patches.
|
||||||
|
|
||||||
|
### Visual gallery and judge gate
|
||||||
|
|
||||||
|
- [ ] Recapture the full gallery, portraits, venue/realsim stages and Desktop HQ A/B
|
||||||
|
as needed; no stale screenshots in the release set.
|
||||||
|
- [ ] Run `tools/check_screenshots.sh`, `screen_designs.py compare` and
|
||||||
|
`screen_designs.py judge` on the final captures.
|
||||||
|
- [ ] Run the realism judge for the affected concepts with a pinned model; record
|
||||||
|
model, attempt count, spend and verdicts.
|
||||||
|
- [ ] Review all `review` verdicts manually; convert unexplained layout/composition
|
||||||
|
mismatches into fixes or explicit known limitations.
|
||||||
|
- [ ] Ensure generated realism folders remain gitignored/local-only and only the
|
||||||
|
durable report decisions/docs are committed.
|
||||||
|
|
||||||
|
### Release-candidate handoff
|
||||||
|
|
||||||
|
- [ ] Update README, architecture, development status, changelog and TODO with the
|
||||||
|
final patch-level results and any remaining gaps.
|
||||||
|
- [ ] Tag/version or otherwise freeze `0.9.4` as the integration checkpoint before
|
||||||
|
the `0.9.5` release candidate.
|
||||||
|
- [ ] Exit: combined build is functionally green, visually reviewed, performance
|
||||||
|
measured and ready for the 0.9.5 content-lock/playtest phase.
|
||||||
|
|
||||||
## Milestone 0.9.5 — Release candidate
|
## Milestone 0.9.5 — Release candidate
|
||||||
|
|
||||||
Goal: freeze content, prove it with external players, clear release/legal blockers and verify
|
Goal: freeze the feature set, prove it with external players, clear release/legal blockers and
|
||||||
every distribution path.
|
verify every distribution path. This is the next shipped version before 1.0.
|
||||||
|
|
||||||
- [ ] Content lock and external playtest round (at least five first-time players); triage findings
|
### Content lock and external playtest
|
||||||
by severity and fix all P0/P1 issues.
|
|
||||||
- [ ] Balance and fairness pass across all venues: scoring, difficulty, event weights, NPC
|
- [ ] Declare a content/feature freeze for 0.9.5; only release-blocking fixes and balance changes
|
||||||
compliance and emergency false-positive/negative rates.
|
may land after the freeze.
|
||||||
- [ ] Save migration test from 0.8/0.9 saves; verify settings, shift history and resume paths.
|
- [ ] Produce a release-candidate build with the tutorial, campaign, all three venues, Help,
|
||||||
- [ ] Release engineering: signed/notarized macOS where possible, checksums, Windows/Linux install
|
accessibility settings and checkpoint/resume enabled.
|
||||||
smoke tests, AppImage update, Web hosting verification and Desktop HQ Vulkan fallback.
|
- [ ] Run at least five first-time-player sessions covering the tutorial and one full venue shift;
|
||||||
- [ ] Legal/credits review: AI-assisted asset provenance, music/SFX licenses, privacy/body-camera
|
record where players get stuck, misunderstand evidence or choose disproportionate escalation.
|
||||||
language, age/content rating and storefront requirements.
|
- [ ] Triage findings by severity (P0/P1/P2) and fix every P0/P1 onboarding/accessibility issue;
|
||||||
- [ ] Documentation sign-off: architecture/ADR/status/TODO/changelog/README/smoke checklist all
|
keep the rest as explicit known limitations or post-1.0 items.
|
||||||
match the release candidate; capture final gallery and run compare + judge.
|
- [ ] Re-run the affected tutorial/campaign smokes after each fix and capture a fresh first-hour
|
||||||
- [ ] Exit: release candidate passes the manual smoke checklist on every target; no release-blocking
|
walkthrough for the release notes.
|
||||||
legal or platform issue remains.
|
|
||||||
|
### Balance and fairness pass
|
||||||
|
|
||||||
|
- [ ] Define measurable targets for routine compliance, access-decision accuracy, peaceful
|
||||||
|
resolution, justified emergency calls and false-positive/false-negative rates.
|
||||||
|
- [ ] Run scripted venue sweeps across easy/normal/hard and all four phases; compare outcomes and
|
||||||
|
tune event weights, reaction tables, compliance and report strictness where targets fail.
|
||||||
|
- [ ] Review emergency calls against actual danger: no routine behavior should make emergency the
|
||||||
|
dominant winning move, and genuine threats must remain answerable.
|
||||||
|
- [ ] Verify the reputation grades, debrief explanations and campaign progression still communicate
|
||||||
|
the de-escalation-first design after tuning.
|
||||||
|
- [ ] Record the balance evidence and any deliberate exceptions in `docs/development-status.md`
|
||||||
|
or `MEMORY.md`.
|
||||||
|
|
||||||
|
### Save migration and session reliability
|
||||||
|
|
||||||
|
- [ ] Add fixtures for a 0.8-era settings/campaign/history save and a 0.9.0 checkpoint; verify
|
||||||
|
migration/default-filling and a clean first launch with no files.
|
||||||
|
- [ ] Test fresh install → tutorial → campaign → pause → quit → resume → review → next venue on
|
||||||
|
an isolated user-data directory.
|
||||||
|
- [ ] Test corrupt JSON, partial temp files, missing optional fields and a failed atomic rename;
|
||||||
|
confirm fallback behavior never destroys a valid save.
|
||||||
|
- [ ] Verify checkpoint resume after all three venues, after an incident, with NPCs at the door and
|
||||||
|
with flashlight/body-camera/door state set.
|
||||||
|
- [ ] Document save locations, schema versions, reset behavior and rollback/export instructions in
|
||||||
|
`docs/getting-started.md` and the release notes.
|
||||||
|
|
||||||
|
### Release engineering and distribution
|
||||||
|
|
||||||
|
- [ ] Run `tools/build_releases.sh` from a clean checkout and verify Linux/Windows/macOS/Web/HQ
|
||||||
|
artifact names, sizes and checksums.
|
||||||
|
- [ ] Smoke-test fresh Linux portable/AppImage, Windows portable/installer, macOS unzip/launch,
|
||||||
|
Web static hosting and Desktop HQ Vulkan fallback on the target matrix.
|
||||||
|
- [ ] Add a disk-space preflight and retention policy to the release/publish scripts so a full
|
||||||
|
Gitea host cannot leave a partially uploaded release.
|
||||||
|
- [ ] Verify release metadata, tag/version consistency, asset counts and download links; retain
|
||||||
|
at least the latest 0.8/0.9 releases and document older-asset pruning.
|
||||||
|
- [ ] Decide and document whether macOS signing/notarization is required for 0.9.5 or explicitly
|
||||||
|
remains a 1.0 blocker; record the quarantine instructions either way.
|
||||||
|
|
||||||
|
### Legal, credits and platform policy
|
||||||
|
|
||||||
|
- [ ] Audit AI-assisted asset provenance and licenses; record source/model usage and any
|
||||||
|
redistribution constraints for textures, characters, props and UI art.
|
||||||
|
- [ ] Audit audio/SFX/music licensing (or confirm everything is procedural) and add a credits file.
|
||||||
|
- [ ] Review body-camera/privacy language, mental-health-crisis representation, age/content rating
|
||||||
|
and storefront requirements; fix any release-blocking copy or content.
|
||||||
|
- [ ] Add the player-facing credits, known limitations, accessibility statement and privacy note to
|
||||||
|
the release package/README.
|
||||||
|
- [ ] Mark external legal/storefront approval as complete or explicitly block 1.0 on it.
|
||||||
|
|
||||||
|
### Documentation and visual sign-off
|
||||||
|
|
||||||
|
- [ ] Update `README.md`, `PLAN.md`, `docs/architecture.md`, ADRs, `docs/development-status.md`,
|
||||||
|
`docs/getting-started.md`, `docs/smoke-checklist.md`, `CHANGELOG.md` and this roadmap.
|
||||||
|
- [ ] Regenerate the full screenshot gallery and realism baselines after content lock; run
|
||||||
|
`check_screenshots.sh` and the pinned vision judge, recording model/spend/verdicts.
|
||||||
|
- [ ] Run the manual smoke checklist on every target and attach/link the release-candidate evidence.
|
||||||
|
- [ ] Verify the tutorial/campaign/help text at maximum font scale and with the longest strings.
|
||||||
|
- [ ] Remove or archive stale plans/notes and confirm no contradictory version/status claims remain.
|
||||||
|
|
||||||
|
### Release-candidate QA and exit
|
||||||
|
|
||||||
|
- [ ] Run the complete headless suite, Python tooling, tutorial/campaign/session/scenario smokes,
|
||||||
|
24-NPC budget smoke and release build from a clean checkout.
|
||||||
|
- [ ] Run the manual QA matrix: fresh install, upgrade, offline launch, gamepad, accessibility
|
||||||
|
settings, pause/resume, all venues and Desktop HQ fallback.
|
||||||
|
- [ ] Confirm no P0/P1 defects remain; P2 items must be documented as known limitations or
|
||||||
|
post-1.0 work.
|
||||||
|
- [ ] Create the `v0.9.5` version bump, changelog entry and tag; build/publish the release and
|
||||||
|
verify all assets and download links.
|
||||||
|
- [ ] Exit: the release candidate is content-locked, externally played, legally reviewed,
|
||||||
|
documented, reproducibly built, and approved as the final stepping stone to 1.0.0.
|
||||||
|
|
||||||
## Milestone 1.0.0 — Launch
|
## Milestone 1.0.0 — Launch
|
||||||
|
|
||||||
|
|||||||
+9
-9
@@ -12,11 +12,11 @@ time you export, either:
|
|||||||
matching templates), or
|
matching templates), or
|
||||||
- Install them manually from the
|
- Install them manually from the
|
||||||
[Godot downloads](https://godotengine.org/download/) page by placing the
|
[Godot downloads](https://godotengine.org/download/) page by placing the
|
||||||
`Godot_v4.3-stable_export_templates.tpz` contents into
|
`Godot_v4.7.2-stable_export_templates.tpz` contents into
|
||||||
`~/.local/share/godot/export_templates/4.3.stable/`.
|
`~/.local/share/godot/export_templates/4.7.2.stable/`.
|
||||||
|
|
||||||
The templates must match the editor binary you use locally. CI pins Godot 4.3;
|
The templates must match the editor binary you use locally. CI and local
|
||||||
the local development machine uses 4.7.2 with its matching templates. Verify with:
|
development both use Godot 4.7.2 with its matching templates. Verify with:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
godot --headless --export-release "Linux" build/gig-line-smoke.x86_64
|
godot --headless --export-release "Linux" build/gig-line-smoke.x86_64
|
||||||
@@ -31,7 +31,7 @@ godot --headless --export-release "Linux" build/gig-line-smoke.x86_64
|
|||||||
|
|
||||||
The repository ships a Gitea Actions workflow (`.gitea/workflows/build.yml`):
|
The repository ships a Gitea Actions workflow (`.gitea/workflows/build.yml`):
|
||||||
|
|
||||||
- Every push/PR runs the **checks** job: Godot 4.3 install, project import, and the
|
- Every push/PR runs the **checks** job: Godot 4.7.2 install, project import, and the
|
||||||
full headless test suite. This is the fast safety net.
|
full headless test suite. This is the fast safety net.
|
||||||
- **Tags (`v*`)** and **manual `workflow_dispatch`** runs additionally execute the
|
- **Tags (`v*`)** and **manual `workflow_dispatch`** runs additionally execute the
|
||||||
**build** job: export templates install, import, `tools/build_releases.sh` for
|
**build** job: export templates install, import, `tools/build_releases.sh` for
|
||||||
@@ -63,10 +63,10 @@ setup, so do not rely on it.
|
|||||||
> artifacts. If CI publishing fails again, run
|
> artifacts. If CI publishing fails again, run
|
||||||
> `./tools/publish_release.sh <version>` from a checkout with `~/.git-credentials`.
|
> `./tools/publish_release.sh <version>` from a checkout with `~/.git-credentials`.
|
||||||
|
|
||||||
> **No `actions/cache` for now:** the runner has no local actions-cache service, so
|
> **Godot cache:** the workflow uses Gitea Actions cache for the Godot binary and the
|
||||||
> `actions/cache` times out against GitHub's cache API. We dropped it (Godot import
|
> 4.7.2 export templates. The first run still downloads them; subsequent runs restore
|
||||||
> is only ~4s). If a host admin later enables Gitea `[cache.actions]` with a cache
|
> from cache. If the host cache service is unavailable, remove the cache steps and
|
||||||
> server, the step can be reintroduced.
|
> let the install steps download fresh copies.
|
||||||
|
|
||||||
> The workflow lives in `.gitea/workflows/` (Gitea's canonical path). The old
|
> The workflow lives in `.gitea/workflows/` (Gitea's canonical path). The old
|
||||||
> `.github/workflows/ci.yml` was removed to avoid double runs on hosts that scan
|
> `.github/workflows/ci.yml` was removed to avoid double runs on hosts that scan
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ This document follows the structure of the arc42 architecture documentation temp
|
|||||||
## 2. Constraints
|
## 2. Constraints
|
||||||
|
|
||||||
- The first implementation should be small enough for a playable vertical slice.
|
- The first implementation should be small enough for a playable vertical slice.
|
||||||
- The engine is Godot 4 with GDScript; a playable prototype vertical slice is implemented. CI pins Godot 4.3 while local development is verified with 4.7.2; the default renderer stays GL Compatibility for Web parity, with an optional Forward+ Desktop HQ build.
|
- The engine is Godot 4.7.2 with GDScript; a playable prototype vertical slice is implemented. CI, local development and exported builds use 4.7.2; the default renderer stays GL Compatibility for Web parity, with an optional Forward+ Desktop HQ build.
|
||||||
- Venue-specific policies must be configurable rather than hard-coded into individual NPCs.
|
- Venue-specific policies must be configurable rather than hard-coded into individual NPCs.
|
||||||
- The game must preserve the de-escalation-first design described in [`PLAN.md`](../PLAN.md).
|
- The game must preserve the de-escalation-first design described in [`PLAN.md`](../PLAN.md).
|
||||||
- The project uses the repository workflow described in [`AGENTS.md`](../AGENTS.md).
|
- The project uses the repository workflow described in [`AGENTS.md`](../AGENTS.md).
|
||||||
@@ -37,7 +37,7 @@ This document follows the structure of the arc42 architecture documentation temp
|
|||||||
- **MINOR** — new venues, NPC archetypes, systems, or features that are backward compatible.
|
- **MINOR** — new venues, NPC archetypes, systems, or features that are backward compatible.
|
||||||
- **PATCH** — bug fixes and small polish that do not change behavior.
|
- **PATCH** — bug fixes and small polish that do not change behavior.
|
||||||
|
|
||||||
The single source of truth for the version is `config/version` in `project.godot` (currently `0.8.1`). Each release is tagged in git as `v<version>` (e.g. `v0.6.0`). The `0.x` series is pre-1.0, so MINOR bumps may introduce breaking changes while the prototype is still stabilizing. `tools/build_releases.sh` and `tools/publish_release.sh` read the version from `project.godot`, so bumping it there is the only required step before a release. The full bump checklist lives in [`RELEASING.md`](RELEASING.md).
|
The single source of truth for the version is `config/version` in `project.godot` (currently `0.9.1`). Each release is tagged in git as `v<version>` (e.g. `v0.6.0`). The `0.x` series is pre-1.0, so MINOR bumps may introduce breaking changes while the prototype is still stabilizing. `tools/build_releases.sh` and `tools/publish_release.sh` read the version from `project.godot`, so bumping it there is the only required step before a release. The full bump checklist lives in [`RELEASING.md`](RELEASING.md).
|
||||||
|
|
||||||
## 3. Context and Scope
|
## 3. Context and Scope
|
||||||
|
|
||||||
@@ -180,7 +180,7 @@ reputation, crowd reaction and shift review read it rather than resolving gamepl
|
|||||||
|
|
||||||
## 7. Deployment View
|
## 7. Deployment View
|
||||||
|
|
||||||
The game is a single-player local client containing presentation, simulation, rules, content, and persistence for local settings and shift results. No online backend is required. A non-threaded Web export ships alongside the desktop builds and can be served from any static host without special headers. The default renderer is GL Compatibility; an optional Desktop HQ zip uses Forward+ with volumetric fog/SDFGI on Vulkan-capable desktops. CI pins Godot 4.3 while local development is verified with 4.7.2, so the light falloff path is version-adaptive until the baseline is unified.
|
The game is a single-player local client containing presentation, simulation, rules, content, and persistence for local settings and shift results. No online backend is required. A non-threaded Web export ships alongside the desktop builds and can be served from any static host without special headers. The default renderer is GL Compatibility; an optional Desktop HQ zip uses Forward+ with volumetric fog/SDFGI on Vulkan-capable desktops. CI, local development and exported builds use Godot 4.7.2; the light-falloff code keeps a compatibility branch for older editors but the supported baseline is unified.
|
||||||
|
|
||||||
Future options include external analytics, cloud saves, or replay sharing, but they are not part of the current architecture.
|
Future options include external analytics, cloud saves, or replay sharing, but they are not part of the current architecture.
|
||||||
|
|
||||||
@@ -188,7 +188,7 @@ Future options include external analytics, cloud saves, or replay sharing, but t
|
|||||||
|
|
||||||
A continuous-integration pipeline keeps the headless test suite green on every change and publishes tagged releases.
|
A continuous-integration pipeline keeps the headless test suite green on every change and publishes tagged releases.
|
||||||
|
|
||||||
- **Workflow:** `.gitea/workflows/build.yml` runs on pushes, pull requests, tags, and manual dispatches. The `checks` job installs Godot 4.3, imports the project, and runs `res://src/test/test_runner.gd`; it fails on a non-zero exit code or any `SCRIPT ERROR` in the output.
|
- **Workflow:** `.gitea/workflows/build.yml` runs on pushes, pull requests, tags, and manual dispatches. The `checks` job restores/caches Godot 4.7.2, imports the project, and runs `res://src/test/test_runner.gd`; it fails on a non-zero exit code or any `SCRIPT ERROR` in the output.
|
||||||
- **Build job:** runs for tags and manual dispatches. It installs export templates, exports Linux/Windows/macOS and the non-threaded Web build, packages the NSIS installer, Linux AppImage and optional Desktop HQ zip, verifies the installer contents, and uploads the artifacts.
|
- **Build job:** runs for tags and manual dispatches. It installs export templates, exports Linux/Windows/macOS and the non-threaded Web build, packages the NSIS installer, Linux AppImage and optional Desktop HQ zip, verifies the installer contents, and uploads the artifacts.
|
||||||
- **Publish job:** tag builds call `tools/publish_release.sh` to create the Gitea release and upload the standard artifacts plus the optional Desktop HQ zip. The script uses `GITEA_TOKEN` when configured and otherwise reuses the runner's checkout extraheader credentials.
|
- **Publish job:** tag builds call `tools/publish_release.sh` to create the Gitea release and upload the standard artifacts plus the optional Desktop HQ zip. The script uses `GITEA_TOKEN` when configured and otherwise reuses the runner's checkout extraheader credentials.
|
||||||
- **Hosting:** the repository lives on Gitea (`https://git.allucanget.biz/zwitschi/security-game`). Export templates must match the pinned Godot version; macOS builds are unsigned and need quarantine guidance or notarization for wider distribution.
|
- **Hosting:** the repository lives on Gitea (`https://git.allucanget.biz/zwitschi/security-game`). Export templates must match the pinned Godot version; macOS builds are unsigned and need quarantine guidance or notarization for wider distribution.
|
||||||
@@ -219,6 +219,7 @@ The release process is: bump the version, run the full test suite and `tools/che
|
|||||||
- **Asset provenance and AI usage:** AI-assisted images/concepts are development inputs only; validated outputs are committed, audited and loaded through the same runtime asset contracts. Generated content must not become an offline/CI dependency.
|
- **Asset provenance and AI usage:** AI-assisted images/concepts are development inputs only; validated outputs are committed, audited and loaded through the same runtime asset contracts. Generated content must not become an offline/CI dependency.
|
||||||
- **Campaign and checkpoint state:** `Campaign` owns venue order/progression; settings, campaign, completed shift history and a versioned pause checkpoint are separate JSON documents. The checkpoint snapshots coordinator systems, scheduler RNG and NPC presentation/access state; it deliberately does not serialize the tutorial overlay or transient input state.
|
- **Campaign and checkpoint state:** `Campaign` owns venue order/progression; settings, campaign, completed shift history and a versioned pause checkpoint are separate JSON documents. The checkpoint snapshots coordinator systems, scheduler RNG and NPC presentation/access state; it deliberately does not serialize the tutorial overlay or transient input state.
|
||||||
- **Difficulty:** easy/normal/hard only scale spawn pacing, NPC compliance tolerance and report-credibility strictness; access/escalation rules and emergency rarity are invariant.
|
- **Difficulty:** easy/normal/hard only scale spawn pacing, NPC compliance tolerance and report-credibility strictness; access/escalation rules and emergency rarity are invariant.
|
||||||
|
- **Settings and accessibility:** volume/motion/caption settings persist through `settings.json`; Help is generated from the input-binding catalogue and the HUD log is the text caption surface. CI/release, local development and exported builds are unified on Godot 4.7.2.
|
||||||
- **Documentation ownership:** `PLAN.md` owns design intent; `docs/gameplay.md` owns playable mechanics; `docs/architecture.md` owns system boundaries, data flow, constraints and cross-cutting decisions; ADRs own decision history; `docs/development-status.md` owns the implemented/gap list; `TODO.md` owns the roadmap; `MEMORY.md` owns gotchas and open questions. Specialized docs link to these rather than becoming competing sources of truth.
|
- **Documentation ownership:** `PLAN.md` owns design intent; `docs/gameplay.md` owns playable mechanics; `docs/architecture.md` owns system boundaries, data flow, constraints and cross-cutting decisions; ADRs own decision history; `docs/development-status.md` owns the implemented/gap list; `TODO.md` owns the roadmap; `MEMORY.md` owns gotchas and open questions. Specialized docs link to these rather than becoming competing sources of truth.
|
||||||
|
|
||||||
## 9. Architecture Decisions
|
## 9. Architecture Decisions
|
||||||
@@ -263,7 +264,7 @@ Architecture decisions are recorded as ADRs:
|
|||||||
- Mental-health-crisis scenarios require careful writing, playtesting, and respectful presentation.
|
- Mental-health-crisis scenarios require careful writing, playtesting, and respectful presentation.
|
||||||
- The choice of engine may affect navigation, crowd scale, tooling, and content authoring.
|
- The choice of engine may affect navigation, crowd scale, tooling, and content authoring.
|
||||||
- Reference mockups can outpace the runtime art style; compare/judge catch gross drift but not composition errors, so the staged gallery needs human review after large visual changes.
|
- Reference mockups can outpace the runtime art style; compare/judge catch gross drift but not composition errors, so the staged gallery needs human review after large visual changes.
|
||||||
- Godot version skew (CI 4.3 vs local 4.7.2) can change lighting, import sidecars and generated UIDs; a single supported version and a visual smoke matrix are required before 1.0.
|
- Godot 4.7.2 is the unified CI/local/project baseline; future engine bumps still require import, visual and export smoke checks before changing that baseline.
|
||||||
- Content volume and authoring tools are still thin; adding venues/events by editing the factory can become error-prone without schema validation and preview tooling.
|
- Content volume and authoring tools are still thin; adding venues/events by editing the factory can become error-prone without schema validation and preview tooling.
|
||||||
- Save data currently covers settings and shift history, not mid-shift resume; adding saves/replays requires a versioned schema and migration policy.
|
- Save data currently covers settings and shift history, not mid-shift resume; adding saves/replays requires a versioned schema and migration policy.
|
||||||
- The optional judge and image-generation paths depend on an external key, model availability and budget; CI cannot make them a release gate, and keys must never be committed.
|
- The optional judge and image-generation paths depend on an external key, model availability and budget; CI cannot make them a release gate, and keys must never be committed.
|
||||||
|
|||||||
@@ -2,10 +2,10 @@
|
|||||||
|
|
||||||
Implemented so far:
|
Implemented so far:
|
||||||
|
|
||||||
- Godot 4.3 project scaffold, input map, procedural world builder
|
- Godot 4.7.2 project scaffold, input map, procedural world builder (CI/local/release unified)
|
||||||
- Venue-driven simulation core: `ShiftCoordinator`, `VenueScenario`, `EventScheduler`, `NPCController` + FSM, `AccessVerifier`, `EscalationManager`, `RadioSystem`, `IncidentRecorder`, `ReputationEvaluator`, `CrowdSystem`
|
- Venue-driven simulation core: `ShiftCoordinator`, `VenueScenario`, `EventScheduler`, `NPCController` + FSM, `AccessVerifier`, `EscalationManager`, `RadioSystem`, `IncidentRecorder`, `ReputationEvaluator`, `CrowdSystem`
|
||||||
- Three authored scenarios (Hollywood Boulevard building, The Joke Shop, Late Night TV Studio) with access policies, NPC archetypes, and event pools
|
- Three authored scenarios (Hollywood Boulevard building, The Joke Shop, Late Night TV Studio) with access policies, NPC archetypes, and event pools
|
||||||
- Headless unit tests: **249 passing** (access rules and venue-correct access loadout, escalation, radio cooldown/battery, NPC reaction determinism, door lock, flashlight perception, persistence round-trip, settings round-trip, input remaps, navmesh, step colliders, skyline alpha, scenario data, full-shift simulation, wand screening, responder dispatch, localization strings, focus cone, action wheel, session shell, PLAN verbs and incident recording, crowd presentation, emergency aftermath, body-camera timeline, NPC theater poses, audio, accessibility, authored scenario content, string formatting, `.tres` venue round-trip, surface materials and environment, focus ranking and outfit/gait helpers, generated prop models, web export preset, prop atlas material, player movement, NPC character layers/LOD/queue, input bindings)
|
- Headless unit tests: **250 passing** (access rules and venue-correct access loadout, escalation, radio cooldown/battery, NPC reaction determinism, door lock, flashlight perception, persistence round-trip, settings round-trip, input remaps, navmesh, step colliders, skyline alpha, scenario data, full-shift simulation, wand screening, responder dispatch, localization strings, focus cone, action wheel, session shell, PLAN verbs and incident recording, crowd presentation, emergency aftermath, body-camera timeline, NPC theater poses, audio, accessibility, authored scenario content, string formatting, `.tres` venue round-trip, surface materials and environment, focus ranking and outfit/gait helpers, generated prop models, web export preset, prop atlas material, player movement, NPC character layers/LOD/queue, input bindings)
|
||||||
- Simulation extras: protester archetype, CALL_SOMEONE reaction, door lock/secure mechanic (visual indicator), flashlight with night perception bonus, LATE shift phase reaching the violent-threat event
|
- Simulation extras: protester archetype, CALL_SOMEONE reaction, door lock/secure mechanic (visual indicator), flashlight with night perception bonus, LATE shift phase reaching the violent-threat event
|
||||||
- First-person prototype with interaction HUD, access inspection, wand screening, radio report form (incl. emergency hold-to-confirm), dispatched responder avatars, aim-free targeting, venue cycling between all three scenarios, color-coded escalation feedback, procedural audio cues, navigation-mesh NPC paths, JSON-backed localized strings, persisted shift history, debug overlay, and shift review
|
- First-person prototype with interaction HUD, access inspection, wand screening, radio report form (incl. emergency hold-to-confirm), dispatched responder avatars, aim-free targeting, venue cycling between all three scenarios, color-coded escalation feedback, procedural audio cues, navigation-mesh NPC paths, JSON-backed localized strings, persisted shift history, debug overlay, and shift review
|
||||||
- Control pass: focus cone on NPC heads with a billboarded blue circle in front of the face and name, action wheel (LMB/Space) with de-escalation-first slices, mouse-look freeze while a panel is open, acceleration-based walking, and named input actions (`action_menu`, `confirm`, `cancel`, `inspect`, `wand`)
|
- Control pass: focus cone on NPC heads with a billboarded blue circle in front of the face and name, action wheel (LMB/Space) with de-escalation-first slices, mouse-look freeze while a panel is open, acceleration-based walking, and named input actions (`action_menu`, `confirm`, `cancel`, `inspect`, `wand`)
|
||||||
@@ -41,6 +41,7 @@ Implemented so far:
|
|||||||
- Visual alignment: start/venue menu, pause, settings, shift review, radio, wand, inspection, timeline, HUD target chip/escalation bar, and radial menu now use or match their AI references in `assets/images/ui/`. The runtime art loader (`src/game/ui/art.gd`) falls back cleanly when a file is missing.
|
- Visual alignment: start/venue menu, pause, settings, shift review, radio, wand, inspection, timeline, HUD target chip/escalation bar, and radial menu now use or match their AI references in `assets/images/ui/`. The runtime art loader (`src/game/ui/art.gd`) falls back cleanly when a file is missing.
|
||||||
- Realism adoption (post-v0.6.0): v2 per-phase skylines and surface tiles with normal maps, retuned sun/exposure/fog, wet asphalt, denser foliage, a visible additive flashlight beam, and refreshed staging captures. `tools/check_screenshots.sh` is the repeatable capture/compare gate; judge is clean of `diff` verdicts.
|
- Realism adoption (post-v0.6.0): v2 per-phase skylines and surface tiles with normal maps, retuned sun/exposure/fog, wet asphalt, denser foliage, a visible additive flashlight beam, and refreshed staging captures. `tools/check_screenshots.sh` is the repeatable capture/compare gate; judge is clean of `diff` verdicts.
|
||||||
- Input/reliability fixes: selecting a venue releases the start-menu input lock and recaptures the mouse; the body-camera overlay no longer covers the shift status. Mouse look now reads at `_input`, restores capture on window focus/click-back, and the HUD is mouse-transparent. Normal radio reports submit on click; emergency calls still require the hold-to-confirm path.
|
- Input/reliability fixes: selecting a venue releases the start-menu input lock and recaptures the mouse; the body-camera overlay no longer covers the shift status. Mouse look now reads at `_input`, restores capture on window focus/click-back, and the HUD is mouse-transparent. Normal radio reports submit on click; emergency calls still require the hold-to-confirm path.
|
||||||
|
- Production-quality pass (v0.9.0): mixer/accessibility settings, audio volume clamping, 24-NPC budget smoke, shortened coat/dress stride, and a unified Godot 4.7.2 CI/local support baseline with documented upgrade/rollback requirements.
|
||||||
- Campaign and first-hour pass (v0.8.0): campaign progression, checkpoint resume, difficulty presets, a searchable Help overlay, recovery events, contextual dialogue, policy/debrief lines and tutorial/replay/skip. Scripted QA bypasses the tutorial unless `--tutorial` is passed.
|
- Campaign and first-hour pass (v0.8.0): campaign progression, checkpoint resume, difficulty presets, a searchable Help overlay, recovery events, contextual dialogue, policy/debrief lines and tutorial/replay/skip. Scripted QA bypasses the tutorial unless `--tutorial` is passed.
|
||||||
- Tutorial pass (0.8.0 work): the eight-beat first shift is wired through a non-blocking prompt overlay, a safe compliant visitor, real wheel/inspection/warning/radio panels, persisted completion/skip and a Settings replay action. Scripted tests/captures bypass it unless `--tutorial` is passed; `smoke_tutorial.gd` covers the full flow.
|
- Tutorial pass (0.8.0 work): the eight-beat first shift is wired through a non-blocking prompt overlay, a safe compliant visitor, real wheel/inspection/warning/radio panels, persisted completion/skip and a Settings replay action. Scripted tests/captures bypass it unless `--tutorial` is passed; `smoke_tutorial.gd` covers the full flow.
|
||||||
- Vision judge (v0.7.2): discovers the cheapest current OpenRouter image+JSON model, reports the model/fallbacks used, and clears the full screen-design judge (13/13 match, 0 diff).
|
- Vision judge (v0.7.2): discovers the cheapest current OpenRouter image+JSON model, reports the model/fallbacks used, and clears the full screen-design judge (13/13 match, 0 diff).
|
||||||
|
|||||||
+1
-1
@@ -4,7 +4,7 @@ The complete design rationale also lives in [`PLAN.md`](../PLAN.md); this page k
|
|||||||
|
|
||||||
## Game Overview
|
## Game Overview
|
||||||
|
|
||||||
A typical shift lasts 10–15 minutes. The player:
|
A typical shift lasts 10–15 minutes. The first-person camera stays at the gameplay height of 1.7 m; the concept frames use a lower ~1.55 m reference camera, but gameplay readability and body-camera framing take priority. The player:
|
||||||
|
|
||||||
1. Watches the entrance, steps, queue, and surrounding sidewalk.
|
1. Watches the entrance, steps, queue, and surrounding sidewalk.
|
||||||
2. Determines why each person is approaching.
|
2. Determines why each person is approaching.
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
## Setup
|
## Setup
|
||||||
|
|
||||||
1. Download the Godot 4.3+ editor (official build) and put `godot` on your PATH. CI pins 4.3; local development is verified with 4.7.2.
|
1. Download Godot **4.7.2** (official build) and put `godot` on your PATH. The project, local tooling and CI use the same version; engine upgrades require import, headless, screenshot and Desktop HQ smoke checks before changing the baseline.
|
||||||
2. Open or run the project from this directory.
|
2. Open or run the project from this directory.
|
||||||
|
|
||||||
## Run and Test
|
## Run and Test
|
||||||
@@ -38,7 +38,7 @@ godot --headless --path . --script res://src/test/smoke_plan_verbs.gd
|
|||||||
# Prop-collision smoke (windowed): guard stops at a bench, guest routes around it
|
# Prop-collision smoke (windowed): guard stops at a bench, guest routes around it
|
||||||
godot --path . --script res://src/test/smoke_props.gd
|
godot --path . --script res://src/test/smoke_props.gd
|
||||||
|
|
||||||
# NPC budget smoke: 16 full-rig avatars against the documented frame budget
|
# NPC budget smoke: 24 full-rig avatars against the documented frame budget
|
||||||
godot --headless --path . --script res://src/test/smoke_npc_budget.gd
|
godot --headless --path . --script res://src/test/smoke_npc_budget.gd
|
||||||
|
|
||||||
# Movement smoke (windowed): steps, precision walk, footsteps and landing
|
# Movement smoke (windowed): steps, precision walk, footsteps and landing
|
||||||
|
|||||||
@@ -37,3 +37,6 @@
|
|||||||
35. Pausing saves a checkpoint: returning to the menu and choosing Continue resumes elapsed time, NPCs, incidents, door/flashlight state and campaign position.
|
35. Pausing saves a checkpoint: returning to the menu and choosing Continue resumes elapsed time, NPCs, incidents, door/flashlight state and campaign position.
|
||||||
36. Settings difficulty changes spawn pacing/compliance/report strictness while escalation rules stay the same; Help filters controls and shows the venue policy.
|
36. Settings difficulty changes spawn pacing/compliance/report strictness while escalation rules stay the same; Help filters controls and shows the venue policy.
|
||||||
37. The F debug overlay lists the next eligible events; recovery events and recently played scripted events behave as authored.
|
37. The F debug overlay lists the next eligible events; recovery events and recently played scripted events behave as authored.
|
||||||
|
38. Master/SFX/ambience volume settings clamp at 0/1 and persist; Reduce motion disables head bob; the captions toggle persists.
|
||||||
|
39. The 24-NPC budget smoke stays inside its frame budget; coats/dresses do not show obvious leg clipping in a normal walk.
|
||||||
|
40. Help remains readable with the largest HUD font scale, and CI/local verification use the same Godot 4.7.2 baseline.
|
||||||
+2
-2
@@ -12,9 +12,9 @@ config_version=5
|
|||||||
|
|
||||||
config/name="Gig Line"
|
config/name="Gig Line"
|
||||||
config/description="Workplace security simulation about observation, access verification, and proportionate escalation."
|
config/description="Workplace security simulation about observation, access verification, and proportionate escalation."
|
||||||
config/version="0.8.1"
|
config/version="0.9.1"
|
||||||
run/main_scene="res://scenes/main.tscn"
|
run/main_scene="res://scenes/main.tscn"
|
||||||
config/features=PackedStringArray("4.3", "GL Compatibility")
|
config/features=PackedStringArray("4.7", "GL Compatibility")
|
||||||
|
|
||||||
[autoload]
|
[autoload]
|
||||||
|
|
||||||
|
|||||||
@@ -78,6 +78,11 @@ const DEFAULT_SETTINGS := {
|
|||||||
"ai_difficulty": "normal",
|
"ai_difficulty": "normal",
|
||||||
"tutorial_completed": false,
|
"tutorial_completed": false,
|
||||||
"tutorial_skipped": false,
|
"tutorial_skipped": false,
|
||||||
|
"master_volume": 1.0,
|
||||||
|
"sfx_volume": 1.0,
|
||||||
|
"ambience_volume": 1.0,
|
||||||
|
"reduce_motion": false,
|
||||||
|
"captions_enabled": true,
|
||||||
}
|
}
|
||||||
|
|
||||||
## Load player settings, merged over the defaults. Returns a Dictionary.
|
## Load player settings, merged over the defaults. Returns a Dictionary.
|
||||||
|
|||||||
@@ -16,6 +16,23 @@ var radio_crackles := 0
|
|||||||
var footsteps := 0
|
var footsteps := 0
|
||||||
var landings := 0
|
var landings := 0
|
||||||
var precision_ticks := 0
|
var precision_ticks := 0
|
||||||
|
var master_volume := 1.0
|
||||||
|
var sfx_volume := 1.0
|
||||||
|
var ambience_volume := 1.0
|
||||||
|
var _master_db := 0.0
|
||||||
|
var _sfx_db := 0.0
|
||||||
|
var _ambience_db := 0.0
|
||||||
|
|
||||||
|
## 0..1 mixer controls from Settings. Headless/no-audio builds just store them.
|
||||||
|
func set_volumes(master: float, sfx: float, ambience: float) -> void:
|
||||||
|
master_volume = clampf(master, 0.0, 1.0)
|
||||||
|
sfx_volume = clampf(sfx, 0.0, 1.0)
|
||||||
|
ambience_volume = clampf(ambience, 0.0, 1.0)
|
||||||
|
_master_db = linear_to_db(maxf(master_volume, 0.0001))
|
||||||
|
_sfx_db = linear_to_db(maxf(sfx_volume, 0.0001))
|
||||||
|
_ambience_db = linear_to_db(maxf(ambience_volume, 0.0001))
|
||||||
|
if _bed_player:
|
||||||
|
_bed_player.volume_db = _level_to_db(crowd_level) + _master_db + _ambience_db + _master_db + _ambience_db + _master_db + _ambience_db
|
||||||
|
|
||||||
func _ready() -> void:
|
func _ready() -> void:
|
||||||
# Pre-create a few players so overlapping cues don't cut each other off.
|
# Pre-create a few players so overlapping cues don't cut each other off.
|
||||||
@@ -112,7 +129,7 @@ func _play_tone(freq: float, duration: float, volume: float, delay: float = 0.0)
|
|||||||
stream.mix_rate = SAMPLE_RATE
|
stream.mix_rate = SAMPLE_RATE
|
||||||
stream.buffer_length = duration + 0.05
|
stream.buffer_length = duration + 0.05
|
||||||
player.stream = stream
|
player.stream = stream
|
||||||
player.volume_db = linear_to_db(volume)
|
player.volume_db = linear_to_db(volume) + _master_db + _sfx_db
|
||||||
player.play()
|
player.play()
|
||||||
# Fill the generator buffer with a sine wave.
|
# Fill the generator buffer with a sine wave.
|
||||||
var playback: AudioStreamGeneratorPlayback = player.get_stream_playback()
|
var playback: AudioStreamGeneratorPlayback = player.get_stream_playback()
|
||||||
@@ -174,7 +191,7 @@ func _play_noise(duration: float, volume: float, cutoff_hz: float = 3200.0) -> v
|
|||||||
stream.stereo = false
|
stream.stereo = false
|
||||||
stream.data = data
|
stream.data = data
|
||||||
player.stream = stream
|
player.stream = stream
|
||||||
player.volume_db = linear_to_db(volume)
|
player.volume_db = linear_to_db(volume) + _master_db + _sfx_db
|
||||||
player.play()
|
player.play()
|
||||||
|
|
||||||
func _free_player() -> AudioStreamPlayer:
|
func _free_player() -> AudioStreamPlayer:
|
||||||
|
|||||||
@@ -377,7 +377,10 @@ func _apply_settings(settings: Dictionary) -> void:
|
|||||||
if guard:
|
if guard:
|
||||||
guard.look_sensitivity = float(settings.get("look_sensitivity", 0.0022))
|
guard.look_sensitivity = float(settings.get("look_sensitivity", 0.0022))
|
||||||
guard.invert_y = bool(settings.get("invert_y", false))
|
guard.invert_y = bool(settings.get("invert_y", false))
|
||||||
guard.head_bob_enabled = bool(settings.get("head_bob", true))
|
guard.head_bob_enabled = bool(settings.get("head_bob", true)) and not bool(settings.get("reduce_motion", false))
|
||||||
|
if audio:
|
||||||
|
audio.set_volumes(float(settings.get("master_volume", 1.0)),
|
||||||
|
float(settings.get("sfx_volume", 1.0)), float(settings.get("ambience_volume", 1.0)))
|
||||||
InputBindings.apply(settings.get("input_bindings", {}))
|
InputBindings.apply(settings.get("input_bindings", {}))
|
||||||
if hud and hud.has_method("set_font_scale"):
|
if hud and hud.has_method("set_font_scale"):
|
||||||
hud.set_font_scale(float(settings.get("hud_font_scale", 1.0)))
|
hud.set_font_scale(float(settings.get("hud_font_scale", 1.0)))
|
||||||
|
|||||||
@@ -1050,7 +1050,10 @@ func _animate(delta: float) -> void:
|
|||||||
_idle_t = 0.0
|
_idle_t = 0.0
|
||||||
_bob_phase += delta * (6.0 + speed * 1.7)
|
_bob_phase += delta * (6.0 + speed * 1.7)
|
||||||
var urgency := 1.35 if reaction_mode == "flee" else 1.0
|
var urgency := 1.35 if reaction_mode == "flee" else 1.0
|
||||||
var stride := clampf(0.36 + speed * 0.10, 0.42, 0.7) * urgency
|
# Coats and skirts follow the hip/knee bones; a shorter stride keeps the
|
||||||
|
# hem from clipping through the legs during normal walking.
|
||||||
|
var hem_scale := 0.76 if character_model in ["npc_dress", "npc_coat"] else 1.0
|
||||||
|
var stride := clampf(0.36 + speed * 0.10, 0.42, 0.7) * urgency * hem_scale
|
||||||
_rig.position.y = sin(_bob_phase * 2.0) * 0.03
|
_rig.position.y = sin(_bob_phase * 2.0) * 0.03
|
||||||
_rig.position.x = 0.0
|
_rig.position.x = 0.0
|
||||||
_rig.rotation.x = sin(_bob_phase) * 0.03
|
_rig.rotation.x = sin(_bob_phase) * 0.03
|
||||||
|
|||||||
@@ -22,6 +22,11 @@ var _font_scale_value: Label = null
|
|||||||
var _invert_y: CheckButton = null
|
var _invert_y: CheckButton = null
|
||||||
var _head_bob: CheckButton = null
|
var _head_bob: CheckButton = null
|
||||||
var _difficulty: OptionButton = null
|
var _difficulty: OptionButton = null
|
||||||
|
var _master: HSlider = null
|
||||||
|
var _sfx: HSlider = null
|
||||||
|
var _ambience: HSlider = null
|
||||||
|
var _reduce_motion: CheckButton = null
|
||||||
|
var _captions: CheckButton = null
|
||||||
var _bind_buttons := {}
|
var _bind_buttons := {}
|
||||||
var _listening_action := ""
|
var _listening_action := ""
|
||||||
var settings: Dictionary = {}
|
var settings: Dictionary = {}
|
||||||
@@ -101,6 +106,27 @@ func _build() -> void:
|
|||||||
_difficulty.item_selected.connect(_on_difficulty_selected)
|
_difficulty.item_selected.connect(_on_difficulty_selected)
|
||||||
diff_row.add_child(_difficulty)
|
diff_row.add_child(_difficulty)
|
||||||
|
|
||||||
|
var audio_row := HBoxContainer.new()
|
||||||
|
column.add_child(audio_row)
|
||||||
|
audio_row.add_child(_volume_label("Master volume"))
|
||||||
|
_master = _add_slider(audio_row, 0.0, 1.0, 0.05)
|
||||||
|
audio_row.add_child(_volume_label("SFX"))
|
||||||
|
_sfx = _add_slider(audio_row, 0.0, 1.0, 0.05)
|
||||||
|
audio_row.add_child(_volume_label("Ambience"))
|
||||||
|
_ambience = _add_slider(audio_row, 0.0, 1.0, 0.05)
|
||||||
|
_master.value_changed.connect(func(v): settings["master_volume"] = v)
|
||||||
|
_sfx.value_changed.connect(func(v): settings["sfx_volume"] = v)
|
||||||
|
_ambience.value_changed.connect(func(v): settings["ambience_volume"] = v)
|
||||||
|
|
||||||
|
_reduce_motion = CheckButton.new()
|
||||||
|
_reduce_motion.text = "Reduce motion"
|
||||||
|
_reduce_motion.toggled.connect(func(v): settings["reduce_motion"] = v)
|
||||||
|
column.add_child(_reduce_motion)
|
||||||
|
_captions = CheckButton.new()
|
||||||
|
_captions.text = "Captions / subtitles"
|
||||||
|
_captions.toggled.connect(func(v): settings["captions_enabled"] = v)
|
||||||
|
column.add_child(_captions)
|
||||||
|
|
||||||
var replay_row := HBoxContainer.new()
|
var replay_row := HBoxContainer.new()
|
||||||
replay_row.alignment = BoxContainer.ALIGNMENT_CENTER
|
replay_row.alignment = BoxContainer.ALIGNMENT_CENTER
|
||||||
column.add_child(replay_row)
|
column.add_child(replay_row)
|
||||||
@@ -165,6 +191,13 @@ func _add_label_row(parent: Control, text: String) -> Label:
|
|||||||
row.add_child(value)
|
row.add_child(value)
|
||||||
return value
|
return value
|
||||||
|
|
||||||
|
func _volume_label(text: String) -> Label:
|
||||||
|
var label := Label.new()
|
||||||
|
label.text = text
|
||||||
|
label.add_theme_font_size_override("font_size", 11)
|
||||||
|
label.custom_minimum_size = Vector2(82, 0)
|
||||||
|
return label
|
||||||
|
|
||||||
func _add_slider(parent: Control, min_v: float, max_v: float, step: float) -> HSlider:
|
func _add_slider(parent: Control, min_v: float, max_v: float, step: float) -> HSlider:
|
||||||
var slider := HSlider.new()
|
var slider := HSlider.new()
|
||||||
slider.min_value = min_v
|
slider.min_value = min_v
|
||||||
@@ -189,6 +222,16 @@ func open(current: Dictionary) -> void:
|
|||||||
if _difficulty:
|
if _difficulty:
|
||||||
var difficulty := str(settings.get("ai_difficulty", "normal"))
|
var difficulty := str(settings.get("ai_difficulty", "normal"))
|
||||||
_difficulty.select(["easy", "normal", "hard"].find(difficulty))
|
_difficulty.select(["easy", "normal", "hard"].find(difficulty))
|
||||||
|
if _master:
|
||||||
|
_master.set_value_no_signal(float(settings.get("master_volume", 1.0)))
|
||||||
|
if _sfx:
|
||||||
|
_sfx.set_value_no_signal(float(settings.get("sfx_volume", 1.0)))
|
||||||
|
if _ambience:
|
||||||
|
_ambience.set_value_no_signal(float(settings.get("ambience_volume", 1.0)))
|
||||||
|
if _reduce_motion:
|
||||||
|
_reduce_motion.set_pressed_no_signal(bool(settings.get("reduce_motion", false)))
|
||||||
|
if _captions:
|
||||||
|
_captions.set_pressed_no_signal(bool(settings.get("captions_enabled", true)))
|
||||||
_listening_action = ""
|
_listening_action = ""
|
||||||
_refresh_bind_buttons()
|
_refresh_bind_buttons()
|
||||||
_sync_labels()
|
_sync_labels()
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ extends SceneTree
|
|||||||
const NpcAvatar := preload("res://src/game/npc_avatar.gd")
|
const NpcAvatar := preload("res://src/game/npc_avatar.gd")
|
||||||
const NpcProfile := preload("res://src/core/npc_profile.gd")
|
const NpcProfile := preload("res://src/core/npc_profile.gd")
|
||||||
const Rules := preload("res://src/core/rules.gd")
|
const Rules := preload("res://src/core/rules.gd")
|
||||||
const COUNT := 16
|
const COUNT := 24
|
||||||
const WARMUP_FRAMES := 60
|
const WARMUP_FRAMES := 60
|
||||||
const SAMPLE_FRAMES := 180
|
const SAMPLE_FRAMES := 180
|
||||||
const BUDGET_MS := 50.0
|
const BUDGET_MS := 50.0
|
||||||
|
|||||||
@@ -66,6 +66,18 @@ func test_radio_crackle_methods() -> bool:
|
|||||||
audio.free()
|
audio.free()
|
||||||
return a and b
|
return a and b
|
||||||
|
|
||||||
|
func test_volume_settings_are_stored_and_applied() -> bool:
|
||||||
|
var audio: Node = AudioFeedback.new()
|
||||||
|
audio.set_volumes(0.8, 0.5, 0.2)
|
||||||
|
var a := TestUtils.check(is_equal_approx(audio.master_volume, 0.8), "master volume stores")
|
||||||
|
var b := TestUtils.check(is_equal_approx(audio.sfx_volume, 0.5), "sfx volume stores")
|
||||||
|
var c := TestUtils.check(is_equal_approx(audio.ambience_volume, 0.2), "ambience volume stores")
|
||||||
|
audio.set_volumes(3.0, -1.0, 0.5)
|
||||||
|
var d := TestUtils.check(is_equal_approx(audio.master_volume, 1.0)
|
||||||
|
and is_equal_approx(audio.sfx_volume, 0.0), "volumes clamp")
|
||||||
|
audio.free()
|
||||||
|
return a and b and c and d
|
||||||
|
|
||||||
func test_game_manager_wires_audio() -> bool:
|
func test_game_manager_wires_audio() -> bool:
|
||||||
var src := FileAccess.get_file_as_string("res://src/game/game_manager.gd")
|
var src := FileAccess.get_file_as_string("res://src/game/game_manager.gd")
|
||||||
var a := TestUtils.check(src.contains("audio.start_crowd_bed()"), "the bed starts with the shift")
|
var a := TestUtils.check(src.contains("audio.start_crowd_bed()"), "the bed starts with the shift")
|
||||||
|
|||||||
@@ -81,7 +81,9 @@ func test_settings_defaults_present() -> bool:
|
|||||||
var ok := TestUtils.check(
|
var ok := TestUtils.check(
|
||||||
defaults.has("look_sensitivity") and defaults.has("hud_font_scale")
|
defaults.has("look_sensitivity") and defaults.has("hud_font_scale")
|
||||||
and defaults.has("invert_y") and defaults.has("head_bob")
|
and defaults.has("invert_y") and defaults.has("head_bob")
|
||||||
and defaults.has("input_bindings"),
|
and defaults.has("input_bindings")
|
||||||
|
and defaults.has("master_volume") and defaults.has("sfx_volume")
|
||||||
|
and defaults.has("ambience_volume") and defaults.has("captions_enabled"),
|
||||||
"settings have documented defaults")
|
"settings have documented defaults")
|
||||||
save.free()
|
save.free()
|
||||||
return ok
|
return ok
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
# Build distributable desktop executables with the Godot export pipeline.
|
# Build distributable desktop executables with the Godot export pipeline.
|
||||||
#
|
#
|
||||||
# Requirements:
|
# Requirements:
|
||||||
# - Godot 4.3 (or the version in project.godot `config/features`) on PATH,
|
# - Godot 4.7.2 (or the version in project.godot `config/features`) on PATH,
|
||||||
# with export templates installed (see docs/RELEASING.md).
|
# with export templates installed (see docs/RELEASING.md).
|
||||||
# - Run from the repository root.
|
# - Run from the repository root.
|
||||||
#
|
#
|
||||||
|
|||||||
Reference in new issue
Block a user