Commit Graph
85 Commits
Author SHA1 Message Date
jpmschweitzerandClaude Opus 4.6 469114cb0e fix(ui): wire M keybind for star map toggle, clean up info panel
- Add _unhandled_key_input to main.gd: M toggles star_map.toggle_visible()
- Remove topology line from info panel (internal data, not player-facing)
- Cast aperture_count to int (was showing decimal point)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-05 08:33:07 +02:00
jpmschweitzerandClaude Opus 4.6 c94c5d7acb fix(client): address PR #109 review — 6 warnings + 5 suggestions
Star map (W1-W3, S3):
- _process visibility guard + dirty flag (no redraw when hidden/unchanged)
- _system_hash masked to 31-bit positive range
- Extracted _find_nearest_system() shared helper

game_state.gd (W4):
- Inline load() in apply_snapshot() replaces per-tick overhead; safe at
  runtime because script is already in resource cache

Data pipeline (W5-W6):
- Script-relative path resolution via __file__
- --check mode + make check-star-map staleness target

Minor (S1-S2, S5):
- Removed redundant bone_idx assignment
- Simplified double-negative test assertion
- Documented autoload parse-order convention in CLAUDE.md

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-05 00:12:48 +02:00
jpmschweitzerandClaude Opus 4.6 0d5323f66c fix(client): resolve GDScript autoload parse-order errors
Autoload scripts are parsed before regular scripts, so class_name
types (CharacterVisualDescriptor, TestHarness, YamlParser) are not
available at parse time. Replace type annotations with untyped vars
and use load() for in-body class references. Fixes all 14 headless
parse errors (9 pre-existing + 5 from Sprint 30 changes).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-04 23:40:28 +02:00
jpmschweitzerandClaude Opus 4.6 aed513eb71 feat(ui): star map insert module — concentric hop-ring view (#674)
New StarMapRenderer: 301 systems in concentric hop-rings from player
location, sector-colored, click-to-select with info panel, pan/zoom.
Integrated into HUD (hidden by default), insert state propagation
wired in main.gd. Data enriched from systems.db + star-map.json via
tooling/generate-star-map-data.py regeneration script.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-04 23:34:36 +02:00
jpmschweitzerandClaude Opus 4.6 bc168c861a feat(client): hair highlight swatch + manifest JSON for exports (#719, #720)
#719: Add display-only hair highlight swatch (Option B) — auto-derived
from primary tint, non-interactive (MOUSE_FILTER_IGNORE).

#720: Remove DirAccess.open() fallback scanning (breaks in PCK exports).
Fully populate manifest.json (11 body types, 14 hair, 4 heads, 4
eyebrows, 8 clothing). Add tooling/generate-character-manifest script
and make manifest target for regeneration.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-04 23:34:23 +02:00
jpmschweitzerandClaude Opus 4.6 4d9840b68f feat(client): character creator overhaul — manifest, segments, eye color
Major changes from runtime testing and iteration:
- Asset manifest (manifest.json) controls all available content —
  replaces filesystem scanning, solves DirAccess/PCK export issue
- Dynamic tabs: only show tabs with manifest content
- Body segmentation: face-based exclusive assignment, hips split from
  torso, torso_upper independent (not a variant)
- Eye color with iris-only mask from T_Eye_Split.png green channel
- Eyebrows tinted with hair color (from body segment, not separate GLB)
- Hair/clothing loaded as skinned meshes on shared skeleton
- Segment hiding disabled for clothing (solidify handles coverage)
- Gender-aware randomizer (no facial hair on female/teen)
- Clothing slots hidden when empty in manifest
- UI: color docks docked to bottom on all tabs, padding, flow layout
- Debug tab with per-segment visibility toggles
- Screenshot automation with test config JSON

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-23 17:42:33 +01:00
jpmschweitzerandClaude Opus 4.6 2614c3c57a fix(client): build tab panel entirely in code — remove from .tscn
TabContainer and its VBoxContainer parent vanish during scene
instantiation when loaded as a child of MainMenu in Godot 4.6.
Moving the entire tab panel construction to _ready() resolves
the issue — the .tscn now only defines the preview side and footer.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-22 19:11:37 +01:00
jpmschweitzerandClaude Opus 4.6 307a221527 fix(client): resolve TabContainer via find_child instead of @onready
@onready path resolution fails when the scene is instantiated as a
child of MainMenu — the node path is valid in the .tscn but the
layout hierarchy breaks during child instantiation in Godot 4.6.
Using find_child() is more robust for scenes that are dynamically
added to another scene's tree.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-22 18:51:09 +01:00
jpmschweitzerandClaude Opus 4.6 a2ef1c34cb fix(client): create TabContainer children programmatically
Godot 4.6 TabContainer silently destroys children defined in .tscn
during scene instantiation ("Parent path has vanished"). Moving tab
shell creation to _ready() fixes the right-side settings panel.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-22 18:41:24 +01:00
jpmschweitzerandClaude Opus 4.6 acb1119b2a fix(client): add explicit type annotations for GDScript strict mode
Dictionary.get() returns Variant, which fails GDScript's strict type
inference (warnings-as-errors). Add explicit type casts on all
dictionary access in clothing and accessory tab code.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-22 18:21:50 +01:00
jpmschweitzerandClaude Opus 4.6 145d8fec17 refactor(client): remove archetype selection, fix Randomise→Randomize
- Remove character_select.tscn and character_select.gd entirely
  (Smuggler/Detective archetypes removed per v0.2 pivot)
- New Game goes straight to character creation
- Rename Randomise→Randomize throughout (US English convention)
- Add *.import and *.uid to client gitignore (import artifacts)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-22 18:18:47 +01:00
jpmschweitzerandClaude Opus 4.6 ebac8c9580 fix(client): address PR #99 review round 2 — 3 doc/comment fixes
1. character_creation.gd:125 — cam_pitch_idx comment: 2=overhead(0°) → (-80°)
2. character_visual.gd:37 — segment arithmetic: 17+2+2=21 → 14+2+2=18
3. decisions/scope.md D-158 — overhead angle: 0° → -80° to match code

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-22 17:54:53 +01:00
jpmschweitzerandClaude Opus 4.6 33d7d6996b fix(ui): address PR #99 review — character creation editor fixes
13 fixes from PR #99 review on #705 (character editor):

- #10/#11: Add _get_swatch_color() helper; fix stale closure in
  _make_color_swatch (reads current color at click time, not
  construction time); fix _on_modal_ok to use helper instead of
  wrong get_child(0) traversal
- #12: Replace HSV palette with D-165 hardcoded hex values (6×9
  rows, muted HSL per spec — reds/greens/blues/purples/browns/grays)
- #13: Fix fallback asset IDs to match actual files — hair: bald/
  bob/buzzed/long; heads: head_001–004; facial hair: beard/moustache/
  mutton_chops (stubble removed — no asset)
- #14: Remove invented "slot field" TODO comment; replace with
  name-prefix convention note
- #15: Fix overhead camera pitch 0.0°→-80.0° (0° was horizontal,
  not top-down as intended per D-158)
