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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
Protocol decoder now reads tile_kind from VisibleTile and maps it to
the client's tile type string (floor/wall/door/object). GameState
falls back to visible_tiles when the test-mode tiles array is absent,
enabling live server tile rendering.
Fix entity-to-tile alignment: server sends tile-center render coords
(tile 16 -> 16.5) but entity renderer was using raw floats, placing
entities half a tile off. Now floors the coords to get the tile index.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Server was sending visible_tiles without tile type data, so the client
could not distinguish floor from wall in live mode. Add TileKind enum
(Floor/Wall/Door/Object) to VisibleTile, populated from WalkabilityMap
in the NaturalVision perception query. Update test fixtures to include
the new field. Uses #[serde(default)] for backward compatibility.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Three tests validating the full client-server input path through a
live server: movement roundtrip (MoveNorth/MoveEast with position
verification), interact roundtrip (unit variant accepted as no-op),
and mixed sequence (movement then interact preserves position).
Catches integration seams that unit tests miss — each test spawns a
real server binary on a random port, connects via LocalBridge, and
exercises the TCP→deserialize→simulation→snapshot→decode pipeline.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add SR_LIVE=1 environment variable to switch SimBridge from test mode
to TCP connection. Default behavior unchanged (test mode).
- sim_bridge.gd: read SR_LIVE env var instead of hardcoded test_mode
- game_state.gd: find player entity by kind.variant == "Player" instead
of hardcoded entity_id 1 (real server assigns different IDs)
- Makefile: add 'make game' (builds server, starts it, launches client
with SR_LIVE=1, kills server on exit) and 'make stop' helper
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Enable the interaction data attachment in main.gd game loop. When E
is pressed and the prompt is active, target_entity_id and verb are
attached to the Interact action before sending to the server. Without
a target, bare Interact is still sent as safe fallback.
Completes the v0.1 interaction prompt data flow:
server sends nearby_interactions → client shows prompt → E press
attaches target+verb → SimBridge encodes and sends to server.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Server proof room now has 3 NPCs instead of 1. Find player entity
by kind instead of assuming entities[0]. Wall-hides test checks
specific NPC position (16.5, 13.5) rather than asserting zero NPC
count. Corner-reveal test searches for NPC1 by position.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Server team shipped strict PROTOCOL_VERSION enforcement (c05ff7b),
1-indexed verb priorities, and "Observe" label for ExamineNpc.
Updates all test snapshots to include version: 4, fixes sim_bridge
test mode priorities (0-indexed → 1-indexed) and labels, replaces
v1 backward-compat tests with strict version rejection tests.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Server-driven interaction prompt that displays "E - Talk" when near
an interactable NPC. Decodes v4 nearby_interactions from snapshot,
stores in GameState, renders via InteractionPrompt UI with fade
animation. Extensible interface (get_interaction_target/get_selected_verb)
for future radial verb menu (v0.2).
- Protocol: decode nearby_interactions array with nested VerbOption structs,
entity relationship/observation fields, tick_rate in GameTime
- GameState: store/clear nearby_interactions per snapshot
- SimBridge: test mode generates v4 format with structured verbs
- InteractionPrompt: PanelContainer with fade in/out, polls GameState
- Tests: 19 new test cases covering protocol, state, sim bridge, UI, encoding
- Fixture assertions updated for v4 protocol version
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Client now rejects snapshots where version != PROTOCOL_VERSION (4).
Returns null with error log on mismatch. Test snapshot updated to
use Protocol.PROTOCOL_VERSION and v4 game_time format (tick_rate
replaces paused field).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Filter remembered entities by z-level (Hoshe + Tyre warning)
- Skip remembered ghosts on currently visible tiles (Hoshe warning)
- Bump ObserverSnapshot version to 3 (Tyre suggestion)
- Add edge case tests: visible tile collision, different z-level,
knowledge without position (Hoshe suggestion)
- Regenerate msgpack fixtures for v3
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Three E2E proof tests verify all acceptance criteria through the real
server pipeline: player movement, v2 snapshot with visible_tiles,
wall hiding (NPC behind wall invisible), corner reveal (move around
wall to see NPC). Dynamic test snapshot tracks player position from
queued inputs with simple LOS and Manhattan-distance visibility for
standalone demo mode. 88 client + 112 server tests passing.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
VisibleEntity now carries relationship state (D-033 entity color) and
observation type (Visible vs Remembered). compute_observer_snapshot
queries the player's KnowledgeGraph to overlay relationship data on
visible entities and include remembered (not-in-LOS) entities as fog
ghosts at their last known position. Regenerated msgpack fixtures.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace hardcoded entity colors with D-033 relationship palette:
Player=#e0e8ff, Npc=unknown teal #4a9ebb, Object=grey #8b8ba0.
Phase 1 defaults by entity kind; Phase 2 (#361) will derive color
from RelationshipState via knowledge graph.
Entities in peripheral vision dimmed to 50% alpha (D-015).
Player entity gets a Polygon2D triangle indicator showing facing
direction, rotated from GameState.player_facing.
82 tests total, 0 failures.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Server shipped ObserverSnapshot v2 with game_time, player_facing,
visible_tiles (with visibility sectors), and per-entity visibility.
Protocol decoder was silently ignoring these fields. Now extracts
all v2 data with null defaults for backward compatibility.
GameState gains game_time, player_facing, visibility_sectors vars.
Derives visible_positions from visible_tiles when present (for real
server mode). Test snapshot updated with v2 fields.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Count-based dirty tracking missed content changes when tile/visibility
count stayed the same (e.g., door opening, player moving through
corridor). Now re-renders all layers when GameState.current_tick
advances, which correctly handles every snapshot change.
Adds 3 tests for tick advancement and same-count-different-content
scenarios. 68 total tests, 0 failures.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Expand wire protocol with version field, GameTime (day/phase/paused),
FacingDirection (8-directional), VisibleTile, VisibilitySector
(Forward/Peripheral), and visibility tag on VisibleEntity.
Regenerate all msgpack fixtures for client compatibility.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Sprint 2 rendering pipeline: tiles (#129), fog (#131), camera (#116).
- tile_renderer.gd: programmatic TileSet with floor/wall/door/object
placeholder tiles, renders from snapshot tile data
- fog_renderer.gd: TileMapLayer overlay with three visibility states
(visible/fog-edge/hidden), computed from visible_positions data
- Camera2D: smoothing enabled (speed 6.0), 2x zoom, locked to player
- game_state.gd: stores visible_tiles and visible_positions from snapshots
- sim_bridge.gd: test data with 8x8 room, corridor, and Manhattan
distance visibility for development without server
- Scene render order: Tiles -> FogOverlay -> Entities
- Background clear color set to near-black for unexplored areas
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
entity_renderer.gd used wrong field names ("id" instead of
"entity_id", "type" instead of "kind.variant", "position" instead
of x/y). Now matches Protocol.decode_entity() output exactly.
Also centers entities (24x24) within 32px tiles.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>