custom dialog plugin styled

This commit is contained in:
2023-02-23 03:56:15 +01:00
parent 82ee00c307
commit 3d6e6b4035
11 changed files with 1055 additions and 3 deletions

View File

@@ -0,0 +1,100 @@
# A simple dialog chooser that shows selectable lines of text
# Supports timeout and avatar display
extends ESCDialogOptionsChooser
export(Color, RGB) var color_normal = Color(1.0,1.0,1.0,1.0)
export(Color, RGB) var color_hover = Color(165.0,42.0,42.0, 1.0)
var _no_more_options: bool = false
# Hide the chooser at the start just to be safe
func _ready() -> void:
hide_chooser()
pause_mode = PAUSE_MODE_STOP
# Process the timeout display
func _process(delta: float) -> void:
if $MarginContainer.visible and self.dialog and self.dialog.timeout > 0:
$TimerProgress.value = (
self.dialog.timeout - $Timer.time_left
) / self.dialog.timeout * 100
# Show the chooser
func show_chooser():
var _vbox = $MarginContainer/ScrollContainer/VBoxContainer
for option_node in _vbox.get_children():
_vbox.remove_child(option_node)
_remove_avatar()
for option in self.dialog.options:
if option.is_valid():
var _option_node = Button.new()
_option_node.text = (option as ESCDialogOption).option
_option_node.flat = true
_option_node.add_color_override("font_color", color_normal)
_option_node.add_color_override("font_color_hover", color_hover)
_vbox.add_child(_option_node)
_option_node.connect("pressed", self, "_on_answer_selected", [
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
# we have to fire the signal AFTER this method returns as the caller
# is almost certainly yielding after this method returns.
if _vbox.get_child_count() == 0:
_no_more_options = true
$Timer.start(0.05)
return
if self.dialog.avatar != "-":
$AvatarContainer.add_child(
ResourceLoader.load(self.dialog.avatar).instance()
)
$MarginContainer.show()
if self.dialog.timeout > 0:
$Timer.start(self.dialog.timeout)
# Hide the chooser
func hide_chooser():
$MarginContainer.hide()
# An option was choosen, emit the option
#
# #### Parameters
# - option: Option that was chosen
func _option_chosen(option: ESCDialogOption):
_remove_avatar()
$TimerProgress.value = 0
emit_signal("option_chosen", option)
# An option was chosen directly from the list
#
# #### Parameters
# - option: Option that was chosen
func _on_answer_selected(option: ESCDialogOption):
_option_chosen(option)
# The timeout came and a option was selected
func _on_Timer_timeout() -> void:
var option_chosen = null if _no_more_options else self.dialog.options[self.dialog.timeout_option - 1]
_no_more_options = false
_option_chosen(option_chosen)
# Remove the avatar
func _remove_avatar():
if $AvatarContainer.get_child_count() > 0:
$AvatarContainer.remove_child($AvatarContainer.get_child(0))

View File

@@ -0,0 +1,63 @@
[gd_scene load_steps=4 format=2]
[ext_resource path="res://addons/escoria-dialog-simple/chooser/simple.gd" type="Script" id=1]
[sub_resource type="Gradient" id=1]
colors = PoolColorArray( 1, 0, 0, 1, 1, 0, 0, 1 )
[sub_resource type="GradientTexture" id=2]
gradient = SubResource( 1 )
[node name="text_dialog_choice" type="Control"]
anchor_right = 1.0
anchor_bottom = 1.0
script = ExtResource( 1 )
[node name="MarginContainer" type="MarginContainer" parent="."]
margin_left = 20.0
margin_top = 20.0
margin_right = 1280.0
margin_bottom = 900.0
mouse_filter = 2
custom_constants/margin_top = 20
custom_constants/margin_left = 20
__meta__ = {
"_edit_use_anchors_": false
}
[node name="ScrollContainer" type="ScrollContainer" parent="MarginContainer"]
margin_left = 20.0
margin_top = 20.0
margin_right = 1260.0
margin_bottom = 880.0
scroll_horizontal_enabled = false
__meta__ = {
"_edit_use_anchors_": false
}
[node name="VBoxContainer" type="VBoxContainer" parent="MarginContainer/ScrollContainer"]
margin_right = 1240.0
margin_bottom = 860.0
size_flags_horizontal = 3
size_flags_vertical = 3
custom_constants/separation = 20
__meta__ = {
"_edit_use_anchors_": false
}
[node name="Timer" type="Timer" parent="."]
one_shot = true
[node name="TimerProgress" type="TextureProgress" parent="."]
anchor_right = 1.0
rect_min_size = Vector2( 0, 20 )
texture_progress = SubResource( 2 )
nine_patch_stretch = true
__meta__ = {
"_edit_use_anchors_": false
}
[node name="AvatarContainer" type="Node2D" parent="."]
position = Vector2( 94, 68 )
[connection signal="timeout" from="Timer" to="." method="_on_Timer_timeout"]

View File

@@ -0,0 +1,120 @@
# A simple dialog manager for Escoria
extends ESCDialogManager
class_name ESCReturnToMonekyIslandDialogs
# The currently running player
var _type_player: Node = null
# Reference to the dialog player
var _dialog_player: Node = null
# Check whether a specific type is supported by the
# dialog plugin
#
# #### Parameters
# - type: required type
# *Returns* Whether the type is supported or not
func has_type(type: String) -> bool:
return true if type in ["floating", "avatar"] 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
# 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
if type == "floating":
_type_player = preload(\
"res://gymkhana/addons/escoria-ui-return-monkey-island-dialog-simple/types/floating.tscn"\
).instance()
else:
_type_player = preload(\
"res://gymkhana/addons/escoria-ui-return-monkey-island-dialog-simple/types/avatar.tscn"\
).instance()
_type_player.connect("say_finished", self, "_on_say_finished", [], CONNECT_ONESHOT)
_type_player.connect("say_visible", self, "_on_say_visible", [], CONNECT_ONESHOT)
_dialog_player.add_child(_type_player)
_type_player.say(global_id, text)
# yield(_type_player, "say_finished")
# if _dialog_player.get_children().has(_type_player):
# _dialog_player.remove_child(_type_player)
# emit_signal("say_finished")
func _on_say_finished():
if _dialog_player.get_children().has(_type_player):
_dialog_player.remove_child(_type_player)
emit_signal("say_finished")
func _on_say_visible():
emit_signal("say_visible")
# Present an option chooser to the player and sends the signal
# `option_chosen` with the chosen dialog option
#
# #### Parameters
# - dialog_player: Node of the dialog player in the UI
# - dialog: Information about the dialog to display
func choose(dialog_player: Node, dialog: ESCDialog):
var chooser = preload(\
"res://gymkhana/addons/escoria-ui-return-monkey-island-dialog-simple/chooser/simple.tscn"\
).instance()
dialog_player.add_child(chooser)
chooser.set_dialog(dialog)
chooser.show_chooser()
var option = yield(chooser, "option_chosen")
dialog_player.remove_child(chooser)
emit_signal("option_chosen", option)
# Trigger running the dialogue faster
func speedup():
if _type_player != null:
_type_player.speedup()
# Trigger an instant finish of the current dialog
func finish():
if _type_player != null:
_type_player.finish()
# The say command has been interrupted, cancel the dialog display
func interrupt():
if _dialog_player.get_children().has(_type_player):
(
escoria.object_manager.get_object(escoria.object_manager.SPEECH).node\
as ESCSpeechPlayer
).set_state("off")
_dialog_player.remove_child(_type_player)
emit_signal("say_finished")
# To be called if voice audio has finished.
func voice_audio_finished():
if _type_player != null:
_type_player.voice_audio_finished()

View File

@@ -0,0 +1,7 @@
[plugin]
name="Escoria Return to Monkey Island UI Dialog Simple"
description="Return to Monkey Island like UI for the Escoria Framework (Dialogs)"
author="Arkitekt"
version="0.1.0"
script="plugin.gd"

View File

@@ -0,0 +1,167 @@
# A simple dialog manager for Escoria
tool
extends EditorPlugin
class_name SimpleDialogPlugin
const MANAGER_CLASS="res://gymkhana/addons/escoria-ui-return-monkey-island-dialog-simple/esc_dialog_simple.gd"
const SETTINGS_ROOT="escoria/dialog_simple"
const AVATARS_PATH = "%s/avatars_path" % SETTINGS_ROOT
const TEXT_TIME_PER_LETTER_MS = "%s/text_time_per_letter_ms" % SETTINGS_ROOT
const TEXT_TIME_PER_LETTER_MS_FAST = "%s/text_time_per_fast_letter_ms" % SETTINGS_ROOT
const READING_SPEED_IN_WPM = "%s/reading_speed_in_wpm" % SETTINGS_ROOT
const CLEAR_TEXT_BY_CLICK_ONLY = "%s/clear_text_by_click_only" % SETTINGS_ROOT
const LEFT_CLICK_ACTION = "%s/left_click_action" % SETTINGS_ROOT
const STOP_TALKING_ANIMATION_ON = "%s/stop_talking_animation_on" % SETTINGS_ROOT
const LEFT_CLICK_ACTION_SPEED_UP = "Speed up"
const LEFT_CLICK_ACTION_INSTANT_FINISH = "Instant finish"
const LEFT_CLICK_ACTION_NOTHING = "None"
const STOP_TALKING_ANIMATION_ON_END_OF_TEXT = "End of text"
const STOP_TALKING_ANIMATION_ON_END_OF_AUDIO = "End of audio"
const READING_SPEED_IN_WPM_DEFAULT_VALUE = 200
const TEXT_TIME_PER_LETTER_MS_DEFAULT_VALUE = 100
const TEXT_TIME_PER_LETTER_MS_FAST_DEFAULT_VALUE = 25
var left_click_actions: PoolStringArray = [
LEFT_CLICK_ACTION_SPEED_UP,
LEFT_CLICK_ACTION_INSTANT_FINISH,
LEFT_CLICK_ACTION_NOTHING
]
var stop_talking_animation_on_options: PoolStringArray = [
STOP_TALKING_ANIMATION_ON_END_OF_TEXT,
STOP_TALKING_ANIMATION_ON_END_OF_AUDIO
]
# Override function to return the plugin name.
func get_plugin_name():
return "escoria-dialog-simple"
# Unregister ourselves
func disable_plugin():
print("Disabling plugin Escoria Dialog Simple")
ESCProjectSettingsManager.remove_setting(
ESCProjectSettingsManager.DEFAULT_DIALOG_TYPE
)
ESCProjectSettingsManager.remove_setting(
AVATARS_PATH
)
ESCProjectSettingsManager.remove_setting(
TEXT_TIME_PER_LETTER_MS
)
ESCProjectSettingsManager.remove_setting(
TEXT_TIME_PER_LETTER_MS_FAST
)
ESCProjectSettingsManager.remove_setting(
CLEAR_TEXT_BY_CLICK_ONLY
)
ESCProjectSettingsManager.remove_setting(
READING_SPEED_IN_WPM
)
ESCProjectSettingsManager.remove_setting(
LEFT_CLICK_ACTION
)
ESCProjectSettingsManager.remove_setting(
STOP_TALKING_ANIMATION_ON
)
EscoriaPlugin.deregister_dialog_manager(MANAGER_CLASS)
# Add ourselves to the list of dialog managers
func enable_plugin():
print("Enabling plugin Escoria Dialog Simple")
if EscoriaPlugin.register_dialog_manager(self, MANAGER_CLASS):
ESCProjectSettingsManager.register_setting(
ESCProjectSettingsManager.DEFAULT_DIALOG_TYPE,
"floating",
{
"type": TYPE_STRING
}
)
ESCProjectSettingsManager.register_setting(
AVATARS_PATH,
"res://game/dialog_avatars",
{
"type": TYPE_STRING,
"hint": PROPERTY_HINT_DIR
}
)
ESCProjectSettingsManager.register_setting(
TEXT_TIME_PER_LETTER_MS,
TEXT_TIME_PER_LETTER_MS_DEFAULT_VALUE,
{
"type": TYPE_REAL
}
)
ESCProjectSettingsManager.register_setting(
TEXT_TIME_PER_LETTER_MS_FAST,
TEXT_TIME_PER_LETTER_MS_FAST_DEFAULT_VALUE,
{
"type": TYPE_REAL
}
)
ESCProjectSettingsManager.register_setting(
CLEAR_TEXT_BY_CLICK_ONLY,
false,
{
"type": TYPE_BOOL
}
)
ESCProjectSettingsManager.register_setting(
READING_SPEED_IN_WPM,
READING_SPEED_IN_WPM_DEFAULT_VALUE,
{
"type": TYPE_INT
}
)
var left_click_actions_string: String = left_click_actions.join(",")
ESCProjectSettingsManager.register_setting(
LEFT_CLICK_ACTION,
LEFT_CLICK_ACTION_SPEED_UP,
{
"type": TYPE_STRING,
"hint": PROPERTY_HINT_ENUM,
"hint_string": left_click_actions_string
}
)
var stop_talking_animation_on_options_string: String = stop_talking_animation_on_options.join(",")
ESCProjectSettingsManager.register_setting(
STOP_TALKING_ANIMATION_ON,
STOP_TALKING_ANIMATION_ON_END_OF_AUDIO,
{
"type": TYPE_STRING,
"hint": PROPERTY_HINT_ENUM,
"hint_string": stop_talking_animation_on_options_string
}
)
else:
get_editor_interface().set_plugin_enabled(
get_plugin_name(),
false
)

View File

@@ -0,0 +1,18 @@
[gd_resource type="Theme" load_steps=3 format=2]
[ext_resource path="res://gymkhana/addons/escoria-ui-return-monkey-island/fonts/caslonantique.tres" type="DynamicFont" id=1]
[sub_resource type="StyleBoxFlat" id=1]
content_margin_left = 5.0
content_margin_right = 5.0
content_margin_top = 5.0
content_margin_bottom = 5.0
bg_color = Color( 0, 0, 0, 0.25098 )
corner_radius_top_left = 8
corner_radius_top_right = 8
corner_radius_bottom_right = 8
corner_radius_bottom_left = 8
[resource]
default_font = ExtResource( 1 )
RichTextLabel/styles/normal = SubResource( 1 )

View File

@@ -0,0 +1,229 @@
# A dialog GUI showing a dialog box and character portraits
extends Popup
# Signal emitted when text has been said
signal say_finished
# Signal emitted when text has just become fully visible
signal say_visible
# The text speed per character for normal display
var _text_time_per_character: float
# The text speed per character if the dialog line is skipped
var _fast_text_time_per_character: float
# The reading speed to be used in determining the length of time text remains
# on the screen.
var _reading_speed_in_wpm: int
# Used to extract words from lines of text.
var _word_regex: RegEx = RegEx.new()
# Whether the current dialog is speeding up
var _is_speeding_up: bool = false
# The current line of text being displayed.
var _current_line: String
# The node holding the avatar
onready var avatar_node = $Panel/MarginContainer/HSplitContainer/VBoxContainer\
/avatar
# The node showing the text
onready var text_node = $Panel/MarginContainer/HSplitContainer/text
# The tween node for text animations
onready var tween = $Panel/MarginContainer/HSplitContainer/text/Tween
# 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(
SimpleDialogPlugin.TEXT_TIME_PER_LETTER_MS
)
if _text_time_per_character < 0:
escoria.logger.warn(
self,
"%s setting must be a non-negative number. Will use default value of %s." %
[
SimpleDialogPlugin.TEXT_TIME_PER_LETTER_MS,
SimpleDialogPlugin.TEXT_TIME_PER_LETTER_MS_DEFAULT_VALUE
]
)
_text_time_per_character = SimpleDialogPlugin.TEXT_TIME_PER_LETTER_MS_DEFAULT_VALUE
_fast_text_time_per_character = ProjectSettings.get_setting(
SimpleDialogPlugin.TEXT_TIME_PER_LETTER_MS_FAST
)
if _fast_text_time_per_character < 0:
escoria.logger.warn(
self,
"%s setting must be a non-negative number. Will use default value of %s." %
[
SimpleDialogPlugin.TEXT_TIME_PER_LETTER_MS_FAST,
SimpleDialogPlugin.TEXT_TIME_PER_LETTER_MS_FAST_DEFAULT_VALUE
]
)
_fast_text_time_per_character = SimpleDialogPlugin.TEXT_TIME_PER_LETTER_MS_FAST_DEFAULT_VALUE
_reading_speed_in_wpm = ProjectSettings.get_setting(
SimpleDialogPlugin.READING_SPEED_IN_WPM
)
if _reading_speed_in_wpm <= 0:
escoria.logger.warn(
self,
"%s setting must be a positive number. Will use default value of %s." %
[
SimpleDialogPlugin.READING_SPEED_IN_WPM,
SimpleDialogPlugin.READING_SPEED_IN_WPM_DEFAULT_VALUE
]
)
_reading_speed_in_wpm = SimpleDialogPlugin.READING_SPEED_IN_WPM_DEFAULT_VALUE
_word_regex.compile("\\S+")
text_node.bbcode_enabled = true
tween.connect(
"tween_completed",
self,
"_on_dialog_line_typed"
)
escoria.connect("paused", self, "_on_paused")
escoria.connect("resumed", self, "_on_resumed")
# Switch the current character
#
# #### Parameters
# - name: The name of the current character
func set_current_character(name: String):
if ProjectSettings.get_setting("escoria/dialog_simple/avatars_path").empty():
escoria.logger.warn(self, "Unable to load avatar '%s': Avatar path not specified" % name)
return
var avatar = "%s/%s.tres" % [
ProjectSettings.get_setting("escoria/dialog_simple/avatars_path"),
name
]
if ResourceLoader.exists(avatar):
avatar_node.texture = ResourceLoader.load(avatar)
if avatar_node.texture is AnimatedTexture:
avatar_node.texture.current_frame = 0
avatar_node.texture.pause = false
else:
escoria.logger.warn(self, "Unable to load avatar '%s': Resource not found in path '%s'" %
[name, ProjectSettings.get_setting("escoria/dialog_simple/avatars_path")])
# Make a character say something
#
# #### Parameters
# - character: The global id of the character speaking
# - line: Line to say
func say(character: String, line: String):
_current_line = line
_is_speeding_up = false
popup_centered()
set_current_character(character)
text_node.bbcode_text = tr(line)
text_node.percent_visible = 0.0
var time_show_full_text = _text_time_per_character / 1000 * len(line)
tween.interpolate_property(text_node, "percent_visible",
0.0, 1.0, time_show_full_text,
Tween.TRANS_LINEAR, Tween.EASE_IN_OUT)
tween.start()
# Called by the dialog player when the
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.TRANS_LINEAR, Tween.EASE_IN_OUT)
tween.start()
# 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()
# To be called if voice audio has finished.
func voice_audio_finished():
if avatar_node and avatar_node.texture:
avatar_node.texture.current_frame = 0
avatar_node.texture.pause = true
# The dialog line was printed, start the waiting time and then finish
# the dialog
func _on_dialog_line_typed(object, key):
if avatar_node.texture is AnimatedTexture:
avatar_node.texture.current_frame = 0
avatar_node.texture.pause = true
text_node.visible_characters = -1
var time_to_disappear: float = _calculate_time_to_disappear()
$Timer.start(time_to_disappear)
$Timer.connect("timeout", self, "_on_dialog_finished")
emit_signal("say_visible")
func _calculate_time_to_disappear() -> float:
return (_get_number_of_words() / _reading_speed_in_wpm as float) * 60
func _get_number_of_words() -> int:
return _word_regex.search_all(text_node.get_text()).size()
# Ending the dialog
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(SimpleDialogPlugin.CLEAR_TEXT_BY_CLICK_ONLY):
emit_signal("say_finished")
queue_free()
# Handler managing pause notification from Escoria
func _on_paused():
if tween.is_active():
is_paused = true
tween.stop_all()
# Handler managing resume notification from Escoria
func _on_resumed():
if not tween.is_active():
is_paused = false
tween.resume_all()

