Implement speech style toolbar live-edit refinements and whole speech show controls

- Added a new specification for the speech style toolbar live-edit, detailing immediate style application, scoped effect demonstration, and hover feedback.
- Introduced refinements to the speech style toolbar, including improved chooser sizing, exclusive stage editing during speech composition, and removal of redundant controls.
- Documented new stage controls for managing how the whole speech shows, including options for bubble arrangement, word appearance, and bubble motion.
- Created a new log file for speech padding syntax to track engine versioning.
This commit is contained in:
2026-10-03 14:49:22 -04:00
parent 6a1359f244
commit 6666173c4f
42 changed files with 9163 additions and 165 deletions
+18 -14
View File
@@ -106,8 +106,11 @@ static func reactive_role(action: Dictionary) -> ReactiveRole:
var tpl: Dictionary = ACTION_TEMPLATES.get(type, {})
var role: ReactiveRole = int(tpl.get("reactive_role", ReactiveRole.SEQUENTIAL))
var params: Dictionary = action.get("params", {})
if type == "speak" and bool(params.get("stop_current", action.get("stop_current", false))):
return ReactiveRole.SEQUENTIAL
if type == "speak":
if params.has("keep_acting") or action.has("keep_acting"):
return ReactiveRole.OVERLAY if bool(params.get("keep_acting", action.get("keep_acting", false))) else ReactiveRole.SEQUENTIAL
if bool(params.get("stop_current", action.get("stop_current", false))):
return ReactiveRole.SEQUENTIAL
return role
@@ -119,10 +122,9 @@ static func to_rule_action(action: Dictionary, target_id: int) -> Dictionary:
"walk_to":
params["target"] = action.get("target", Vector2.ZERO)
"speak":
params["text"] = String(action.get("text", ""))
params["duration"] = float(action.get("duration", 2.0))
if bool(action.get("stop_current", false)):
params["stop_current"] = true
for key: String in ["text", "duration", "stop_current", "keep_acting", "visual", "arrangement", "bubble_layout", "connect_bubbles", "reveal", "pop_in", "duration_mode", "placement", "bubbles"]:
if action.has(key):
params[key] = action[key].duplicate(true) if action[key] is Dictionary or action[key] is Array else action[key]
"wait":
params["duration"] = float(action.get("duration", 0.0))
"pick_up_prop":
@@ -144,13 +146,12 @@ static func from_rule_action(rule_action: Dictionary) -> Dictionary:
"walk_to":
return { "type": "walk_to", "target": params.get("target", Vector2.ZERO) }
"speak":
var speak: Dictionary = {
"type": "speak",
"text": String(params.get("text", "")),
"duration": float(params.get("duration", 2.0)),
}
if bool(params.get("stop_current", false)):
speak["stop_current"] = true
var speak: Dictionary = {"type": "speak"}
for key: String in ["text", "duration", "stop_current", "keep_acting", "visual", "arrangement", "bubble_layout", "connect_bubbles", "reveal", "pop_in", "duration_mode", "placement", "bubbles"]:
if params.has(key):
speak[key] = params[key].duplicate(true) if params[key] is Dictionary or params[key] is Array else params[key]
if not speak.has("keep_acting"):
speak["keep_acting"] = not bool(params.get("stop_current", false))
return speak
"wait":
return { "type": "wait", "duration": float(params.get("duration", 0.0)) }
@@ -180,7 +181,10 @@ static func summarize(action: Dictionary) -> String:
"speak":
var text := String(action.get("text", params.get("text", "")))
var dur := float(action.get("duration", params.get("duration", 2.0)))
var suffix: String = " — stops current" if bool(params.get("stop_current", action.get("stop_current", false))) else ""
var has_keep_acting: bool = params.has("keep_acting") or action.has("keep_acting")
var keep_acting: bool = bool(params.get("keep_acting", action.get("keep_acting", false)))
var legacy_stop_current: bool = bool(params.get("stop_current", action.get("stop_current", false)))
var suffix: String = " — keeps acting" if has_keep_acting and keep_acting else (" — stops current" if not has_keep_acting and legacy_stop_current else "")
return "Speak \"%s\" (%ss)%s" % [text, _fmt_duration(dur), suffix]
"wait":
var wd := float(action.get("duration", params.get("duration", 0.0)))