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
@@ -8,7 +8,7 @@ const FSM := preload("res://src/core/fsm.gd")
|
||||
## reaction logic. The presentation layer adds a visual avatar and navigation.
|
||||
## RefCounted on purpose: headless tests and CI do not need a scene tree.
|
||||
|
||||
signal interacted(level: int, tone: int)
|
||||
signal interacted(level: int)
|
||||
|
||||
var npc_id: String = ""
|
||||
var profile: NpcProfile = null
|
||||
@@ -61,15 +61,10 @@ func _build_fsm(initial_state: String) -> void:
|
||||
fsm.add_transition("THREATENING", "FORCING_ENTRY")
|
||||
fsm.start(initial_state)
|
||||
|
||||
func roll_reaction(level: int, tone: int) -> int:
|
||||
## Weighted pick from profile's reaction table for `level`, adjusted for tone.
|
||||
func roll_reaction(level: int) -> int:
|
||||
## Weighted pick from profile's reaction table for `level`.
|
||||
highest_escalation_received = maxi(highest_escalation_received, level)
|
||||
var weights: Dictionary = profile.pickup_reactions_per_level(level).duplicate()
|
||||
var tone_mod: float = profile.tone_modifiers.get(tone, 0.0)
|
||||
if tone_mod > 0.0 and weights.has(Rules.Reaction.COMPLY):
|
||||
# Shift weight mass toward compliance proportionally.
|
||||
var transferable: float = float(weights[Rules.Reaction.COMPLY]) * tone_mod
|
||||
weights[Rules.Reaction.COMPLY] += transferable * 0.5
|
||||
var roll_value := rng.randf()
|
||||
var total := 0.0
|
||||
for key in weights.keys():
|
||||
@@ -83,16 +78,15 @@ func roll_reaction(level: int, tone: int) -> int:
|
||||
return key
|
||||
return Rules.Reaction.LEAVE
|
||||
|
||||
func apply_player_action(level: int, tone: int) -> Dictionary:
|
||||
func apply_player_action(level: int) -> Dictionary:
|
||||
## Returns reaction to the player's action and updates FSM when needed.
|
||||
var performed_reaction := roll_reaction(level, tone)
|
||||
var performed_reaction := roll_reaction(level)
|
||||
reaction = performed_reaction
|
||||
reaction_set = true
|
||||
_update_state_for_reaction(performed_reaction)
|
||||
return {
|
||||
"npc_id": npc_id,
|
||||
"level_used": level,
|
||||
"tone": tone,
|
||||
"reaction": performed_reaction,
|
||||
"reaction_name": Rules.Reaction.find_key(performed_reaction),
|
||||
"new_state": fsm.current_state,
|
||||
|
||||
+3
-11
@@ -12,8 +12,7 @@ const Rules := preload("res://src/core/rules.gd")
|
||||
## Affects how likely the NPC is to argue, point, or threaten at each level.
|
||||
@export_range(0.0, 1.0) var temperament: float = 0.25
|
||||
|
||||
## Base compliance: probability the NPC obeys a level-1 polite direction.
|
||||
## Venue/scenario recalculates effective compliance from profile + tone + level.
|
||||
## Probability the NPC obeys a level-1 polite direction.
|
||||
@export_range(0.0, 1.0) var base_compliance: float = 0.8
|
||||
|
||||
## Probability that an NPC directed away will circle back later in the shift
|
||||
@@ -56,18 +55,11 @@ const Rules := preload("res://src/core/rules.gd")
|
||||
},
|
||||
}
|
||||
|
||||
@export var tone_modifiers: Dictionary = {
|
||||
Rules.Tone.FRIENDLY: 0.10, # + compliance
|
||||
Rules.Tone.PROFESSIONAL: 0.00,
|
||||
Rules.Tone.FIRM: -0.05,
|
||||
Rules.Tone.SUSPICIOUS: -0.15,
|
||||
}
|
||||
|
||||
## Delay the NPC waits before reacting to the player (frames/seconds scaled).
|
||||
@export_range(0.1, 5.0) var reaction_delay: float = 0.6
|
||||
|
||||
## Dialogue lines per tone and intent. Falls back to generic lines when empty.
|
||||
@export var dialogue_lines: Dictionary = {}
|
||||
## Dialogue lines this NPC uses. Falls back to generic lines when empty.
|
||||
@export var dialogue_lines: Array[String] = []
|
||||
|
||||
## Items the NPC is carrying, used by the handheld wand (The Joke Shop).
|
||||
## Values are item names: "keys", "belt", "phone", "weapon", "knife", etc.
|
||||
|
||||
@@ -108,21 +108,6 @@ enum Reaction {
|
||||
CALL_SOMEONE = 8,
|
||||
}
|
||||
|
||||
## Player dialogue tones.
|
||||
enum Tone {
|
||||
PROFESSIONAL = 0,
|
||||
FRIENDLY = 1,
|
||||
FIRM = 2,
|
||||
SUSPICIOUS = 3,
|
||||
}
|
||||
|
||||
const TONE_NAMES := {
|
||||
Tone.PROFESSIONAL: "Professional",
|
||||
Tone.FRIENDLY: "Friendly",
|
||||
Tone.FIRM: "Firm",
|
||||
Tone.SUSPICIOUS: "Suspicious",
|
||||
}
|
||||
|
||||
## Shift phases by time of day.
|
||||
enum Phase {
|
||||
EARLY = 0,
|
||||
|
||||
Reference in new issue
Block a user