View File

@@ -0,0 +1,68 @@
[gd_scene load_steps=2 format=2]
[ext_resource path="res://addons/escoria-dialog-simple/types/avatar.gd" type="Script" id=1]
[node name="dialog_box" type="Popup"]
anchor_right = 1.0
anchor_bottom = 1.0
margin_right = -782.0
margin_bottom = -734.0
script = ExtResource( 1 )
__meta__ = {
"_edit_use_anchors_": false
}
[node name="Timer" type="Timer" parent="."]
[node name="Panel" type="Panel" parent="."]
anchor_right = 1.0
anchor_bottom = 1.0
__meta__ = {
"_edit_use_anchors_": false
}
[node name="MarginContainer" type="MarginContainer" parent="Panel"]
anchor_right = 1.0
anchor_bottom = 1.0
custom_constants/margin_right = 20
custom_constants/margin_top = 20
custom_constants/margin_left = 20
custom_constants/margin_bottom = 20
__meta__ = {
"_edit_use_anchors_": false
}
[node name="HSplitContainer" type="HSplitContainer" parent="Panel/MarginContainer"]
margin_left = 20.0
margin_top = 20.0
margin_right = 478.0
margin_bottom = 146.0
custom_constants/separation = 35
dragger_visibility = 1
[node name="VBoxContainer" type="VBoxContainer" parent="Panel/MarginContainer/HSplitContainer"]
margin_right = 88.0
margin_bottom = 126.0
size_flags_horizontal = 3
size_flags_stretch_ratio = 0.3
[node name="avatar" type="TextureRect" parent="Panel/MarginContainer/HSplitContainer/VBoxContainer"]
margin_right = 88.0
margin_bottom = 108.0
size_flags_horizontal = 3
size_flags_vertical = 3
expand = true
[node name="text" type="RichTextLabel" parent="Panel/MarginContainer/HSplitContainer"]
margin_left = 123.0
margin_right = 458.0
margin_bottom = 126.0
size_flags_horizontal = 3
bbcode_enabled = true
bbcode_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"]

