Commit Graph
94 Commits
Author SHA1 Message Date
jpmschweitzer fdf82a89ff Merge remote-tracking branch 'origin/audio' 2026-02-18 11:20:16 +01:00
jpmschweitzerandClaude Opus 4.6 dd8718c762 fix(client): address PR #34 review — 8 items from Hoshe and Tyre
- Cast Variant to String via str() before passing to _on_room_change
- Clear _current_room_id on null room transition (fixes re-entry skip)
- Add push_error for failed dir creation and file writes in _save_report
- Fix docstring: tests/gauntlet-stats.json → user://dev/gauntlet-stats.json
- Namespace stats path to user://dev/ to avoid save data collision
- Replace print() with push_warning in _save_report (codebase consistency)
- Downgrade client-only wire guard from push_warning to silent return

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-18 11:06:56 +01:00
jpmschweitzerandClaude Opus 4.6 20427b9d8b feat(audio): revise Sprint 7 UI audio assets for #453
Re-generate monologue chimes (were oversized placeholders) and
fog_recognition (was silent). Fix sample rate headers on remaining
assets (192kHz→44.1kHz). All 8 UI assets now at 44.1kHz stereo,
LUFS -16 normalized, Vorbis q6, durations within D-038 spec.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-18 11:01:19 +01:00
jpmschweitzerandClaude Opus 4.6 a292674342 feat(client): add 24 gauntlet + bug report tests (#495, #496)
Replace stub F12 tests with BugReportDialog integration tests (dialog
exists, activates on action, pause/unpause, wire guard, text render
with entities/monologue/dialogue, empty snapshot edge case). Add 16
GauntletHUD tests (format_time, visibility toggle, timer lifecycle,
room change reset, personal bests record/overwrite/preserve, null room,
timer paused when hidden, finalize, session attempts, snapshot
roundtrip). Anti-tedium assertions now falsifiable against real
GameState.room_id and gauntlet_mode properties.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-18 10:53:26 +01:00
jpmschweitzerandClaude Opus 4.6 d7755698b2 feat(client): add WRONG button F12 bug report capture (#495)
F12 pauses simulation, shows modal LineEdit prompt, saves three files
to user://bug-reports/gauntlet-t{tick}-{timestamp}/: snapshot.json
(full ObserverSnapshot), render.txt (simplified client-side text
render), description.txt (tester notes + tick/room/stance metadata).
Esc cancels without saving. Double-activation guard prevents stacking.

BUG_REPORT action added to InputMapper with wire guard in SimBridge
(client-only, never sent to server). Dialog on ModalLayer (CL 30).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-18 10:53:15 +01:00
jpmschweitzerandClaude Opus 4.6 bc073c891f feat(client): add gauntlet room timer + personal bests (#496)
GauntletHUD in UILayer shows TIMER: MM:SS (PB: MM:SS). Timer starts on
room entry, resets on room change, records personal bests to
user://gauntlet-stats.json. Session summary printed on disconnect.
Hidden in non-gauntlet mode (anti-tedium guard).

Adds room_id and gauntlet_mode fields to GameState, parsed from
ObserverSnapshot. Main.gd wires update_from_state() and finalize().

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-18 10:53:05 +01:00
jpmschweitzer bb94a6581c Merge remote-tracking branch 'origin/ci' 2026-02-18 10:24:13 +01:00
jpmschweitzerandClaude Opus 4.6 4f20a996aa fix(client): address PR #30 review — 9 items from Hoshe and Tyre
- Add SimBridge._last_snapshot = null to P3 before_test() (contamination risk)
- Clarify mono.is_visible is custom property, not CanvasItem builtin
- Camera smoothing test uses approximate equality instead of exact
- Propagate inner _encode_message errors in array/dict encoding
- Add explanatory comment on int_64 encoder branch
- Document unfalsifiable gauntlet guard as intentional future-proof
- Remove loose D-053 citation from LERP_SPEED pin
- Assert FogOverlay is sibling of FogGroup under World
- Add CANVAS_MODAL=30 (ModalLayer) assertion in P3-Z04

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-18 09:46:08 +01:00
jpmschweitzerandClaude Opus 4.6 3ccac5432b fix(ci): address PR #31 review — harden cross-encoder fixture pipeline
- Fail on encode errors instead of silently writing empty .msgpack files
- Fail test on missing/empty fixture dir instead of silent skip
- Add all missing action variants (MoveSouth, MoveEast, MoveWest,
  Unpause, ToggleStanceDown, WalkAway) to GDScript fixture generator
- Add GDScript fixture staleness check to make pre-pr
- Validate repo root detection before writing outside client/
- Add file.flush() before close in headless mode
- Document fixture failure recovery in DEVOPS.md

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-18 09:45:13 +01:00
jpmschweitzerandClaude Opus 4.6 da63aa580e feat(ci): add make fixtures-client target for GDScript->Rust cross-encoder validation (#475)
Closes the bidirectional protocol compatibility loop (D-030 Layer 1):
- GDScript fixture generator (20 fixtures: inputs, boundary ticks, batch)
- Rust decoder test verifying all GDScript-encoded fixtures deserialize
- Makefile target with generation + verification in one step

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-18 02:20:24 +01:00
jpmschweitzerandClaude Opus 4.6 4648ce62bb feat(client): add 5 anti-tedium regression tests (#494)
Regression guards for Sprint 9 QA features:
- F12 bug report (2): no-crash without handler, no queued input action
  (stubs for when #495 WRONG button lands)
- Gauntlet UI hidden (3): no gauntlet nodes visible in default mode,
  no room_id/gauntlet_mode in normal snapshots, stays hidden across
  multiple ticks

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-18 02:14:46 +01:00
jpmschweitzerandClaude Opus 4.6 f82f97afcb feat(client): add 12 P3 tests — z-layer, entity lerp, Tyre additions (#493)
gdUnit4 tests covering:
- Z-layer ordering (4): floor below ysort, entities in ysort at z:0,
  fog exact z_index values (Z_FOG=900, Z_FOG_ENTITIES=950), UI layers
- Entity lerp (3): snap on first appear, moves toward target,
  converges within 0.3s at LERP_SPEED=12.0
- Tyre additions (5): recognition progress, facing rotation, lerp
  weight scaling with delta, blob removal, LERP_SPEED constant guard

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-18 02:14:42 +01:00
jpmschweitzerandClaude Opus 4.6 5820609594 feat(client): add 16 P2 tests — camera, entity alpha/color, UI (#492)
gdUnit4 tests covering:
- Camera (5): zoom default, smoothing convergence, viewport tracking,
  follow movement, no-panning lock per D-014
- Entity alpha/color (4): null visibility default, peripheral/forward
  transition, terrain object color, player color constant
- UI (7): monologue visible/hidden, interaction verbs, inventory grid,
  dialogue overlay, pause indicator, fog blob count, fog z_index

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-18 02:14:37 +01:00
jpmschweitzerandClaude Opus 4.6 1435a77dcc fix(client): fix MessagePack int_64 encoder dead code branch (#516)
The int_64 branch condition `-(1 << 63) <= value` overflowed in
GDScript's signed 64-bit arithmetic, making the branch unreachable.
Negative values beyond int_32 range were incorrectly encoded as
uint_64 (0xcf) instead of int_64 (0xd3). Replaced with `value < 0`.

Updated boundary tests BV-N15 and BV-N16 to expect correct int_64
header byte.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-18 02:14:29 +01:00
jpmschweitzer 58072bc119 Merge remote-tracking branch 'origin/client'
# Conflicts:
#	CHANGELOG.md
2026-02-18 01:57:07 +01:00
jpmschweitzerandClaude Opus 4.6 674c7147de feat(client): sync protocol to v8 — dialogue_response + Interact encoding
Bump PROTOCOL_VERSION from 7 to 8 to match server. Three changes:

1. Add dialogue_response field decoding (DialogueResponseEvent with
   line_id, text, speaker_entity_id) from server #305/D-028.

2. Fix Interact encoding: server changed PlayerAction::Interact from
   unit variant to struct variant with {target_entity_id, verb}.
   Extract _encode_action() helper to handle this consistently.

3. Update all test assertions that checked version=7 or expected
   Interact as a bare string.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-18 01:41:27 +01:00
jpmschweitzerandClaude Opus 4.6 dcb76d1221 fix(client): fix monologue duplication test using wrong poll path
test_monologue_not_duplicated_after_consumption was failing because
poll_snapshot() in test mode returns _test_snapshot() without
consuming _last_snapshot. The carry-forward logic then incorrectly
preserved the monologue. Fix: directly clear _last_snapshot to
simulate the live-mode consumption path.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-18 01:41:18 +01:00
jpmschweitzerandClaude Opus 4.6 053380103a feat(audio): add weapon aim lock and stance change audio assets for #440
Delivers final 2/6 interaction UI audio assets, completing ticket #440:
- sfx_weapon_aim_lock.ogg (0.5s, clinical targeting lock tone)
- sfx_stance_change.ogg (0.35s, soft mechanical stance toggle click)

Both insert-tech aesthetic, UI Sounds bus, non-positional. Generated
via Stable Audio Open, trimmed, LUFS-normalized, converted to ogg.
Updated docs/assets/audio/ui.md with UI-007 and UI-008 entries.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-18 01:26:27 +01:00
jpmschweitzer a5c30f0101 Merge remote-tracking branch 'origin/server' 2026-02-17 18:21:53 +01:00
jpmschweitzerandClaude Opus 4.6 9c60325c2d chore(engine): update and add msgpack fixtures for protocol v8
Update existing snapshot fixtures for protocol v8 (dialogue_response
field). Add 14 raw boundary value fixtures and 5 snapshot boundary
tick fixtures for encoding edge case coverage.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-17 17:41:40 +01:00
jpmschweitzerandClaude Opus 4.6 2ab41a0f04 fix(client): address PR #25 review — 5 critical bugs, 4 warnings, 3 suggestions
Critical fixes:
- hide_dialogue() sent PAUSE instead of UNPAUSE, permanently freezing
  simulation after every dialogue (both reviewers)
- Confrontation monologue hardcoded in GDScript constant, violating
  D-042/D-020 — moved to ui-strings.yaml as dialogue.confrontation_beat
- Walk-away WASD didn't call set_input_as_handled(), letting movement
  event propagate and potentially stepping on the same frame
- is_dialogue_active() returned _is_showing only — interaction list
  could flash during 300ms fade gap. Now includes dialogue_active state
- Removed dead _last_dialogue_id / get_dialogue_id() state (never read)

Warnings addressed:
- Audio registry now scans res://audio/ recursively (subdirs registered)
- add_bus_effect guarded against duplicate calls in tests
- int64 encoder dead code tagged KNOWN-DEFECT, filed as ticket #516
- D-073 zone crossfade stub comment clarifies Sprint 9+ deferral
- listening_focus dip documents caller tick-gate responsibility (D-069/D-071)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-17 17:33:56 +01:00
jpmschweitzerandClaude Opus 4.6 afc433be34 test(client): add boundary, P0 regression, P1 fog/entity, protocol v7 tests
MessagePack boundary tests: 41 values (25 pos + 16 neg) with encode-
only verification, roundtrip, and Rust-style unsigned decode (#470).
P0 regressions: monologue carry-forward (Bug #5), camera stability
during pause (Bug #2) (#477). P1 tests: fog shader state (4), entity
lifecycle (2), pending recognition blob (1) using FogState named
constants (#478). Protocol v7: structured dialogue options with
response_id, priority, confrontation flag, malformed skip (#435).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-17 16:35:19 +01:00
jpmschweitzerandClaude Opus 4.6 be763908b2 refactor(client): replace fog byte magic numbers with named constants
Define VIS_HIDDEN/PERIPHERAL/FORWARD and EXP_UNEXPLORED/EXPLORED/
VISIBLE in FogState. Replaces 7 magic number usages in _resize() and
update_from_state(). Provides stable assertion targets for fog tests.
Implements #476.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-17 16:35:05 +01:00
jpmschweitzerandClaude Opus 4.6 bfc699c15d feat(ui): implement dialogue pipeline — selection, walk-away, confrontation
Protocol: decode current_dialogue with structured options {text,
response_id, priority, confrontation} and npc_entity_id (#435).
Dialogue box: priority sort, max 3 visible, RichTextLabel for BBCode
italic confrontation options (D-063), 1.5s monologue beat with audio
dip before confrontation send. Walk-away: WASD triggers WalkAway
input, 300ms fade, dialogue_active flag gates movement (D-064).
Implements #435, #437, #436.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-17 16:34:55 +01:00
jpmschweitzerandClaude Opus 4.6 9e6b859cdf feat(audio): add AudioManager autoload with 5-bus architecture
D-068 bus layout (Music, Ambient, WorldSFX, PlayerActions, UISounds),
directory-scan asset registry, spatial/non-spatial playback, D-069
audio dip profiles (dialogue, confrontation, listening_focus) with
low-pass filter sweep, and D-073 zone crossfade stub. No-op fallback
when audio assets absent. Implements #255.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-17 16:34:42 +01:00
jpmschweitzerandClaude Opus 4.6 3a02fd0d2a feat(client): add camera anchor test suite
10 gdUnit4 tests verifying camera behavior: SimBridge test mode
connection, snapshot pipeline, player position extraction, camera
anchor in _ready(), smoothing disable/re-enable cycle, camera tracking
across frames, and player movement following.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-16 23:26:28 +01:00
jpmschweitzerandClaude Opus 4.6 8bf7f6e610 fix(client): entity lerp, fog shader safety, type fixes
Entity renderer: add framerate-independent position lerping so entities
slide between tiles instead of snapping. Tuned for Sprint snappiness
and Walk/Careful fluidity.

Fog shader: set ColorRect to transparent fallback so a shader load
failure doesn't paint solid white over the world. Track camera position
(not player position) so fog stays synced during smooth camera pan.
Restructure GLSL to avoid early return (some GPU drivers miscompile it).

Minor type fixes: typed Array[Vector2] in cursor_renderer tick drawing,
untyped Array in inventory_grid to avoid Godot typed-array cast issues.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-16 23:26:23 +01:00
jpmschweitzerandClaude Opus 4.6 bc875d607f fix(client): correct messagepack signed int boundary encoding
Off-by-one in all four signed int branches: upper bound used <= instead
of < (e.g., value <= 128 matched int8 instead of falling through to
uint8). Tick 128 was encoded as int8 -128, causing server deserialization
failure. Also remove stray debug prints from nil/false decode paths.

Fixes bug #4 (MessagePack encodes tick 128 as -128).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-16 23:26:13 +01:00
jpmschweitzerandClaude Opus 4.6 ee3ac75578 fix(client): add pause toggle, hold-to-move, snapshot event carry-forward
Three client input/bridge fixes:

1. Pause toggle: add UNPAUSE action and toggle logic based on
   GameState.game_time.tick_rate. Wire UNPAUSE in sim_bridge.gd.

2. Hold-to-move: replace press-event movement with polled _process()
   direction sampling. Composite diagonals via simultaneous keys
   (W+D → northeast). Client-side throttle per stance (D-053):
   Sprint=200ms, Walk=400ms, Careful=600ms, Crouch=800ms.

3. Snapshot carry-forward: when a newer snapshot overwrites an
   unconsumed one, carry forward current_monologue and current_dialogue
   so one-shot events aren't silently dropped.

Fixes bugs #5 (monologue lost on overwrite) and #6 (overwrite spam).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-16 23:26:07 +01:00
jpmschweitzerandClaude Opus 4.6 2dd1e9545d fix(client): anchor camera to player before first frame renders
Camera2D's internal smoothed_camera_pos starts at (0,0) and lerps
toward global_position, causing a visible white-screen drift on startup.
Disable position_smoothing in _ready(), snap camera to player position
from the first snapshot, then re-enable smoothing with reset_smoothing()
after the first anchored frame. Add tick guards to monologue/dialogue
consumption to prevent re-triggering when client FPS > sim tick rate.

Fixes bug #2 (camera doesn't center on player at startup).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-16 23:25:58 +01:00
jpmschweitzerandClaude Opus 4.6 be168d59ef refactor(client): rename test_protocol_v6.gd to test_protocol_bridge.gd
Version numbers in test filenames go stale every sprint. The file tests
bridge protocol features (stance, inventory, fixtures) not a specific
protocol version.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-16 01:33:53 +01:00
jpmschweitzerandClaude Opus 4.6 6d6b59c17b fix(client): address PR #24 review — 5 critical bugs, 3 warnings, 8 suggestions
Critical:
- Protocol test assertions updated v6→v7 (test_protocol_v6.gd)
- Dialogue signal connections wired (option_selected→DialogueResponse,
  dialogue_dismissed→DialogueEnd sent to server via SimBridge)
- Consume-once race fixed: _consume_dialogue() checks is_dialogue_active()
  before re-showing; dialogue_id tracking prevents re-trigger during fade
- Dialogue box responsive: _update_layout() clamps width to MAX_WIDTH_PX
  (832px) or 65% viewport, height to 20% viewport (MAX_HEIGHT_RATIO)
- Auto-pause added: SimBridge.send_input(PAUSE) on dialogue open/close

Warnings:
- Test coverage: 16 new tests in test_protocol_v7.gd (pending_recognitions
  decode, current_dialogue, GameState, SimBridge mock data, insert colors)
- queue_redraw() optimization: early return when no entities and no pings
- Fixed 200px height → responsive 20% viewport via _update_layout()

Suggestions:
- WASD detection refactored to _WALK_AWAY_ACTIONS array loop
- Button colors reference Constants.INSERT_COLOR_TEXT/HOVER/ACTIVE
- Named constants: COLOR_TRANSITION_START, SILHOUETTE_APPEAR_THRESHOLD,
  SILHOUETTE_SIZE with explanatory comments
- Bounds check: MAX_PENDING_RECOGNITIONS=64 with truncation warning
- Mock dialogue sustained across ticks (not 1-tick flash)
- COLOR_PING coupling with cursor documented as intentional
- Consume helpers extracted: _consume_monologue(), _consume_dialogue()

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-16 01:30:15 +01:00
jpmschweitzer 90a80e73df Merge remote-tracking branch 'origin/main' into client 2026-02-16 01:26:36 +01:00
jpmschweitzer 7edc513632 Merge remote-tracking branch 'origin/audio'
# Conflicts:
#	CHANGELOG.md
2026-02-16 01:25:40 +01:00
jpmschweitzerandClaude Opus 4.6 6035d2049a feat(audio): add 6 interaction UI audio assets for #440
Generated via Stable Audio Open with sonic family prompt prefixes:
- cursor_hover.ogg (insert-tech, digital click)
- weapon_aim.ogg (insert-tech, mechanical latch sketch)
- implant_open.ogg (insert-tech, neural lattice rising tone)
- fog_recognition.ogg (organic, cognitive realization chime)
- sfx_monologue_chime.ogg (insert-tech, placeholder per D-071)
- sfx_monologue_chime_urgent.ogg (insert-tech, placeholder per D-071)

All assets need duration trimming in next audio sprint (#453).
Updated docs/assets/audio/ui.md status to draft.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-16 01:22:56 +01:00
jpmschweitzerandClaude Opus 4.6 2659de0c28 feat(client): add fog entity visualization and wire Sprint 7 UI (#431, #434)
Fog entity cognitive delay rendering (D-059/D-060): sonar-style sound
pings (3 concentric rings, 1.5s fade), unrecognized grey blobs with
breathing pulse, D-033 color transition at 50% recognition progress,
±0.5 tile position drift. FogEntities node at z:950 between fog
shader and InsertOverlay.

Protocol v7 bump to match server PR #23 (pending_recognitions field).
Wires dialogue box and fog entities into game loop with mock test data.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-16 01:19:24 +01:00
jpmschweitzerandClaude Opus 4.6 2d56131221 feat(ui): add dialogue box — bottom screen, max 20% height, walk-away (#434)
D-061 compliant UI skeleton: NPC speech top, max 3 response options
below, left-aligned. Insert-styled colors (white-blue, amber hover,
green pressed). WASD walk-away fades over 300ms, no close button.
InsertOverlay (CanvasLayer 10, z-layer 6). Mock data in next commit.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-16 01:19:15 +01:00
jpmschweitzerandClaude Opus 4.6 4d8fe996fc feat(perception): add cognitive delay system for fog recognition (#423)
New CognitiveDelay component buffers perception events before emitting
KnowledgeEvents. Normal delay: 6 ticks (0.6s), urgent: 3 ticks (0.3s).
Drain system runs after emit_observation_events, before process_knowledge_events.

Adds pending_recognitions to ObserverSnapshot (protocol v7) for client
fog entity visualization. Includes cancellation when entity leaves LOS.

Monologue fires during delay (not after) per D-060 — cross-system
wiring deferred to follow-up ticket #451.

Ref: D-060 (cognitive delay), D-031 (10 tps), D-059 (fog layers)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-16 00:41:08 +01:00
jpmschweitzerandClaude Opus 4.6 9e8ccb13bf fix(client): address PR #22 review — 3 critical bugs, 2 warnings, 8 suggestions
Critical fixes:
- fog_state: guard _compute_bounds() against all-invalid tiles (negative Rect2i crash)
- fog_shader: read Camera2D zoom dynamically instead of hardcoded Vector2(2,2)
- world_radial: set custom_minimum_size in _ready() from spoke geometry

Warnings:
- fog.gdshader: tighten PERIPHERAL_LOW 0.15→0.55 to match D-059 peripheral band
- Extract color_for_entity_kind() to Constants.gd, decouple CursorRenderer from EntityRenderer

Documentation: shallow copy assumption, gradual decay TODO, tween guard rationale,
fade timing rationale, ToggleInsert TODO, monologue consume-once, hover offset safety,
v6 fixture gap TODO.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-15 23:23:11 +01:00
jpmschweitzerandClaude Opus 4.6 1fcf08d21f feat(client): Sprint 6 Touch — z-layer pipeline, cursor, fog, interactions, inventory, stance, radial
Three-scope z-layer rendering pipeline (D-049): world z:0-900 inside
CanvasGroup, insert overlay CanvasLayer 10, UI CanvasLayer 20, modal
CanvasLayer 30. Y-sort contract enforced (entities z_index=0). Reserved
ranges for VFX, airborne, lower floors documented in constants.gd.

Sprint 6 client tickets:
- #429: Cursor state machine — 4 states, 150ms transitions (D-056)
- #430: Fog shader rebuild — 5-layer fragment shader, animated noise (D-059)
- #432: Entity interaction list — vertical multi-verb, insert-styled (D-057)
- #433: World radial menu — 2 spokes, drag-release + click-click (D-058)
- #438: Inventory UI — 3x3 grid, 40x40px, 1-9 hotkeys (D-065)
- #439: Stance indicator — color-coded HUD, C/X keybinds (D-053)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-15 23:06:03 +01:00
jpmschweitzerandClaude Opus 4.6 24cce41379 feat(client): protocol v6 bridge — stance, inventory, input mapping
Upgrade client protocol bridge from v5 to v6 to match server.
Adds player_stance (4 variants) and player_inventory decode to
ObserverSnapshot. Adds TOGGLE_STANCE_UP/DOWN to InputMapper.
Includes 25 gdUnit4 tests for v6 decode + server serialization
test gap fix.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-15 23:05:47 +01:00
jpmschweitzerandClaude Opus 4.6 98f4cedc03 feat(simulation): Sprint 6 Touch — stance, tile presence, verbs, protocol v6
Implements the core Sprint 6: Touch systems across 5 tickets:

- #449 ObserverSnapshot v6: add player_stance (MovementStance) and
  player_inventory (Vec<InventoryItem>) wire fields with serde defaults
  for backward compatibility. Bump PROTOCOL_VERSION 5→6.

- #417 Stance system: Sprint/Walk/Careful/Crouch movement stance with
  tick-based speed (1/2/3/4 ticks per move), monologue rate multipliers,
  and PlayerMoveCooldown component. ToggleStanceUp/Down player actions.

- #420 TilePresence: posture-layer collision system allowing same-tile
  occupancy for different layers (Standing/Prone/Seated/Fixture).
  Layer-based collision in validate_movement.

- #421 ObjectType component: Readable/Container/Terminal/Door/Pickup/
  Furniture types with Phase 1 verb sets computed from type + proximity.

- #422 Phase 2 verb filter: KG-gated observer-side verb processing —
  POI priority flips, Confront injection at KnowsDetails+, contradiction
  marking, archetype-specific label relabeling (Smuggler/Detective).

217 unit tests + 17 integration tests passing. All MessagePack fixtures
regenerated for v6 wire format.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-14 15:38:59 +01:00
jpmschweitzerandClaude Opus 4.6 c41bec0d15 chore(client): track Godot .uid resource identifier files
These are auto-generated by Godot 4 to provide stable resource
references across renames. Tracking them prevents UID divergence.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-14 09:49:41 +01:00
jpmschweitzerandClaude Opus 4.6 3c106aa2d0 feat(simulation): complete interaction and monologue pipelines (#413, #414, #415)
Three fixes to make the gameplay loop functional end-to-end:

- Add Interactable component to NPC spawn so E-prompt detection works
- Build monologue trigger system (enter_location + time_idle) with
  MonologueBuffer/MonologueState components, wire through ObserverSnapshot
  as current_monologue field, decode on client and display via HUD
- Change PlayerAction::Interact from unit to struct variant carrying
  optional target_entity_id and verb fields

Bumps protocol version from 4 to 5. Regenerates MessagePack fixtures.
All 200 tests pass (170 unit + 30 integration).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-13 19:23:47 +01:00
jpmschweitzerandClaude Opus 4.6 470ec59b63 fix(ui): adapt client to new ui-strings.yaml structure
The copy team rewrote ui-strings.yaml with multi-level nesting,
renamed sections, and inline comments. Update the YAML parser to
use a stack-based approach for arbitrary nesting depth, update HUD
and interaction prompt to reference the new key names, and align
tests with the new structure.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-13 18:07:15 +01:00
jpmschweitzer 15ea6f1375 Merge remote-tracking branch 'origin/copy'
# Conflicts:
#	CHANGELOG.md
#	client/data/ui-strings.yaml
2026-02-13 17:57:10 +01:00
jpmschweitzerandClaude Opus 4.6 fe3232377d refactor(content): move ui-strings.yaml to client/data/
UI microcopy strings belong in the client data directory where
the Godot client can load them directly, not in campaign content.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-13 17:54:55 +01:00
jpmschweitzerandClaude Opus 4.6 5a04656781 feat(ui): add YAML-based UI string loading system (#409)
Adds UIStrings autoload that loads display text from a YAML file,
replacing hardcoded strings in HUD and interaction prompt. Copy team
can now author UI microcopy in client/data/ui-strings.yaml without
touching GDScript. Includes 38 strings across 5 categories and 16
gdUnit4 tests for the parser and lookup API.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-13 17:18:01 +01:00
jpmschweitzerandClaude Opus 4.6 e6d6802c8d fix(client): align tests with kind-based player detection
Tests used entity_id matching to find the player, but game_state now
finds the player by kind.variant == "Player". Update test fixture to
include a Player entity and remove stale player_entity_id assignments.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-13 02:07:43 +01:00
jpmschweitzerandClaude Opus 4.6 e810abdcaf fix(client): use server tick for movement input processing
Client was sending Time.get_ticks_msec() (e.g. 12345) as the input
tick, but the server's drain_for_tick only processes inputs where
tick <= current_tick (a small frame counter). Inputs accumulated in
the queue and were never processed, making movement keys unresponsive
in live mode. Use GameState.current_tick from the latest snapshot.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-13 02:07:38 +01:00