- #16: Make hair highlight swatch non-interactive (_make_display_swatch);
  remove _on_hair_highlight_changed and _hair_highlight_auto flag
- #17: Remove no-op self-assignment in _on_hair_selected; remove
  redundant assignment inside _hair_highlight_auto block
- #18: Store _clothing_dock_container/_accessory_dock_container as
  instance vars — eliminates fragile get_child(3).get_child(0) chain
- #19: Fix test_r_key_triggers_randomise — replaces assert_bool(true)
  with a real assertion checking body_type or skin_tone changed
- #20: Cache scan results in _cached_hair_ids/_cached_head_ids during
  tab build; _on_randomise() reads cache (no re-scan per keypress)
- #21: Fix character_visual.gd docstring "21 segments" → "18 segments"
- #22: Fix _get_accessory_ids_for_slot — apply slot name-prefix
  filtering instead of returning all accessories for every slot

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-22 17:46:10 +01:00
jpmschweitzerandClaude Opus 4.6 56e8c70081 feat(client): character creation screen with live 3D preview (#705)
Full character creation UI with 5-tab customisation panel (Body, Head,
Hair, Clothing, Accessories), live 3D compositor preview via SubViewport,
D-165 color picker modal, keyboard navigation, and game flow integration.

- CharacterCreation scene + script (~1440 lines) implementing wireframe spec
- SubViewport with Camera3D (frontal/dramatic/overhead presets per D-158)
- Cardinal rotation (Q/E) per D-155, randomise (R), Tab/Enter/Esc navigation
- Body type grid (11 types, D-159), skin tone dock (9 tones, shared state)
- Head template, hair, facial hair, eyebrow grids with DirAccess asset scanning
- Clothing slot selector with per-item Primary/Secondary/Accent tints
- Accessory slot selector with Primary/Secondary tints (Array[Color] descriptor)
- 54-swatch color picker modal (D-165) with hex input and recent colors
- Auto-derive flags for highlight, eyebrow tint, facial hair tint from hair primary
- Game flow: main_menu → archetype select → character creation → game start
- GameState.character_visual_descriptor field for gameplay consumption
- Updated accessory_tints from single Color to Array[Color] in descriptor + compositor
- 40+ GdUnit tests covering scene structure, signals, keyboard nav, color derivation

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-22 17:16:47 +01:00
jpmschweitzerandClaude Sonnet 4.6 f51366b3f5 fix(ui): address PR #90 review — 8 items (W1–W4, S5–S6, A3–A4)
W1/A2: add SimBridge.CONNECTED guard before send_input in toggle handler
W2/A1: assert PlatformInfo != null in HardwareDetector._ready();
       add ordering comment in project.godot [autoload] section
W3: replace FileAccess.open() with get_file_as_string() in
    read_benchmark_cache() — auto-closes, no leak
W4/A3: add _extract_bool_setting() helper in game_state.gd that handles
       both {"Bool": true} and plain bool; push_warning on type mismatch
S5: sync _pre_battery_pref from GameState after load_ai_pref() in
    HardwareDetector._ready() — closes race if system starts on battery
S6: separate "red" TPT status into its own arm with STATUS_RED dot and
    label colour — three-colour mapping: green/yellow/red now distinct
A4: replace DebugConsole.PREFS_PATH compile-time dependency in
    _save_ai_pref() with local SETTINGS_CFG_PATH constant

S7 (battery CI guard) already applied by Hoshe in test file.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-13 11:39:47 +01:00
jpmschweitzerandClaude Sonnet 4.6 9108e5d9ed feat(ui): add get_battery_warning_visible() getter to settings_dialog
Testable API for Hoshe's battery warning visibility assertions (#646).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-13 10:54:54 +01:00
jpmschweitzerandClaude Sonnet 4.6 41d16d01ae fix(ui): toggle stays clickable during battery suspend — D-138 player autonomy
Player autonomy wins: AI Dialogue toggle is only greyed out for RAM fail
(< 1.6 GB free). Battery suspend shows a warning label instead of
disabling the toggle — player can override the auto-suspend at any time.

Changes:
- settings_dialog: toggle disabled = hw_status == "fail" only
- settings_dialog: add _ai_battery_warning_label (STATUS_YELLOW) shown
  when _ai_inference_suspended; hidden when plugged back in via
  set_ai_inference_suspended()
- settings_dialog: is_ai_dialogue_toggle_enabled() no longer checks
  _ai_inference_suspended
- settings_dialog: set_ai_inference_suspended() updates warning label
  visibility, not toggle disabled state
- ui-strings: add settings.ai_battery_warning "High battery usage"

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-13 10:49:06 +01:00
jpmschweitzerandClaude Sonnet 4.6 d7a4e3268a feat(ui): PlatformInfo abstraction + battery detection + fixes (#646 D-138)
Platform abstraction:
- New PlatformInfo autoload (extends Node, registered first in project.godot).
  Owns all OS queries: power state monitoring (30s poll), memory (on demand),
  file path resolution (user_data_dir, config_dir, benchmark_cache_path,
  install_dir, executable_path, cache_dir, model_dir).
- PowerProfile enum (FULL/BATTERY/POWER_SAVER), power_profile_changed signal.
  Uses OS.callv("get_power_info") to defer resolution to runtime — avoids
  compile errors on Godot 4.6 headless builds without power API.

HardwareDetector refactor:
- check_ram() now delegates to PlatformInfo.refresh_memory() + free_memory_mb.
  All direct OS.get_memory_info() calls removed.
- classify_power_state(int) and should_suspend_inference(int) delegate to
  PlatformInfo for single source of truth.
- check_power_state() → {power_state, classification, should_suspend}.
- Battery suspend/resume: on PowerProfile.BATTERY, stores pre-battery pref and
  sends ChangeSettings(false) to server. On FULL restore, sends ChangeSettings
  with saved pref if it was enabled. inference_suspended member tracks state.

Settings dialog:
- is_ai_inference_suspended() / set_ai_inference_suspended(bool) — testable API
  per Hoshe's test contract. Reads HardwareDetector.inference_suspended on open.
- Toggle now disabled when battery-suspended OR hardware fails (not only fail).
- get_ai_dialogue_label_text() wired to UIStrings ("settings.ai_dialogue_toggle")
  instead of hardcoded string.

Cleanup:
- Deleted ai_dialogue_detector.gd and .uid (orphaned duplicate, dead code).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-13 10:41:07 +01:00
jpmschweitzerandClaude Sonnet 4.6 01b0583265 feat(ui): AI-Enhanced Dialogue toggle + hardware detection (#646, D-138)
Implements the full AI-Enhanced Dialogue feature for Sprint 26:

- HardwareDetector autoload (extends Node): three-layer detection —
  Layer 1 RAM classification (pass/marginal/fail, thresholds 2GB/1.6GB),
  Layer 2 TPT benchmark cache (green/yellow/red, thresholds 6/3 t/s),
  Layer 3 degradation monitoring (>40% drop → yellow). load_ai_pref()
  restores toggle state from user://settings.cfg on startup.

- Settings dialog AI section: toggle, colored status dot, status message
  label, testable API (get_ai_dialogue_label_text, set_ai_dialogue_
  hardware_status, is_ai_dialogue_toggle_enabled). Only RAM "fail" greys
  out toggle — player always overrides yellow/red recommendations (D-138).

- GameState.ai_enhanced_dialogue_enabled (default true, opt-out model).
  GameState.settings_response (v20 one-shot settings dump from server).
  apply_snapshot() hydrates ai_enhanced_dialogue_enabled from full dump.

- Protocol v19→v20, settings_response decoding in decode_snapshot().
  Protocol converted to extends Node autoload (enables test has_method).
  encode_change_settings() helper for test inspection.

- InputMapper: CHANGE_SETTINGS, REQUEST_ALL_SETTINGS, DELETE_SETTING.
  SimBridge: wire mappings for all three. RequestAllSettings queued after
  handshake to hydrate client state from server SQLite on connect.
  settings_response carry-forward in receive_bytes().

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-13 10:34:48 +01:00
jpmschweitzerandClaude Opus 4.6 e0eb3cd35e fix(client): address PR #86 review — archetype validation, teleport clear, ticker layout
- protocol.gd: replace capitalize() with explicit match for archetype
  string mapping, push_error on unknown input with Detective fallback
- main.gd: clear _known_triangle_ids in _teleport_transition() alongside
  _known_recognition_ids so chime re-fires after room change
- news_ticker.gd: defer get_minimum_size() via call_deferred to run
  after layout pass, fixing first-frame scroll distance
- 3 new tests: unknown archetype fallback, triangle dedup per-id,
  independent triangle ID firing

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 16:28:12 +01:00
jpmschweitzerandClaude Opus 4.6 61d454228d feat(client): character select, triangle activation consumer, news ticker
Sprint 24 Signal — three client tickets delivering the player-facing
storyteller feedback loop:

- #588: Character archetype select screen between New Game and session
  start. Two-card UI (Smuggler/Detective), keyboard+mouse, ESC cancels.
  GameState.character_archetype persisted and sent in StartupMessage.
  PROTOCOL_VERSION bumped to 19.
- #590: Triangle crisis event consumer. Decodes triangle_crisis_events
  from snapshot, fires sfx_monologue_chime_urgent once per triangle per
  session via AudioManager.CHIME_ACTIVATION.
- #592: News ticker HUD element. Scrolling marquee on UILayer, visible
  only when current_ticker is present in snapshot (Last Shift zone).
  Zero-arg update_from_state reads from GameState.current_snapshot.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 11:44:05 +01:00
jpmschweitzerandClaude Opus 4.6 fc24de6128 fix(client): test harness tile types, bug report screenshot, time_display maxf
TestHarness: remove deprecated tiles/visible_positions keys, add tile
type (floor/wall/door) to visible_tiles, expand radius to 5. Bug report
dialog: capture viewport screenshot before showing overlay, save as
screenshot.png in report bundle. time_display: use maxf() instead of
max() to match float argument types.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 08:41:18 +01:00
jpmschweitzerandClaude Opus 4.6 388df8000a fix(client): debug console review fixes — D-088 pause, settings state, response guard
- Add D-088 Overlay pause/unpause signals to DebugConsole, wire in main.gd
  so sim does not advance while typing debug commands
- Settings dialog reads live DebugConsole.is_enabled() instead of ConfigFile
  directly, preventing checkbox/state divergence
- append_response respects disabled state — no auto-open when user disabled
  console via settings
- tp command warns on invalid z value instead of silently defaulting to 0

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 22:31:52 +01:00
jpmschweitzerandClaude Sonnet 4.6 c3abf32185 feat(ui): add in-game debug console with tilde toggle and command dispatch (#581)
- debug_console.gd: new ModalLayer Control — tilde key toggles bottom-40% panel,
  command history (up/down), SimBridge dispatch for all DebugCommandKind variants:
  ticks, contaminate, tp, activate, triangle, npc, triangles, pop, status, help
- debug_console.tscn: minimal scene node; UI built programmatically in _ready()
- input_mapper.gd: DEBUG_COMMAND action added to Action enum
- sim_bridge.gd: DEBUG_COMMAND → "DebugCommand" wire mapping
- protocol.gd: v18 debug_response decode (command, text, success fields)
- game_state.gd: debug_response field + apply_snapshot one-shot handling
- main.gd: @onready ref, router registration, _consume_debug_response(), settings signal
- settings_dialog.gd: debug_console_toggled signal + CheckButton toggle row (+36px height),
  reads initial state from user://settings.cfg; CheckButton state loaded from PREFS_PATH
- main.tscn: DebugConsole node on ModalLayer, load_steps 27→28

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-04 09:50:23 +01:00
jpmschweitzerandClaude Sonnet 4.6 d30ab62bc0 fix(ui): clear color registry on conversation end, add speaker color tests (#573)
- Reset _npc_entity_colors/_npc_entity_id/_next_npc_color in _end_player_conversation()
  to prevent palette exhaustion across long sessions with many unique NPCs
- Re-enforce contrast floor after passive desaturation (_enforce_contrast after _desaturate)
- Add TestDialogueSpeakerColors suite: palette allocation, entity reuse, reset, fallback

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-04 09:50:02 +01:00
jpmschweitzerandClaude Sonnet 4.6 974bb2b28e feat(ui): bind dialogue speaker colors to entity identity (#573)
Maintains Dict[entity_id → Color] in dialogue_box for player conversations.
On first encounter, assigns a round-robin palette color; reuses on subsequent lines.
Eliminates position-based name-hash coloring for player dialogue.

Changes:
- Add _npc_entity_colors dict, _npc_entity_id, _next_npc_color fields
- Add _assign_npc_color(entity_id) — registers palette color on first encounter
- show_dialogue: accept npc_entity_id param, register entity color
- append_line: optional speaker_entity_id/target_entity_id stored in log entries
- append_player_line: pass _npc_entity_id as target_entity_id
- append_dialogue_response: accept entity_id, register, pass to append_line
- _format_entry else branch: look up _npc_entity_colors before name-hash fallback
- main.gd: pass _last_dialogue_npc_id to show_dialogue, speaker_entity_id to append_dialogue_response

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-04 02:05:15 +01:00
jpmschweitzerandClaude Opus 4.6 a862426f84 docs(docs): add Sprint 22 briefings and track Godot auto-generated files
Sprint 22 "Wire" briefings for server, client, visual, CI, and
planning teams. Also track Godot .import and .uid files that were
previously untracked.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-28 12:20:02 +01:00
jpmschweitzerandClaude Opus 4.6 64bf4ec539 fix(client): address PR #73 review — race conditions and defensive guards (#257)
- Defer LOAD_GAME dispatch until SimBridge reaches CONNECTED (critical)
- Guard _build_saves_list() against queue_free() race on rapid reopen
- Disable save entries with empty newest_save, guard in _on_save_selected
- Send before show_loading on F6 quickload, skip overlay on send failure
- Clear pending_load_path in _on_new_game()/_on_continue() (stale path)
- Add hide_loading(success: bool) API for future failure-state UI
- Add test_save_load_flow_sprint21.gd covering LoadingScreen + GameState

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 18:06:16 +01:00
jpmschweitzerandClaude Opus 4.6 c797869503 feat(client): add save/load game flow and move debug_overlay (#257, #561)
#257: Add Load Game screen to main menu with sorted save list, loading
overlay during quickload round-trip, and pending_load_path cross-scene
flow. F5/F6 quicksave/quickload were already wired.

#561: Move debug_overlay.gd from scripts/ui/ to ui/ for consistency
with all other UI components. Update scene and test references.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 11:07:10 +01:00
jpmschweitzerandClaude Opus 4.6 6f9c97ca03 refactor(client): decouple dialogue_box from GameState and AudioManager (#558)
Replace 3 direct GameState.dialogue_active mutations and all
AudioManager.apply_dip/clear_dip calls with signals:
dialogue_state_changed, audio_dip_requested, audio_dip_cleared.
dialogue_box.gd now has zero references to GameState or AudioManager.
main.gd wires coordinator handlers in _ready() (D-020).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 21:59:47 +01:00
jpmschweitzerandClaude Opus 4.6 3725a3df5e fix(client): address PR #70 review — event leak, quit flush, notification color
- input_mapper.gd: call set_input_as_handled() before early return on
  empty game_id so F5/F6 events don't propagate to other handlers
- session_manager.gd: defer scene change by one frame after buffering
  quit-save so SimBridge._process() flushes the outbound buffer
- monologue_display.gd: tag queued notifications with is_notification
  flag so drain path routes to _show_notification_line (correct color)
  instead of _show_line (lattice-profile fallback color)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 15:43:53 +01:00
jpmschweitzerandClaude Opus 4.6 e1ea07e746 feat(client): save/load client UI — F5/F6 quicksave/quickload (#554)
Wire SaveGame/LoadGame player actions through the full client stack:
protocol v15 decode, InputMapper F5/F6 bindings, SimBridge wire mapping
with one-shot carry-forward, GameState save_result field, and HUD
notification via monologue display. Quit-to-menu triggers quicksave
before scene change.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 13:15:05 +01:00
jpmschweitzerandClaude Opus 4.6 e7f1e80307 fix(client): POI category key mismatch — use poi_category from wire format
protocol.gd decoded server's poi_category as "category", minimap.gd
read "category" — both now use "poi_category" matching the wire format.
Protocol falls back to "category" for older server snapshots.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 12:57:29 +01:00
jpmschweitzerandClaude Opus 4.6 83a244fc2c fix(client): address PR #67 round 2 — broken tests, BBCode escape, expiry loop
- Add missing _test_input_queue proxy to SimBridge (26 call sites across
  6 test files broken by TestHarness extraction)
- Parent quit dialog to SceneTree root instead of caller node to prevent
  orphaned reference if caller freed before user responds
- Remove deprecated rng.randomize() call (Godot 4 auto-seeds)
- Clear debug overlay state (_npc_paths, tick timing) on session change
  via new GameState.game_id_changed signal to prevent entity ID collisions
- Update settings_dialog quit_to_menu() call site (no-arg signature)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 12:48:47 +01:00
jpmschweitzerandClaude Opus 4.6 5d1d0d000c fix(client): address PR #67 review — error propagation, test cleanup
SessionManager.new_game() now returns "" on dir creation failure
instead of proceeding with a broken game-id. Main menu guards
against empty return. Test suite tracks and cleans up created
save directories in after_test().

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 12:08:48 +01:00
jpmschweitzerandClaude Opus 4.6 ef135830f2 feat(client): game session management (#258, D-085)
Per-game save directories under user://saves/<timestamp>-<seed>/.
SessionManager autoload handles new_game(), resume_game(), quit flow.
Main menu scene with New Game / Continue / Quit buttons. Game-id
passed to server subprocess via --game-id flag.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 11:45:46 +01:00
jpmschweitzerandClaude Opus 4.6 776ba2e55f fix(client): address PR #65 round 2 — broken tests, BBCode escape, expiry loop
- test_journal_sprint18.gd: replace references to removed
  CONFIDENCE_LABELS/SOURCE_LABELS with UIStrings key tests and
  regression guards
- dialogue_box.gd: escape ] as [rb] in _escape_bbcode for complete
  BBCode injection protection
- dialogue_box.gd: fix _expire_entries to skip pinned entries with
  continue instead of break, cleaning expired entries behind pins

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 09:44:42 +01:00
jpmschweitzerandClaude Opus 4.6 a82eb0748a fix(client): address PR #65 review — POI key, ToldBy parsing, KG dirty flag
- minimap.gd: fix "poi_category" → "category" key mismatch so POI
  colors and shapes render correctly
- journal_panel.gd: parse ToldBy(N) source format, resolve entity
  names from player_knowledge; move confidence/source labels to
  UIStrings per D-042
- observer/mod.rs: add Changed<KnowledgeGraph> dirty flag to skip
  per-tick KG serialization when unchanged
- types.rs: fix stale version doc comment (13 → 14)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 02:41:31 +01:00
jpmschweitzerandClaude Opus 4.6 86ff83d927 feat(ui): knowledge/journal display panel (#264)
Right-side insert panel toggled with J key. Facts grouped by entity
with confidence, source, and state metadata. Contradicted entries
in amber with strikethrough (THE FRIEND arc surface). Stale entries
dimmed. Mutual exclusion with dialogue box. All labels via UIStrings.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 02:30:04 +01:00
jpmschweitzerandClaude Opus 4.6 9b80ff69c3 feat(ui): dialogue UI hardening and examine result overlay (#174)
Confrontation options use RichTextLabel with italic tags for
first-person voice (D-063). Examine result overlay auto-dismisses
after 5s with confidence-based color tinting. Dismisses when
dialogue opens. D-062 invisible locked options confirmed correct.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 02:29:55 +01:00
jpmschweitzerandClaude Opus 4.6 eeb82535f6 feat(ui): minimap rendering with POI dots and border arrows (#151)
Circular 160px diegetic insert overlay on CanvasLayer 10. Nearby
POIs as colored dots (diamond=danger, square=evidence, circle=default),
distant POIs as directional border arrows. Player centered, fixed-north.
Moved from UILayer to InsertOverlay per D-013/D-049.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 02:29:46 +01:00
jpmschweitzerandClaude Opus 4.6 821d716509 fix(client): address PR #62 review suggestions — polish pass
- interaction_list.gd: skip queue_redraw() when position unchanged (Tyre #4)
- time_display.tscn: widen bounding rect 154x44→184x54, add clip note
  for #314 wireframe (Tyre #3)
- test_time_display_sprint17.gd: document private state access pattern
  in header (Tyre #5), add upper bound assertion for D-031 1439 max (Hoshe #6)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-24 11:30:24 +01:00
jpmschweitzerandClaude Opus 4.6 16c00e137e fix(client): address PR #62 review — input guard, public API, geometry cache
- constants.gd: clamp format_game_time input to 0..1439 (Hoshe #2)
- interaction_list.gd: add public hide_list() wrapper (Hoshe #3, Tyre #1)
- main.gd: call hide_list() instead of private _hide()
- time_display.gd: cache font geometry in update_from_state(), use boolean
  _has_data flag instead of string guard (Tyre #2)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-24 11:28:43 +01:00
jpmschweitzerandClaude Opus 4.6 6c3a30a4bc feat(ui): add relationship color accent to E-Talk overlay (#537)
Phase 1: interaction_list.gd shows a 3px left-edge accent bar in
D-033 relationship color (teal/green/amber/red) at 85% alpha.
Cross-references entity_id against visible_entities via
_cache_entity_relationship(). NPC name and tier hint deferred to
Phase 2 (requires server protocol extension).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-24 11:16:33 +01:00
jpmschweitzerandClaude Opus 4.6 66a435e201 feat(ui): add diegetic time display on insert HUD (#263)
Time display on InsertOverlay (CanvasLayer 10) shows station local
time (HH:MM), day phase with cycle-tinted color, and day number.
Reads SimulationTime from GameState.game_time via update_from_state().
Adds Constants.format_game_time() helper for testability.
Placeholder layout — position refines when #314 wireframe lands.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-24 11:16:23 +01:00
jpmschweitzerandClaude Opus 4.6 0880e8d987 feat(client): permanent dialogue panel + protocol v13 + build check
- dialogue_box.gd: panel is always visible as permanent insert UI
  element per D-061 — content fades but frame stays on screen
- protocol.gd: bump PROTOCOL_VERSION to 13
- Makefile: add check-protocol target that verifies server/client
  protocol versions match, runs automatically before build

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-23 15:36:18 +01:00
jpmschweitzer eb6b5cc337 Merge remote-tracking branch 'origin/main' into client
# Conflicts:
#	client/data/dialogue-theme.yaml
#	client/scripts/main.gd
#	client/scripts/protocol/protocol.gd
#	client/scripts/ui/debug_overlay.gd
#	client/ui/dialogue_box.gd
2026-02-21 13:48:08 +01:00
jpmschweitzerandClaude Opus 4.6 aa97ef988a chore(client): track Godot-generated uid and import files
New .uid files from Godot 4 and updated .import metadata for
audio assets and fonts added during Sprint 14.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-21 13:43:43 +01:00
jpmschweitzerandClaude Opus 4.6 2c69e557c2 fix(client): resolve WASD freezes, warnings, and chime spam
- bug_report_dialog: release_focus() before queue_free() prevents
  stale focus on ModalLayer blocking input to lower layers
- dialogue_box: clear dialogue_active immediately on conversation
  end instead of holding for entry_lifetime
- main.gd: permanent entity ID tracking per room stops recognition
  chime re-triggering when NPCs oscillate in/out of fog queue
- audio_manager: correct path res://audio/ to res://assets/audio/
- world_radial.tscn: anchors_preset 15 to 0 (script sets size)
- bug_report_dialog: push_warning to print (informational)
- debug_overlay: max() to maxi() for integer line count
- monologue_display: remove unnecessary Tween cast

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-21 13:43:18 +01:00
jpmschweitzerandClaude Opus 4.6 03ff3c5fef feat(ui): entity-anchored dialogue log with keyboard selection
Log entries store entity IDs and resolve display names at render
time from _entity_display lookup — enables retroactive name update
when player learns an NPC's real name. Color index from server
replaces name-hash coloring for stable NPC colors.

Dialogue options: switched RichTextLabel to Label (fixes stacking
bug), added 1/2/3 number key selection, numbered option labels.

Interaction list: added background panel, mouse hover highlighting,
click-to-interact, pointing hand cursor.

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