View File

@@ -0,0 +1,256 @@
# A dialog UI using a label above the head of the character
extends RichTextLabel
# Signal emitted when text has been said
signal say_finished
# Signal emitted when text has just become fully visible
signal say_visible
# The text speed per character for normal display
var _text_time_per_character: float
# The text speed per character if the dialog line is skipped
var _fast_text_time_per_character: float
# The reading speed to be used in determining the length of time text remains
# on the screen.
var _reading_speed_in_wpm: int
# Used to extract words from lines of text.
var _word_regex: RegEx = RegEx.new()
# Current character speaking, to keep track of reference for animation purposes
var _current_character
# Whether the current dialog is speeding up
var _is_speeding_up: bool = false
# The current line of text being displayed.
var _current_line: String
# Tween node for text animation
onready var tween: Tween = $Tween
# The node showing the text
onready var text_node: RichTextLabel = self
# Whether the dialog manager is paused
onready var is_paused: bool = true
# Enable bbcode and catch the signal when a tween completed
func _ready():
_text_time_per_character = ProjectSettings.get_setting(
SimpleDialogPlugin.TEXT_TIME_PER_LETTER_MS
)
if _text_time_per_character < 0:
escoria.logger.warn(
self,
"%s setting must be a non-negative number. Will use default value of %s." %
[
SimpleDialogPlugin.TEXT_TIME_PER_LETTER_MS,
SimpleDialogPlugin.TEXT_TIME_PER_LETTER_MS_DEFAULT_VALUE
]
)
_text_time_per_character = SimpleDialogPlugin.TEXT_TIME_PER_LETTER_MS_DEFAULT_VALUE
_fast_text_time_per_character = ProjectSettings.get_setting(
SimpleDialogPlugin.TEXT_TIME_PER_LETTER_MS_FAST
)
if _fast_text_time_per_character < 0:
escoria.logger.warn(
self,
"%s setting must be a non-negative number. Will use default value of %s." %
[
SimpleDialogPlugin.TEXT_TIME_PER_LETTER_MS_FAST,
SimpleDialogPlugin.TEXT_TIME_PER_LETTER_MS_FAST_DEFAULT_VALUE
]
)
_fast_text_time_per_character = SimpleDialogPlugin.TEXT_TIME_PER_LETTER_MS_FAST_DEFAULT_VALUE
_reading_speed_in_wpm = ProjectSettings.get_setting(
SimpleDialogPlugin.READING_SPEED_IN_WPM
)
if _reading_speed_in_wpm <= 0:
escoria.logger.warn(
self,
"%s setting must be a positive number. Will use default value of %s." %
[
SimpleDialogPlugin.READING_SPEED_IN_WPM,
SimpleDialogPlugin.READING_SPEED_IN_WPM_DEFAULT_VALUE
]
)
_reading_speed_in_wpm = SimpleDialogPlugin.READING_SPEED_IN_WPM_DEFAULT_VALUE
_word_regex.compile("\\S+")
bbcode_enabled = true
$Tween.connect("tween_completed", self, "_on_dialog_line_typed")
connect("tree_exiting", self, "_on_tree_exiting")
escoria.connect("paused", self, "_on_paused")
escoria.connect("resumed", self, "_on_resumed")
_current_line = ""
func _process(delta):
if _current_character.is_inside_tree() and \
_current_character.has_node("dialog_position"):
# Position the RichTextLabel on the character's dialog position, if any.
rect_position = _current_character.get_node("dialog_position") \
.get_global_transform_with_canvas().origin
rect_position.x -= rect_size.x / 2
if rect_position.x < 0:
rect_position.x = 0
var screen_margin = rect_position.x + rect_size.x - \
ProjectSettings.get("display/window/size/width")
if screen_margin > 0:
rect_position.x -= screen_margin
# Make a character say something
#
# #### Parameters
# - character: The global id of the character speaking
# - line: Line to say
func say(character: String, line: String) :
_current_line = line
show()
_is_speeding_up = false
# Position the RichTextLabel on the character's dialog position, if any.
_current_character = escoria.object_manager.get_object(character).node
# 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.bbcode_text = "[center][color=#" + text_color_html + "]" \
.format([text_color_html]) + tr(line) + "[/color][center]"
if _current_character.is_inside_tree() and \
_current_character.has_node("dialog_position"):
rect_position = _current_character.get_node(
"dialog_position"
).get_global_transform_with_canvas().origin
rect_position.x -= rect_size.x / 2
else:
rect_position.x = 0
rect_size.x = ProjectSettings.get_setting("display/window/size/width")
if rect_position.x < 0:
rect_position.x = 0
var screen_margin = rect_position.x + rect_size.x - \
ProjectSettings.get("display/window/size/width")
if screen_margin > 0:
rect_position.x -= screen_margin
_current_character.start_talking()
text_node.percent_visible = 0.0
var time_show_full_text = _text_time_per_character / 1000 * len(_current_line)
tween.interpolate_property(text_node, "percent_visible",
0.0, 1.0, time_show_full_text,
Tween.TRANS_LINEAR, Tween.EASE_IN_OUT)
tween.start()
set_process(true)
# Called by the dialog player when user wants to finish dialogue fast.
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.TRANS_LINEAR, Tween.EASE_IN_OUT)
tween.start()
# 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()
# To be called if voice audio has finished.
func voice_audio_finished():
_stop_character_talking()
# The dialog line was printed, start the waiting time and then finish
# the dialog
func _on_dialog_line_typed(object, key):
_stop_character_talking()
text_node.visible_characters = -1
var time_to_disappear: float = _calculate_time_to_disappear()
$Timer.start(time_to_disappear)
$Timer.connect("timeout", self, "_on_dialog_finished")
emit_signal("say_visible")
func _calculate_time_to_disappear() -> float:
return (_get_number_of_words() / _reading_speed_in_wpm as float) * 60
func _get_number_of_words() -> int:
return _word_regex.search_all(text_node.get_text()).size()
# Ending the dialog
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(SimpleDialogPlugin.CLEAR_TEXT_BY_CLICK_ONLY):
emit_signal("say_finished")
# Handler managing pause notification from Escoria
func _on_paused():
if tween.is_active():
is_paused = true
tween.stop_all()
# Handler managing resume notification from Escoria
func _on_resumed():
if not tween.is_active():
is_paused = false
tween.resume_all()
# Handler to deal with this node being removed
func _on_tree_exiting() -> void:
_stop_character_talking()
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()

