From a8c527c3e47d92bc9c737f217e7d03e43f12f5fa Mon Sep 17 00:00:00 2001 From: Eneko Nieto Date: Mon, 20 Jan 2025 23:30:12 +0100 Subject: [PATCH] feat: ported escoria-ui-return-monkey-island-dialog-simple --- .../chooser/simple.gd | 7 +- .../commands/say_last_dialog_option.gd | 5 +- .../commands/say_random.gd | 7 +- .../commands/say_sequence.gd | 5 +- .../patterns/state_machine/state_machine.gd | 6 +- .../plugin.gd | 2 +- .../rtmi_dialog_simple.gd | 95 ++----------- .../states/dialog_choices.gd | 4 +- .../states/dialog_finish.gd | 4 +- .../states/dialog_interrupt.gd | 7 +- .../states/dialog_say.gd | 91 ++++++------ .../states/dialog_say_fast.gd | 6 +- .../states/dialog_say_finish.gd | 6 +- .../states/dialog_visible.gd | 12 +- .../types/avatar.gd | 82 ++++++----- .../types/avatar.tscn | 50 ++----- .../types/floating.gd | 133 +++++++++++------- .../turno_cocina/creditos/scrollingText.gd | 6 +- 18 files changed, 232 insertions(+), 296 deletions(-) diff --git a/addons/escoria-ui-return-monkey-island-dialog-simple/chooser/simple.gd b/addons/escoria-ui-return-monkey-island-dialog-simple/chooser/simple.gd index 7117240c..2fc44397 100644 --- a/addons/escoria-ui-return-monkey-island-dialog-simple/chooser/simple.gd +++ b/addons/escoria-ui-return-monkey-island-dialog-simple/chooser/simple.gd @@ -42,9 +42,8 @@ func show_chooser(): _option_node.add_theme_color_override("font_color", color_normal) _option_node.add_theme_color_override("font_color_hover", color_hover) _vbox.add_child(_option_node) - _option_node.connect("pressed", self, "_on_answer_selected", [ - option - ]) + + _option_node.pressed.connect(_on_answer_selected.bind(option)) # If we've no options left, signify as much and start the timer with a # very short interval so the appropriate signal can be fired. Note that @@ -78,7 +77,7 @@ func hide_chooser(): func _option_chosen(option: ESCDialogOption): _remove_avatar() $TimerProgress.value = 0 - emit_signal("option_chosen", option) + option_chosen.emit(option) # An option was chosen directly from the list diff --git a/addons/escoria-ui-return-monkey-island-dialog-simple/commands/say_last_dialog_option.gd b/addons/escoria-ui-return-monkey-island-dialog-simple/commands/say_last_dialog_option.gd index 9fe38218..54a4b5bf 100644 --- a/addons/escoria-ui-return-monkey-island-dialog-simple/commands/say_last_dialog_option.gd +++ b/addons/escoria-ui-return-monkey-island-dialog-simple/commands/say_last_dialog_option.gd @@ -9,7 +9,7 @@ class_name SayLastDialogOptionCommand # Return the descriptor of the arguments of this command func configure() -> ESCCommandArgumentDescriptor: - return ESCCommandArgumentDescriptor.new() + return ESCCommandArgumentDescriptor.new() # Run the command func run(_command_params: Array) -> int: @@ -42,7 +42,8 @@ func run(_command_params: Array) -> int: escoria.dialog_player.say( speaking_character_global_id, "", - text + text, + text # TODO (Eneko): should we pass real key? ) await escoria.dialog_player.say_finished escoria.current_state = escoria.GAME_STATE.DEFAULT diff --git a/addons/escoria-ui-return-monkey-island-dialog-simple/commands/say_random.gd b/addons/escoria-ui-return-monkey-island-dialog-simple/commands/say_random.gd index 9db0252b..4664aa9c 100644 --- a/addons/escoria-ui-return-monkey-island-dialog-simple/commands/say_random.gd +++ b/addons/escoria-ui-return-monkey-island-dialog-simple/commands/say_random.gd @@ -94,7 +94,7 @@ func run(command_params: Array) -> int: escoria.current_state = escoria.GAME_STATE.DEFAULT return ESCExecution.RC_CANCEL - var text = param_list_id + "_" + String(rng.randi_range(0,param_lenght -1)) + ':" "' + var text = param_list_id + "_" + String.num_int64(rng.randi_range(0,param_lenght -1)) + ':" "' var speaking_character_global_id = escoria.main.current_scene.player.global_id \ if param_global_id.to_upper() == CURRENT_PLAYER_KEYWORD \ @@ -103,7 +103,8 @@ func run(command_params: Array) -> int: escoria.dialog_player.say( speaking_character_global_id, "", - text + text, + text # TODO (Eneko): should we pass real key? ) await escoria.dialog_player.say_finished escoria.current_state = escoria.GAME_STATE.DEFAULT @@ -123,4 +124,4 @@ func interrupt(): escoria.logger.debug( self, "[%s] interrupt() function not implemented." % get_command_name() - ) \ No newline at end of file + ) diff --git a/addons/escoria-ui-return-monkey-island-dialog-simple/commands/say_sequence.gd b/addons/escoria-ui-return-monkey-island-dialog-simple/commands/say_sequence.gd index 828fafce..73b77a92 100644 --- a/addons/escoria-ui-return-monkey-island-dialog-simple/commands/say_sequence.gd +++ b/addons/escoria-ui-return-monkey-island-dialog-simple/commands/say_sequence.gd @@ -107,7 +107,8 @@ func run(command_params: Array) -> int: escoria.dialog_player.say( speaking_character_global_id, "", - text + text, + text # TODO (Eneko): should we pass real key? ) await escoria.dialog_player.say_finished escoria.current_state = escoria.GAME_STATE.DEFAULT @@ -137,4 +138,4 @@ func interrupt(): escoria.logger.debug( self, "[%s] interrupt() function not implemented." % get_command_name() - ) \ No newline at end of file + ) diff --git a/addons/escoria-ui-return-monkey-island-dialog-simple/patterns/state_machine/state_machine.gd b/addons/escoria-ui-return-monkey-island-dialog-simple/patterns/state_machine/state_machine.gd index 7b1dbf12..f3cdc965 100644 --- a/addons/escoria-ui-return-monkey-island-dialog-simple/patterns/state_machine/state_machine.gd +++ b/addons/escoria-ui-return-monkey-island-dialog-simple/patterns/state_machine/state_machine.gd @@ -16,7 +16,7 @@ the node that inherits from this state machine interface If you don't the game will crash (on purpose, so you won't forget to initialize the state machine) """ -@export var START_STATE: NodePath +@export var START_STATE: Node var states_map = {} var states_stack = [] # can also be used as a pushdown automaton @@ -27,7 +27,7 @@ var _active = false: set = set_active func initialize(start_state): for child in get_children(): - child.connect("finished", Callable(self, "_change_state")) + child.finished.connect(_change_state) set_active(true) states_stack.push_front(start_state) @@ -76,7 +76,7 @@ func _change_state(state_name): current_state = states_stack[0] - emit_signal("state_changed", current_state) + state_changed.emit(current_state) #if state_name != "previous": current_state.enter() diff --git a/addons/escoria-ui-return-monkey-island-dialog-simple/plugin.gd b/addons/escoria-ui-return-monkey-island-dialog-simple/plugin.gd index cc685cdf..06fd41e2 100644 --- a/addons/escoria-ui-return-monkey-island-dialog-simple/plugin.gd +++ b/addons/escoria-ui-return-monkey-island-dialog-simple/plugin.gd @@ -64,7 +64,7 @@ func _disable_plugin(): # Add ourselves to the list of dialog managers -func enable_plugin(): +func _enable_plugin(): print("Enabling plugin Escoria Dialog Simple") if EscoriaPlugin.register_dialog_manager(self, MANAGER_CLASS): diff --git a/addons/escoria-ui-return-monkey-island-dialog-simple/rtmi_dialog_simple.gd b/addons/escoria-ui-return-monkey-island-dialog-simple/rtmi_dialog_simple.gd index 2a13c54d..f07d011d 100644 --- a/addons/escoria-ui-return-monkey-island-dialog-simple/rtmi_dialog_simple.gd +++ b/addons/escoria-ui-return-monkey-island-dialog-simple/rtmi_dialog_simple.gd @@ -29,7 +29,6 @@ func _ready() -> void: escoria.connect("paused", Callable(self, "_on_paused")) - # Check whether a specific type is supported by the # dialog plugin # @@ -40,25 +39,6 @@ func has_type(type: String) -> bool: return true if type in ["floating"] else false -# Check whether a specific chooser type is supported by the -# dialog plugin -# -# #### Parameters -# - type: required chooser type -# *Returns* Whether the type is supported or not -func has_chooser_type(type: String) -> bool: - return true if type == "simple" else false - -# Instructs the dialog manager to preserve the next dialog box used by a `say` -# command until a call to `disable_preserve_dialog_box` is made. -# -# This method should be idempotent, i.e. if called after the first time and -# prior to `disable_preserve_dialog_box` being called, the result should be the -# same. -func enable_preserve_dialog_box() -> void: - _should_preserve_dialog_box = true - - # Instructs the dialog manager to no longer preserve the currently-preserved # dialog box or to not preserve the next dialog box used by a `say` command # (this is the default state). @@ -74,36 +54,6 @@ func disable_preserve_dialog_box() -> void: _preserved_type_player_type = "" _dialog_player.remove_child(_dialog_tip) -# Output a text said by the item specified by the global id. Emit -# `say_finished` after finishing displaying the text. -# -# #### Parameters -# - dialog_player: Node of the dialog player in the UI -# - global_id: Global id of the item that is speaking -# - text: Text to say, optional prefixed by a translation key separated -# by a ":" -# - type: Type of dialog box to use -func say(dialog_player: Node, global_id: String, text: String, type: String): - _dialog_player = dialog_player - - _initialize_say_states(global_id, text, type) - - if _should_preserve_dialog_box: - # If the dialog box type doesn't match what's currently being reused (if anything), - # we want to remove the old one (if it exists) and then initialize and add the new dialog - # box type to the dialog player - if type != _preserved_type_player_type: - if _dialog_player.get_children().has(_type_player): - _dialog_player.remove_child(_type_player) - - _init_type_player(type) - - _preserved_type_player_type = type - else: - _init_type_player(type) - - state_machine._change_state("say") - func do_say(global_id: String, text: String) -> void: # Only add_child here in order to prevent _type_player from running its _process method @@ -116,8 +66,6 @@ func do_say(global_id: String, text: String) -> void: _type_player.say(global_id, text) - - func _init_type_player(type: String) -> void: if type == "floating": _type_player = preload(\ @@ -131,16 +79,8 @@ func _init_type_player(type: String) -> void: "res://addons/escoria-ui-return-monkey-island-dialog-simple/dialog_tip.tscn"\ ).instantiate() - _type_player.connect("say_finished", Callable(self, "_on_say_finished")) - _type_player.connect("say_visible", Callable(self, "_on_say_visible")) - -func _initialize_say_states(global_id: String, text: String, type: String) -> void: - state_machine.states_map["say"].initialize(self, global_id, text, type) - state_machine.states_map["finish"].initialize(_dialog_player) - state_machine.states_map["say_fast"].initialize(self) - state_machine.states_map["say_finish"].initialize(self) - state_machine.states_map["visible"].initialize(self) - state_machine.states_map["interrupt"].initialize(self) + _type_player.say_finished.connect(_on_say_finished) + _type_player.say_visible.connect(_on_say_visible) func _on_say_finished(): @@ -150,11 +90,12 @@ func _on_say_finished(): _is_saying = false - emit_signal("say_finished") + say_finished.emit() + func _on_say_visible(): - emit_signal("say_visible") - + say_visible.emit() + # Present an option chooser to the player and sends the signal # `option_chosen` with the chosen dialog option @@ -188,19 +129,7 @@ func do_choose(dialog_player: Node, dialog: ESCDialog, type: String = "simple"): if option is ESCDialogOption: escoria.globals_manager.set_global("ESC_DIALOG_CHOSEN_OPTION", option.option) # END MODIFIED FOR RETURN TO MONKEY UI - emit_signal("option_chosen", option) - - -# Trigger running the dialogue faster -func speedup(): - if is_instance_valid(_type_player): - _type_player.speedup() - - -# Trigger an instant finish of the current dialog -func finish(): - if is_instance_valid(_type_player): - _type_player.finish() + option_chosen.emit(option) # The say command has been interrupted, cancel the dialog display @@ -215,21 +144,17 @@ func interrupt(): _dialog_player.remove_child(_type_player) remove_dialop_tip() - emit_signal("say_finished") - - -# To be called if voice audio has finished. -func voice_audio_finished(): - if is_instance_valid(_type_player): - _type_player.voice_audio_finished() + say_finished.emit() func add_dialog_tip(): if not _dialog_player.get_children().has(_dialog_tip): _dialog_player.add_child(_dialog_tip) + func remove_dialop_tip(): _dialog_player.remove_child(_dialog_tip) + func _on_paused(): remove_dialop_tip() diff --git a/addons/escoria-ui-return-monkey-island-dialog-simple/states/dialog_choices.gd b/addons/escoria-ui-return-monkey-island-dialog-simple/states/dialog_choices.gd index 3596f86b..70a5806e 100644 --- a/addons/escoria-ui-return-monkey-island-dialog-simple/states/dialog_choices.gd +++ b/addons/escoria-ui-return-monkey-island-dialog-simple/states/dialog_choices.gd @@ -40,5 +40,5 @@ func update(_delta): escoria.logger.trace(self, "Dialog State Machine: 'choices' -> 'idle'") - emit_signal("finished", "idle") - _dialog_player.emit_signal("option_chosen", option) + finished.emit("idle") + _dialog_player.option_chosen.emit(option) diff --git a/addons/escoria-ui-return-monkey-island-dialog-simple/states/dialog_finish.gd b/addons/escoria-ui-return-monkey-island-dialog-simple/states/dialog_finish.gd index eb6b0a7f..3253ccb8 100644 --- a/addons/escoria-ui-return-monkey-island-dialog-simple/states/dialog_finish.gd +++ b/addons/escoria-ui-return-monkey-island-dialog-simple/states/dialog_finish.gd @@ -17,5 +17,5 @@ func enter(): func update(_delta): escoria.logger.trace(self, "Dialog State Machine: 'finish' -> 'idle'") - emit_signal("finished", "idle") - _dialog_player.emit_signal("say_finished") + finished.emit("idle") + _dialog_player.say_finished.emit() diff --git a/addons/escoria-ui-return-monkey-island-dialog-simple/states/dialog_interrupt.gd b/addons/escoria-ui-return-monkey-island-dialog-simple/states/dialog_interrupt.gd index 7a865f2a..07b210b5 100644 --- a/addons/escoria-ui-return-monkey-island-dialog-simple/states/dialog_interrupt.gd +++ b/addons/escoria-ui-return-monkey-island-dialog-simple/states/dialog_interrupt.gd @@ -13,13 +13,12 @@ func enter(): escoria.logger.trace(self, "Dialog State Machine: Entered 'interrupt'.") if _dialog_manager != null: - if not _dialog_manager.is_connected("say_finished", Callable(self, "_on_say_finished")): - _dialog_manager.connect("say_finished", Callable(self, "_on_say_finished")) + if not _dialog_manager.say_finished.is_connected(_on_say_finished): + _dialog_manager.say_finished.connect(_on_say_finished) _dialog_manager.interrupt() func _on_say_finished() -> void: escoria.logger.trace(self, "Dialog State Machine: 'interrupt' -> 'finish'") - emit_signal("finished", "finish") - + finished.emit("finish") diff --git a/addons/escoria-ui-return-monkey-island-dialog-simple/states/dialog_say.gd b/addons/escoria-ui-return-monkey-island-dialog-simple/states/dialog_say.gd index 1ca5b06e..2934fa24 100644 --- a/addons/escoria-ui-return-monkey-island-dialog-simple/states/dialog_say.gd +++ b/addons/escoria-ui-return-monkey-island-dialog-simple/states/dialog_say.gd @@ -1,11 +1,7 @@ extends "res://addons/escoria-ui-return-monkey-island-dialog-simple/patterns/state_machine/state.gd" -# A regular expression that separates the translation key from the text -const KEYTEXT_REGEX = "^((?[^:]+):)?\"(?.+)\"" - - -# Reference to the currently playing dialog manager +# Reference to the currently playing dialog manager var _dialog_manager: ESCDialogManager = null # Character that is talking @@ -14,27 +10,28 @@ var _character: String # UI to use for the dialog var _type: String +# Translation key +var _key: String = "" + # Text to say var _text: String -# Regular expression object for the separation of key and text -var _keytext_regex: RegEx = RegEx.new() - var _ready_to_say: bool +# flag for whether the dialog manager has started to "say" to ensure that it has +# prior to exiting this state as other states need this to happen to continue +# (other states rely on the setup that the dialog manager does) +var _say_started: bool + var _stop_talking_animation_on_option: String -# Constructor -func _init() -> void: - _keytext_regex.compile(KEYTEXT_REGEX) - - -func initialize(dialog_manager: ESCDialogManager, character: String, text: String, type: String) -> void: +func initialize(dialog_manager: ESCDialogManager, character: String, text: String, type: String, key: String) -> void: _dialog_manager = dialog_manager _character = character _text = text _type = type + _key = key _stop_talking_animation_on_option = \ ESCProjectSettingsManager.get_setting(RTMISimpleDialogSettings.STOP_TALKING_ANIMATION_ON) @@ -53,17 +50,17 @@ func handle_input(_event): func _handle_left_click_action(left_click_action: String) -> void: match left_click_action: RTMISimpleDialogSettings.LEFT_CLICK_ACTION_SPEED_UP: - if _dialog_manager.is_connected("say_visible", Callable(self, "_on_say_visible")): - _dialog_manager.disconnect("say_visible", Callable(self, "_on_say_visible")) + if _dialog_manager.say_visible.is_connected(_on_say_visible): + _dialog_manager.say_visible.disconnect(_on_say_visible) escoria.logger.trace(self, "Dialog State Machine: 'say' -> 'say_fast'") - emit_signal("finished", "say_fast") + finished.emit("say_fast") RTMISimpleDialogSettings.LEFT_CLICK_ACTION_INSTANT_FINISH: - if _dialog_manager.is_connected("say_visible", Callable(self, "_on_say_visible")): - _dialog_manager.disconnect("say_visible", Callable(self, "_on_say_visible")) + if _dialog_manager.say_visible.is_connected(_on_say_visible): + _dialog_manager.say_visible.disconnect(_on_say_visible) escoria.logger.trace(self, "Dialog State Machine: 'say' -> 'say_finish'") - emit_signal("finished", "say_finish") + finished.emit("say_finish") get_viewport().set_input_as_handled() @@ -71,28 +68,18 @@ func _handle_left_click_action(left_click_action: String) -> void: func enter(): escoria.logger.trace(self, "Dialog State Machine: Entered 'say'.") - if not _dialog_manager.is_connected("say_visible", Callable(self, "_on_say_visible")): - _dialog_manager.connect("say_visible", Callable(self, "_on_say_visible")) + _say_started = false + + if not _dialog_manager.say_visible.is_connected(_on_say_visible): + _dialog_manager.say_visible.connect(_on_say_visible) - var matches = _keytext_regex.search(_text) - - if not matches: - escoria.logger.error( - self, - "Unexpected text encountered: %s." % _text - ) - - var key = matches.get_string("key") - - if matches.get_string("key") != "": - var _speech_resource = _get_voice_file( - matches.get_string("key") - ) + if _key and not _key.is_empty(): + var _speech_resource = _get_voice_file(_key) if _speech_resource == "": escoria.logger.warn( self, - "Unable to find voice file with key '%s'." % matches.get_string("key") + "Unable to find voice file with key '%s'." % _key ) else: ( @@ -104,34 +91,38 @@ func enter(): if not ( escoria.object_manager.get_object(escoria.object_manager.SPEECH).node\ as ESCSpeechPlayer - ).stream.is_connected("finished", Callable(self, "_on_audio_finished")): + ).stream.finished.is_connected(_on_audio_finished): ( escoria.object_manager.get_object(escoria.object_manager.SPEECH).node\ as ESCSpeechPlayer - ).stream.connect("finished", Callable(self, "_on_audio_finished")) + ).stream.finished.connect(_on_audio_finished) - var translated_text: String = tr(matches.get_string("key")) + var translated_text: String = tr(_key) # Only update the text if the translated text was found; otherwise, raise # a warning and use the original, untranslated text. - if translated_text == matches.get_string("key"): + if translated_text == _key: escoria.logger.warn( self, - "Unable to find position key '%s'. Using untranslated text." % matches.get_string("key") + "Unable to find translation key '%s'. Using untranslated text." % _key ) - _text = matches.get_string("text") else: _text = translated_text - else: - _text = matches.get_string("text") _ready_to_say = true +func exit() -> void: + if not _say_started: + _dialog_manager.do_say(_character, _text) + _say_started = true + + func update(_delta): if _ready_to_say: _dialog_manager.do_say(_character, _text) + _say_started = true _ready_to_say = false @@ -148,15 +139,15 @@ func _get_voice_file(key: String, start: String = "") -> String: start = ESCProjectSettingsManager.get_setting( ESCProjectSettingsManager.SPEECH_FOLDER ) - var _dir = DirAccess.new() - if _dir.open(start) == OK: + var _dir = DirAccess.open(start) + if _dir != null: _dir.list_dir_begin() # TODOConverter3To4 fill missing arguments https://github.com/godotengine/godot/pull/40547 var file_name = _dir.get_next() while file_name != "": if _dir.current_is_dir(): var _voice_file = _get_voice_file( key, - start.plus_file(file_name) + start.path_join(file_name) ) if _voice_file != "": return _voice_file @@ -167,14 +158,14 @@ func _get_voice_file(key: String, start: String = "") -> String: ESCProjectSettingsManager.SPEECH_EXTENSION ) ]: - return start.plus_file(file_name.trim_suffix(".import")) + return start.path_join(file_name.trim_suffix(".import")) file_name = _dir.get_next() return "" func _on_say_visible() -> void: escoria.logger.trace(self, "Dialog State Machine: 'say' -> 'visible'") - emit_signal("finished", "visible") + finished.emit("visible") func _on_audio_finished() -> void: diff --git a/addons/escoria-ui-return-monkey-island-dialog-simple/states/dialog_say_fast.gd b/addons/escoria-ui-return-monkey-island-dialog-simple/states/dialog_say_fast.gd index e61586ce..f2271002 100644 --- a/addons/escoria-ui-return-monkey-island-dialog-simple/states/dialog_say_fast.gd +++ b/addons/escoria-ui-return-monkey-island-dialog-simple/states/dialog_say_fast.gd @@ -16,8 +16,8 @@ func enter(): escoria.inputs_manager.INPUT_NONE and \ _dialog_manager != null: - if not _dialog_manager.is_connected("say_visible", Callable(self, "_on_say_visible")): - _dialog_manager.connect("say_visible", Callable(self, "_on_say_visible")) + if not _dialog_manager.say_visible.is_connected(_on_say_visible): + _dialog_manager.say_visible.connect(_on_say_visible) _dialog_manager.speedup() else: @@ -26,4 +26,4 @@ func enter(): func _on_say_visible() -> void: escoria.logger.trace(self, "Dialog State Machine: 'say_fast' -> 'visible'") - emit_signal("finished", "visible") + finished.emit("visible") diff --git a/addons/escoria-ui-return-monkey-island-dialog-simple/states/dialog_say_finish.gd b/addons/escoria-ui-return-monkey-island-dialog-simple/states/dialog_say_finish.gd index 52263f2a..4b0b41cd 100644 --- a/addons/escoria-ui-return-monkey-island-dialog-simple/states/dialog_say_finish.gd +++ b/addons/escoria-ui-return-monkey-island-dialog-simple/states/dialog_say_finish.gd @@ -16,8 +16,8 @@ func enter(): escoria.inputs_manager.INPUT_NONE and \ _dialog_manager != null: - if not _dialog_manager.is_connected("say_visible", Callable(self, "_on_say_visible")): - _dialog_manager.connect("say_visible", Callable(self, "_on_say_visible")) + if not _dialog_manager.say_visible.is_connected(_on_say_visible): + _dialog_manager.say_visible.connect(_on_say_visible) _dialog_manager.finish() else: @@ -26,4 +26,4 @@ func enter(): func _on_say_visible() -> void: escoria.logger.trace(self, "Dialog State Machine: 'say_finish' -> 'visible'") - emit_signal("finished", "visible") + finished.emit("visible") diff --git a/addons/escoria-ui-return-monkey-island-dialog-simple/states/dialog_visible.gd b/addons/escoria-ui-return-monkey-island-dialog-simple/states/dialog_visible.gd index c4b331ec..558abf45 100644 --- a/addons/escoria-ui-return-monkey-island-dialog-simple/states/dialog_visible.gd +++ b/addons/escoria-ui-return-monkey-island-dialog-simple/states/dialog_visible.gd @@ -12,8 +12,8 @@ func initialize(dialog_manager: ESCDialogManager) -> void: func enter(): escoria.logger.trace(self, "Dialog State Machine: Entered 'visible'.") - if not _dialog_manager.is_connected("say_finished", Callable(self, "_on_say_finished")): - _dialog_manager.connect("say_finished", Callable(self, "_on_say_finished")) + if not _dialog_manager.say_finished.is_connected(_on_say_finished): + _dialog_manager.say_finished.connect(_on_say_finished) func handle_input(_event): @@ -21,14 +21,14 @@ func handle_input(_event): if escoria.inputs_manager.input_mode != \ escoria.inputs_manager.INPUT_NONE: - if _dialog_manager.is_connected("say_finished", Callable(self, "_on_say_finished")): - _dialog_manager.disconnect("say_finished", Callable(self, "_on_say_finished")) + if _dialog_manager.say_finished.is_connected(_on_say_finished): + _dialog_manager.say_finished.disconnect(_on_say_finished) - emit_signal("finished", "interrupt") + finished.emit("interrupt") get_viewport().set_input_as_handled() # Handles the end of a say function after it has emitted say_finished. func _on_say_finished(): escoria.logger.trace(self, "Dialog State Machine: 'visible' -> 'finish'") - emit_signal("finished", "finish") + finished.emit("finish") diff --git a/addons/escoria-ui-return-monkey-island-dialog-simple/types/avatar.gd b/addons/escoria-ui-return-monkey-island-dialog-simple/types/avatar.gd index ec4d7247..1daedd7d 100644 --- a/addons/escoria-ui-return-monkey-island-dialog-simple/types/avatar.gd +++ b/addons/escoria-ui-return-monkey-island-dialog-simple/types/avatar.gd @@ -37,13 +37,12 @@ var _current_line: String @onready var text_node = $Panel/MarginContainer/HSplitContainer/text # The tween node for text animations -@onready var tween = $Panel/MarginContainer/HSplitContainer/text/Tween +@onready var tween: Tween3 = Tween3.new(self) # Whether the dialog manager is paused @onready var is_paused: bool = true - # Build up the UI func _ready(): _text_time_per_character = ProjectSettings.get_setting( @@ -56,11 +55,11 @@ func _ready(): "%s setting must be a non-negative number. Will use default value of %s." % [ RTMISimpleDialogSettings.TEXT_TIME_PER_LETTER_MS, - RTMISimpleDialogSettings.TEXT_TIME_PER_LETTER_MS_DEFAULT_VALUE + escoria.TEXT_TIME_PER_LETTER_MS_DEFAULT_VALUE ] ) - _text_time_per_character = RTMISimpleDialogSettings.TEXT_TIME_PER_LETTER_MS_DEFAULT_VALUE + _text_time_per_character = escoria.TEXT_TIME_PER_LETTER_MS_DEFAULT_VALUE _fast_text_time_per_character = ProjectSettings.get_setting( RTMISimpleDialogSettings.TEXT_TIME_PER_LETTER_MS_FAST @@ -72,11 +71,11 @@ func _ready(): "%s setting must be a non-negative number. Will use default value of %s." % [ RTMISimpleDialogSettings.TEXT_TIME_PER_LETTER_MS_FAST, - RTMISimpleDialogSettings.TEXT_TIME_PER_LETTER_MS_FAST_DEFAULT_VALUE + escoria.TEXT_TIME_PER_LETTER_MS_FAST_DEFAULT_VALUE ] ) - _fast_text_time_per_character = RTMISimpleDialogSettings.TEXT_TIME_PER_LETTER_MS_FAST_DEFAULT_VALUE + _fast_text_time_per_character = escoria.TEXT_TIME_PER_LETTER_MS_FAST_DEFAULT_VALUE _reading_speed_in_wpm = ProjectSettings.get_setting( RTMISimpleDialogSettings.READING_SPEED_IN_WPM @@ -88,23 +87,21 @@ func _ready(): "%s setting must be a positive number. Will use default value of %s." % [ RTMISimpleDialogSettings.READING_SPEED_IN_WPM, - RTMISimpleDialogSettings.READING_SPEED_IN_WPM_DEFAULT_VALUE + escoria.READING_SPEED_IN_WPM_DEFAULT_VALUE ] ) - _reading_speed_in_wpm = RTMISimpleDialogSettings.READING_SPEED_IN_WPM_DEFAULT_VALUE + _reading_speed_in_wpm = escoria.READING_SPEED_IN_WPM_DEFAULT_VALUE _word_regex.compile("\\S+") text_node.bbcode_enabled = true - tween.connect( - "tween_completed", - self, - "_on_dialog_line_typed" - ) + tween.finished.connect(_on_dialog_line_typed.bind("", "")) - escoria.connect("paused", Callable(self, "_on_paused")) - escoria.connect("resumed", Callable(self, "_on_resumed")) + escoria.paused.connect(_on_paused) + escoria.resumed.connect(_on_resumed) + + tree_exited.connect(_on_tree_exited) # Switch the current character @@ -145,13 +142,15 @@ func say(character: String, line: String): text_node.text = tr(line) - text_node.percent_visible = 0.0 + text_node.visible_ratio = 0.0 var time_show_full_text = _text_time_per_character / 1000 * len(line) - tween.interpolate_property(text_node, "percent_visible", + tween.reset() + + tween.interpolate_property(text_node, "visible_ratio", 0.0, 1.0, time_show_full_text, Tween.TRANS_LINEAR, Tween.EASE_IN_OUT) - tween.start() + tween.play() # Called by the dialog player when the @@ -159,19 +158,19 @@ func speedup(): if not _is_speeding_up: _is_speeding_up = true var time_show_full_text = _fast_text_time_per_character / 1000 * len(_current_line) - tween.remove_all() - tween.interpolate_property(text_node, "percent_visible", - text_node.percent_visible, 1.0, time_show_full_text, + tween.reset() + tween.interpolate_property(text_node, "visible_ratio", + text_node.visible_ratio, 1.0, time_show_full_text, Tween.TRANS_LINEAR, Tween.EASE_IN_OUT) - tween.start() + tween.play() # Called by the dialog player when user wants to finish dialogue immediately. func finish(): - tween.remove_all() - tween.interpolate_property(text_node, "percent_visible", - text_node.percent_visible, 1.0, 0.0) - tween.start() + tween.reset() + tween.interpolate_property(text_node, "visible_ratio", + text_node.visible_ratio, 1.0, 0.0) + tween.play() # To be called if voice audio has finished. @@ -191,10 +190,13 @@ func _on_dialog_line_typed(object, key): text_node.visible_characters = -1 var time_to_disappear: float = _calculate_time_to_disappear() - $Timer.start(time_to_disappear) - $Timer.connect("timeout", Callable(self, "_on_dialog_finished")) - emit_signal("say_visible") + if not $Timer.timeout.is_connected(_on_dialog_finished): + $Timer.timeout.connect(_on_dialog_finished) + + $Timer.start(time_to_disappear) + + say_visible.emit() func _calculate_time_to_disappear() -> float: @@ -207,21 +209,31 @@ func _get_number_of_words() -> int: # Ending the dialog func _on_dialog_finished(): + $Timer.stop() + # Only trigger to clear the text if we aren't limiting the clearing trigger to a click. if not ESCProjectSettingsManager.get_setting(RTMISimpleDialogSettings.CLEAR_TEXT_BY_CLICK_ONLY): - emit_signal("say_finished") - queue_free() + say_finished.emit() # Handler managing pause notification from Escoria func _on_paused(): - if tween.is_active(): + if tween.is_running(): is_paused = true - tween.stop_all() + tween.stop() # Handler managing resume notification from Escoria func _on_resumed(): - if not tween.is_active(): + if not tween.is_running(): + # We can't rely on "show()" to make an invisible popup reappear, as per the docs for + # CanvasItem. Instead, we need to use one of the popup_* methods. + if is_inside_tree(): + popup_centered() + is_paused = false - tween.resume_all() + tween.resume() + + +func _on_tree_exited(): + queue_free() diff --git a/addons/escoria-ui-return-monkey-island-dialog-simple/types/avatar.tscn b/addons/escoria-ui-return-monkey-island-dialog-simple/types/avatar.tscn index 441acdcb..59535b8d 100644 --- a/addons/escoria-ui-return-monkey-island-dialog-simple/types/avatar.tscn +++ b/addons/escoria-ui-return-monkey-island-dialog-simple/types/avatar.tscn @@ -1,68 +1,46 @@ -[gd_scene load_steps=2 format=2] +[gd_scene load_steps=2 format=3 uid="uid://cp75ofyuetxux"] -[ext_resource path="res://addons/escoria-ui-return-monkey-island-dialog-simple/types/avatar.gd" type="Script" id=1] +[ext_resource type="Script" path="res://addons/escoria-ui-return-monkey-island-dialog-simple/types/avatar.gd" id="1"] [node name="dialog_box" type="Popup"] -anchor_right = 1.0 -anchor_bottom = 1.0 -offset_right = -782.0 -offset_bottom = -734.0 -script = ExtResource( 1 ) -__meta__ = { -"_edit_use_anchors_": false -} +size = Vector2i(510, 180) +visible = true +script = ExtResource("1") [node name="Timer" type="Timer" parent="."] [node name="Panel" type="Panel" parent="."] +anchors_preset = 15 anchor_right = 1.0 anchor_bottom = 1.0 -__meta__ = { -"_edit_use_anchors_": false -} [node name="MarginContainer" type="MarginContainer" parent="Panel"] +layout_mode = 0 anchor_right = 1.0 anchor_bottom = 1.0 -theme_override_constants/margin_right = 20 -theme_override_constants/margin_top = 20 theme_override_constants/margin_left = 20 +theme_override_constants/margin_top = 20 +theme_override_constants/margin_right = 20 theme_override_constants/margin_bottom = 20 -__meta__ = { -"_edit_use_anchors_": false -} [node name="HSplitContainer" type="HSplitContainer" parent="Panel/MarginContainer"] -offset_left = 20.0 -offset_top = 20.0 -offset_right = 478.0 -offset_bottom = 146.0 +layout_mode = 2 theme_override_constants/separation = 35 dragger_visibility = 1 [node name="VBoxContainer" type="VBoxContainer" parent="Panel/MarginContainer/HSplitContainer"] -offset_right = 88.0 -offset_bottom = 126.0 +layout_mode = 2 size_flags_horizontal = 3 size_flags_stretch_ratio = 0.3 [node name="avatar" type="TextureRect" parent="Panel/MarginContainer/HSplitContainer/VBoxContainer"] -offset_right = 88.0 -offset_bottom = 108.0 +layout_mode = 2 size_flags_horizontal = 3 size_flags_vertical = 3 -expand = true +stretch_mode = 4 [node name="text" type="RichTextLabel" parent="Panel/MarginContainer/HSplitContainer"] -offset_left = 123.0 -offset_right = 458.0 -offset_bottom = 126.0 +layout_mode = 2 size_flags_horizontal = 3 bbcode_enabled = true text = "Here be some text" -text = "Here be some text" -__meta__ = { -"_edit_use_anchors_": false -} - -[node name="Tween" type="Tween" parent="Panel/MarginContainer/HSplitContainer/text"] diff --git a/addons/escoria-ui-return-monkey-island-dialog-simple/types/floating.gd b/addons/escoria-ui-return-monkey-island-dialog-simple/types/floating.gd index 7113120a..4c93d934 100644 --- a/addons/escoria-ui-return-monkey-island-dialog-simple/types/floating.gd +++ b/addons/escoria-ui-return-monkey-island-dialog-simple/types/floating.gd @@ -34,7 +34,7 @@ var _current_line: String # Tween node for text animation -@onready var tween: Tween = $Tween +@onready var tween: Tween3 = Tween3.new(self) # The node showing the text @onready var text_node: RichTextLabel = self @@ -42,6 +42,7 @@ var _current_line: String # Whether the dialog manager is paused @onready var is_paused: bool = true +var dialog_location_node = null # Enable bbcode and catch the signal when a tween completed func _ready(): @@ -55,11 +56,11 @@ func _ready(): "%s setting must be a non-negative number. Will use default value of %s." % [ RTMISimpleDialogSettings.TEXT_TIME_PER_LETTER_MS, - RTMISimpleDialogSettings.TEXT_TIME_PER_LETTER_MS_DEFAULT_VALUE + escoria.TEXT_TIME_PER_LETTER_MS_DEFAULT_VALUE ] ) - _text_time_per_character = RTMISimpleDialogSettings.TEXT_TIME_PER_LETTER_MS_DEFAULT_VALUE + _text_time_per_character = escoria.TEXT_TIME_PER_LETTER_MS_DEFAULT_VALUE _fast_text_time_per_character = ProjectSettings.get_setting( RTMISimpleDialogSettings.TEXT_TIME_PER_LETTER_MS_FAST @@ -71,11 +72,11 @@ func _ready(): "%s setting must be a non-negative number. Will use default value of %s." % [ RTMISimpleDialogSettings.TEXT_TIME_PER_LETTER_MS_FAST, - RTMISimpleDialogSettings.TEXT_TIME_PER_LETTER_MS_FAST_DEFAULT_VALUE + escoria.TEXT_TIME_PER_LETTER_MS_FAST_DEFAULT_VALUE ] ) - _fast_text_time_per_character = RTMISimpleDialogSettings.TEXT_TIME_PER_LETTER_MS_FAST_DEFAULT_VALUE + _fast_text_time_per_character = escoria.TEXT_TIME_PER_LETTER_MS_FAST_DEFAULT_VALUE _reading_speed_in_wpm = ProjectSettings.get_setting( RTMISimpleDialogSettings.READING_SPEED_IN_WPM @@ -87,41 +88,36 @@ func _ready(): "%s setting must be a positive number. Will use default value of %s." % [ RTMISimpleDialogSettings.READING_SPEED_IN_WPM, - RTMISimpleDialogSettings.READING_SPEED_IN_WPM_DEFAULT_VALUE + escoria.READING_SPEED_IN_WPM_DEFAULT_VALUE ] ) - _reading_speed_in_wpm = RTMISimpleDialogSettings.READING_SPEED_IN_WPM_DEFAULT_VALUE + _reading_speed_in_wpm = escoria.READING_SPEED_IN_WPM_DEFAULT_VALUE _word_regex.compile("\\S+") bbcode_enabled = true - $Tween.connect("tween_completed", Callable(self, "_on_dialog_line_typed")) + + tween.finished.connect(_on_dialog_line_typed.bind("", "")) - connect("tree_exiting", Callable(self, "_on_tree_exiting")) + tree_exiting.connect(_on_tree_exiting) - escoria.connect("paused", Callable(self, "_on_paused")) - escoria.connect("resumed", Callable(self, "_on_resumed")) + escoria.paused.connect(_on_paused) + escoria.resumed.connect(_on_resumed) _current_line = "" func _process(delta): if _current_character.is_inside_tree() and \ - _current_character.has_node("dialog_position"): + is_instance_valid(dialog_location_node): # Position the RichTextLabel on the character's dialog position, if any. - position = _current_character.get_node("dialog_position") \ - super.get_global_transform_with_canvas().origin + position = dialog_location_node.get_global_transform_with_canvas().origin position.x -= size.x / 2 - if position.x < 0: - position.x = 0 + _account_for_margin_x() - var screen_margin = position.x + size.x - \ - ProjectSettings.get("display/window/size/viewport_width") - - if screen_margin > 0: - position.x -= screen_margin + _account_for_margin_y() # Make a character say something @@ -139,41 +135,52 @@ func say(character: String, line: String) : # Position the RichTextLabel on the character's dialog position, if any. _current_character = escoria.object_manager.get_object(character).node + var dialog_location_count:int = 0 + + for c in escoria.object_manager.get_object(character).node.get_children(): + if c is Marker2D: + # Identify any Postion2D nodes + if c is ESCDialogLocation: + dialog_location_count += 1 + dialog_location_node = c + + if dialog_location_count > 1: + escoria.logger.warn( + self, + "Multiple ESCDialogLocation nodes found " + + "object %s. Last one will be used." % _current_character) + # Set text color to color set in the actor var text_color = _current_character.dialog_color var text_color_html = text_color.to_html(false) text_node.text = "[center][color=#" + text_color_html + "]" \ - super.format([text_color_html]) + tr(line) + "[/color][center]" + .format([text_color_html]) + tr(line) + "[/color][center]" if _current_character.is_inside_tree() and \ - _current_character.has_node("dialog_position"): - position = _current_character.get_node( - "dialog_position" - ).get_global_transform_with_canvas().origin + is_instance_valid(dialog_location_node): + position = dialog_location_node.get_global_transform_with_canvas().origin + position.x -= size.x / 2 else: position.x = 0 size.x = ProjectSettings.get_setting("display/window/size/viewport_width") - if position.x < 0: - position.x = 0 + _account_for_margin_x() - var screen_margin = position.x + size.x - \ - ProjectSettings.get("display/window/size/viewport_width") - - if screen_margin > 0: - position.x -= screen_margin + _account_for_margin_y() _current_character.start_talking() - text_node.percent_visible = 0.0 + text_node.visible_ratio = 0.0 var time_show_full_text = _text_time_per_character / 1000 * len(_current_line) - tween.interpolate_property(text_node, "percent_visible", + tween.reset() + + tween.interpolate_property(text_node, "visible_ratio", 0.0, 1.0, time_show_full_text, Tween.TRANS_LINEAR, Tween.EASE_IN_OUT) - tween.start() + tween.play() set_process(true) @@ -183,19 +190,21 @@ func speedup(): _is_speeding_up = true var time_show_full_text = _fast_text_time_per_character / 1000 * len(_current_line) - tween.remove_all() - tween.interpolate_property(text_node, "percent_visible", - text_node.percent_visible, 1.0, time_show_full_text, + tween.reset() + + tween.interpolate_property(text_node, "visible_ratio", + text_node.visible_ratio, 1.0, time_show_full_text, Tween.TRANS_LINEAR, Tween.EASE_IN_OUT) - tween.start() + tween.play() # Called by the dialog player when user wants to finish dialogue immediately. func finish(): - tween.remove_all() - tween.interpolate_property(text_node, "percent_visible", - text_node.percent_visible, 1.0, 0.0) - tween.start() + tween.reset() + + tween.interpolate_property(text_node, "visible_ratio", + text_node.visible_ratio, 1.0, 0.0) + tween.play() # To be called if voice audio has finished. @@ -211,9 +220,9 @@ func _on_dialog_line_typed(object, key): var time_to_disappear: float = _calculate_time_to_disappear() $Timer.start(time_to_disappear) - $Timer.connect("timeout", Callable(self, "_on_dialog_finished")) + $Timer.timeout.connect(_on_dialog_finished) - emit_signal("say_visible") + say_visible.emit() func _calculate_time_to_disappear() -> float: @@ -228,23 +237,23 @@ func _get_number_of_words() -> int: func _on_dialog_finished(): # Only trigger to clear the text if we aren't limiting the clearing trigger to a click. if not ESCProjectSettingsManager.get_setting(RTMISimpleDialogSettings.CLEAR_TEXT_BY_CLICK_ONLY): - emit_signal("say_finished") + say_finished.emit() # Handler managing pause notification from Escoria func _on_paused(): - if tween.is_active(): + if tween.is_running(): is_paused = true visible = false - tween.stop_all() + tween.stop() # Handler managing resume notification from Escoria func _on_resumed(): - if not tween.is_active(): + if not tween.is_running(): is_paused = false visible = true - tween.resume_all() + tween.resume() # Handler to deal with this node being removed @@ -256,3 +265,25 @@ func _stop_character_talking(): # Make the speaking item animation stop talking, if it is still alive if is_instance_valid(_current_character) and _current_character != null: _current_character.stop_talking() + + +func _account_for_margin_x() -> void: + if position.x < 0: + position.x = 0 + + var screen_margin_x = position.x + size.x - \ + ProjectSettings.get("display/window/size/viewport_width") + + if screen_margin_x > 0: + position.x -= screen_margin_x + + +func _account_for_margin_y() -> void: + if position.y < 0: + position.y = 0 + + var screen_margin_y = position.y + size.y - \ + ProjectSettings.get("display/window/size/viewport_height") + + if screen_margin_y > 0: + position.y -= screen_margin_y diff --git a/gymkhana/rooms/turno_cocina/creditos/scrollingText.gd b/gymkhana/rooms/turno_cocina/creditos/scrollingText.gd index 82df67ca..790f0f2e 100644 --- a/gymkhana/rooms/turno_cocina/creditos/scrollingText.gd +++ b/gymkhana/rooms/turno_cocina/creditos/scrollingText.gd @@ -1,14 +1,12 @@ extends VBoxContainer -signal finished - func _ready(): pass # Replace with function body. func _process(_delta): - var size = self.get_global_rect().size + var textSize = self.get_global_rect().size if escoria.globals_manager.get_global("turno_credits_rolling"): self.set_position(self.get_position() + Vector2(0, -0.5)) - if self.get_position().y < -20 - size.y: + if self.get_position().y < -20 - textSize.y: escoria.globals_manager.set_global("turno_credits_rolling", false) emit_signal("finished")