Remove dialogue tone-of-voice system, add Gitea Actions full build, add venue cycling
Full build / Import + headless tests (push) Successful in 2m25s
Full build / Full desktop build + optional release (push) Skipped

- Delete Rules.Tone/TONE_NAMES, NpcProfile.tone_modifiers, tone params on
  NPCController.roll_reaction/apply_player_action; dialogue_lines flattened
  to Array[String]; HUD tone label, T binding, and hud.tone_prefix removed
- Docs updated everywhere (PLAN, README, DONE, MEMORY); PLAN section heading
  'Tone and Design Direction' -> 'Design Direction'
- Add .gitea/workflows/build.yml: checks job (import+tests) on push/PR; full
  build job (export templates, Linux/Windows/macOS exports, artifact upload,
  and tag-based Gitea release publish via GITEA_TOKEN) on tags/dispatch
- Remove old .github/workflows/ci.yml to avoid double runs
- Add venue cycling (V) across all three scenarios with hud.venue_switched
- Refresh README screenshots to match the new HUD
- 53/53 tests pass, boot smoke clean
This commit is contained in:
zwitschi committed 2026-10-31 13:08:20 +01:00
1 parent f7486d7539
commit a3768c2ce4
21 files changed
+230 -185

No files matched your search

+21 -21
View File
@@ -46,9 +46,9 @@ var current_incident_npc_id := ""
var current_incident_active := false
var current_npc_truth := {"weapons_seen": false, "danger_level": 0}
## Dialogue tone picker (PLAN.md: Level 1 tones). Cycled with T.
var selected_tone: int = Rules.Tone.PROFESSIONAL
const TONE_ORDER := [Rules.Tone.PROFESSIONAL, Rules.Tone.FRIENDLY, Rules.Tone.FIRM, Rules.Tone.SUSPICIOUS]
## Venue cycling (V): next venue in the scenario list.
const VENUE_ORDER := ["hollywood_building", "joke_shop", "tv_studio"]
var _venue_index := 0
## Aim-free targeting: cycle through nearby NPCs with Tab (accessibility).
const NEARBY_RADIUS := 12.0
@@ -266,12 +266,10 @@ func _handle_key(keycode: Key) -> void:
_toggle_inspection()
KEY_Q:
if targeted_npc != null and not inspection_open:
_apply_interaction(Rules.Level.SIMPLE_DETERRENCE, selected_tone, "polite direction")
_apply_interaction(Rules.Level.SIMPLE_DETERRENCE, "polite direction")
KEY_W:
if targeted_npc != null and not inspection_open:
_toggle_wand_screening()
KEY_T:
_cycle_tone()
KEY_TAB:
_cycle_nearby_target()
KEY_F:
@@ -280,21 +278,23 @@ func _handle_key(keycode: Key) -> void:
_toggle_flashlight()
KEY_L:
_toggle_door_lock()
KEY_V:
_cycle_venue()
_:
_handle_action_key(keycode)
func _handle_action_key(keycode: Key) -> void:
match keycode:
KEY_1:
_apply_interaction(Rules.Level.SIMPLE_DETERRENCE, selected_tone, "raise hand")
_apply_interaction(Rules.Level.SIMPLE_DETERRENCE, "raise hand")
KEY_2:
_apply_interaction(Rules.Level.SIMPLE_DETERRENCE, selected_tone, "point")
_apply_interaction(Rules.Level.SIMPLE_DETERRENCE, "point")
KEY_3:
_apply_interaction(Rules.Level.SIMPLE_DETERRENCE, selected_tone, "head shake")
_apply_interaction(Rules.Level.SIMPLE_DETERRENCE, "head shake")
KEY_4:
_apply_interaction(Rules.Level.FORMAL_WARNING, selected_tone, "formal warning")
_apply_interaction(Rules.Level.FORMAL_WARNING, "formal warning")
KEY_5:
_apply_interaction(Rules.Level.BLOCKING, selected_tone, "blocking")
_apply_interaction(Rules.Level.BLOCKING, "blocking")
KEY_6:
_open_radio(false)
KEY_R:
@@ -331,13 +331,14 @@ func _toggle_door_lock() -> void:
hud.set_door(door.locked)
hud.log(Strings.lookup("door.locked") if door.locked else Strings.lookup("door.unlocked"))
## Cycle the dialogue tone (Professional → Friendly → Firm → Suspicious).
func _cycle_tone() -> void:
var idx := TONE_ORDER.find(selected_tone)
idx = (idx + 1) % TONE_ORDER.size()
selected_tone = TONE_ORDER[idx]
hud.set_tone(Rules.TONE_NAMES.get(selected_tone, "?"))
hud.log("Tone: %s" % Rules.TONE_NAMES.get(selected_tone, "?"))
## Cycle to the next venue (Hollywood Blvd → The Joke Shop → TV Studio).
## The coordinator is rebuilt with the new scenario and the shift restarts.
func _cycle_venue() -> void:
_venue_index = (_venue_index + 1) % VENUE_ORDER.size()
switch_scenario(VENUE_ORDER[_venue_index])
var venue_name: String = selected_scenario.display_name if selected_scenario else "?"
hud.log(Strings.fmt("hud.venue_switched", [venue_name]))
hud.set_shift_state(coordinator, selected_scenario)
## Aim-free targeting: cycle through NPCs near the guard (Tab). Lets players
## interact without precise aiming (accessibility).
@@ -359,20 +360,19 @@ func _cycle_nearby_target() -> void:
_begin_incident(next_target)
hud.log(Strings.fmt("hud.targeting", [next_target.name]))
func _apply_interaction(level: int, tone: int, action_name: String) -> void:
func _apply_interaction(level: int, action_name: String) -> void:
if targeted_npc == null:
hud.log(Strings.lookup("hud.aim_first"))
return
var controller: Object = _targeted_controller()
if controller == null or coordinator == null:
return
var outcome: Dictionary = controller.apply_player_action(level, tone)
var outcome: Dictionary = controller.apply_player_action(level)
var npc_id: String = controller.npc_id
coordinator.recorder.add_event(npc_id, {
"type": "player_action",
"action": action_name,
"level": level,
"tone": Rules.TONE_NAMES.get(tone, "?"),
})
coordinator.recorder.add_escalation(npc_id, level, "%s on %s" % [action_name, npc_id])
if level >= Rules.Level.FORMAL_WARNING: