Implement TODO backlog: LATE phase fix, protester, CALL_SOMEONE, door lock, flashlight, persistence, navmesh, JSON localization, and release tooling
CI / headless-tests (push) Successful in 55s

- Fix LATE shift phase (start 700s) so the violent-threat event is reachable
- Add PROTESTER archetype (rules, profile, colors, events in public venues)
- Add CALL_SOMEONE reaction (FSM -> ARGUING, influencer/trespasser/protester weights)
- Door lock: DoorState core class, L binding, red/green visual indicator,
  locked doors thwart FORCE_ENTRY
- Flashlight: G binding, SpotLight3D, perception radius bonus at evening/late
- Persistence: save shift results via Save autoload, history + best score on
  review screen, round-trip test
- Navigation: flat NavigationRegion3D navmesh, NavigationAgent3D path following
  with direct-movement fallback; steps made visual-only so NPCs reach entrance
- Localization: strings moved to content/strings.en.json (loader keeps
  lookup/fmt signatures; coverage test over all keys)
- Distribution: export_presets.cfg (Linux/Windows/macOS), tools/build_releases.sh,
  docs/RELEASING.md, prominent README Downloads section
- Remove stale signal_bus.gd (invalid static-signal experiment)
- Tests: 53 passing across 9 suites
This commit is contained in:
zwitschi committed 2026-10-31 12:51:13 +01:00
1 parent c808165302
commit 1e972a7490
27 files changed
+1044 -340

No files matched your search

+22
View File
@@ -16,6 +16,7 @@ var inspect_panel: PanelContainer
var inspect_text: Label
var inspect_meta: Label
var radio_cooldown_label: Label
var mode_label: Label
var wand_panel: PanelContainer
var wand_text: Label
var wand_meta: Label
@@ -91,6 +92,13 @@ func _init() -> void:
radio_cooldown_label.modulate = Color(1, 0.55, 0.45)
vbox.add_child(radio_cooldown_label)
# --- door / flashlight state ---
mode_label = Label.new()
mode_label.text = "Door: open · Light: off"
mode_label.add_theme_font_size_override("font_size", 13)
mode_label.modulate = Color(0.85, 0.85, 0.9)
vbox.add_child(mode_label)
# --- dialogue tone indicator ---
tone_label = Label.new()
tone_label.text = "Tone: Professional"
@@ -175,6 +183,20 @@ func _update_radio_cooldown(coordinator: Object) -> void:
func set_target_label(text: String) -> void:
target_label.text = text
var _flashlight := false
var _door_locked := false
func set_door(locked: bool) -> void:
_door_locked = locked
_refresh_mode_label()
func set_flashlight(on: bool) -> void:
_flashlight = on
_refresh_mode_label()
func _refresh_mode_label() -> void:
mode_label.text = "Door: %s · Light: %s" % ["LOCKED" if _door_locked else "open", "on" if _flashlight else "off"]
func set_action_hint(text: String) -> void:
hint_label.text = text