Remove dialogue tone-of-voice system, add Gitea Actions full build, add venue cycling
- 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:
1 parent
f7486d7539
commit
a3768c2ce4
21 files changed
+230
-185
No files matched your search
+21
-21
@@ -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:
|
||||
|
||||
Reference in new issue
Block a user