View File

@@ -0,0 +1,18 @@
[gd_scene load_steps=3 format=2]
[ext_resource path="res://addons/escoria-dialog-simple/types/floating.gd" type="Script" id=1]
[ext_resource path="res://gymkhana/addons/escoria-ui-return-monkey-island-dialog-simple/theme.tres" type="Theme" id=2]
[node name="dialog_label" type="RichTextLabel"]
margin_right = 672.0
margin_bottom = 97.0
theme = ExtResource( 2 )
bbcode_enabled = true
bbcode_text = "[center]Here be some text.[/center]"
text = "Here be some text."
fit_content_height = true
script = ExtResource( 1 )
[node name="Tween" type="Tween" parent="."]
[node name="Timer" type="Timer" parent="."]

View File

@@ -384,6 +384,11 @@ _global_script_classes=[ {
"language": "GDScript",
"path": "res://addons/escoria-core/game/core-scripts/resources/esc_resource_descriptor.gd"
}, {
"base": "ESCDialogManager",
"class": "ESCReturnToMonekyIslandDialogs",
"language": "GDScript",
"path": "res://gymkhana/addons/escoria-ui-return-monkey-island-dialog-simple/esc_dialog_simple.gd"
}, {
"base": "Node2D",
"class": "ESCRoom",
"language": "GDScript",
@@ -607,7 +612,7 @@ _global_script_classes=[ {
"base": "EditorPlugin",
"class": "SimpleDialogPlugin",
"language": "GDScript",
"path": "res://addons/escoria-dialog-simple/plugin.gd"
"path": "res://gymkhana/addons/escoria-ui-return-monkey-island-dialog-simple/plugin.gd"
}, {
"base": "SlideCommand",
"class": "SlideBlockCommand",
@@ -765,6 +770,7 @@ _global_script_class_icons={
"ESCProjectSettingsManager": "",
"ESCResourceCache": "",
"ESCResourceDescriptor": "",
"ESCReturnToMonekyIslandDialogs": "",
"ESCRoom": "res://addons/escoria-core/design/esc_room.svg",
"ESCRoomManager": "",
"ESCRoomObjects": "",
@@ -888,7 +894,7 @@ ui/inventory_items_path="res://gymkhana/items/inventory"
ui/default_transition="instant"
ui/transition_paths=[ "res://addons/escoria-core/game/scenes/transitions/shaders/" ]
ui/inventory_item_size=Vector2( 72, 72 )
ui/dialog_managers=[ "res://addons/escoria-dialog-simple/esc_dialog_simple.gd" ]
ui/dialog_managers=[ "res://gymkhana/addons/escoria-ui-return-monkey-island-dialog-simple/esc_dialog_simple.gd" ]
sound/master_volume=1
sound/music_volume=1
sound/sfx_volume=1
@@ -900,7 +906,7 @@ platform/skip_cache.mobile=true
sound/speech_enabled=1
ui/tooltip_follows_mouse=false
main/escoria_version=""
ui/dialogs_chooser="res://addons/escoria-core/ui_library/dialogs/text_dialog_chooser.tscn"
ui/dialogs_chooser="res://gymkhana/addons/escoria-ui-return-monkey-island-dialog-simple/text_dialog_chooser.tscn"
ui/default_dialog_scene="res://addons/escoria-core/ui_library/dialogs/floating_dialog_player.tscn"
main/action_default_script="res://action_defaults.esc"
dialog_simple/text_speed_per_character=0.1