105 lines
2.8 KiB
GDScript3
105 lines
2.8 KiB
GDScript3
|
extends RichTextLabel
|
||
|
|
||
|
|
||
|
signal spoke(letter, speed)
|
||
|
signal paused(duration)
|
||
|
signal finished()
|
||
|
|
||
|
|
||
|
const DialogueLine = preload("res://addons/dialogue_manager/dialogue_line.gd")
|
||
|
|
||
|
export var skip_action: String = "ui_cancel"
|
||
|
export var seconds_per_step: float = 0.02
|
||
|
|
||
|
|
||
|
var dialogue: DialogueLine
|
||
|
|
||
|
var index: int = 0
|
||
|
var percent_per_index: float = 0
|
||
|
var last_wait_index: int = -1
|
||
|
var last_mutation_index: int = -1
|
||
|
var waiting_seconds: float = 0
|
||
|
var is_typing: bool = false
|
||
|
var has_finished: bool = false
|
||
|
|
||
|
|
||
|
func _process(delta: float) -> void:
|
||
|
if is_typing:
|
||
|
# Type out text
|
||
|
if percent_visible < 1:
|
||
|
# If cancel is pressed then skip typing it out
|
||
|
if Input.is_action_just_pressed(skip_action):
|
||
|
percent_visible = 1
|
||
|
# Run any inline mutations that haven't been run yet
|
||
|
for i in range(index, get_total_character_count()):
|
||
|
dialogue.mutate_inline_mutations(i)
|
||
|
|
||
|
# Otherwise, keep typing
|
||
|
elif waiting_seconds > 0:
|
||
|
waiting_seconds = max(0, waiting_seconds - delta)
|
||
|
else:
|
||
|
type_next(delta, 0)
|
||
|
else:
|
||
|
is_typing = false
|
||
|
if has_finished == false:
|
||
|
has_finished = true
|
||
|
emit_signal("finished")
|
||
|
|
||
|
|
||
|
func reset_height() -> void:
|
||
|
# For some reason, RichTextLabels within containers don't resize properly when their content
|
||
|
# changes so we make a clone that isn't bound by a VBox
|
||
|
var size_check_label = duplicate(0)
|
||
|
size_check_label.modulate.a = 0
|
||
|
get_tree().current_scene.add_child(size_check_label)
|
||
|
size_check_label.rect_size.x = rect_size.x
|
||
|
size_check_label.bbcode_text = dialogue.dialogue
|
||
|
|
||
|
# Give the size check a chance to resize
|
||
|
yield(get_tree(), "idle_frame")
|
||
|
|
||
|
# Resize our dialogue label with the new size hint
|
||
|
rect_min_size = Vector2(rect_size.x, size_check_label.get_content_height())
|
||
|
rect_size = Vector2(0, 0)
|
||
|
|
||
|
# Destroy our clone
|
||
|
size_check_label.queue_free()
|
||
|
|
||
|
|
||
|
|
||
|
func type_next(delta: float, seconds_needed: float) -> void:
|
||
|
if last_mutation_index != index:
|
||
|
last_mutation_index = index
|
||
|
dialogue.mutate_inline_mutations(index)
|
||
|
|
||
|
if last_wait_index != index and dialogue.get_pause(index) > 0:
|
||
|
last_wait_index = index
|
||
|
waiting_seconds += dialogue.get_pause(index)
|
||
|
emit_signal("paused", dialogue.get_pause(index))
|
||
|
else:
|
||
|
percent_visible += percent_per_index
|
||
|
index += 1
|
||
|
seconds_needed += seconds_per_step * (1.0 / dialogue.get_speed(index))
|
||
|
if seconds_needed > delta:
|
||
|
waiting_seconds += seconds_needed
|
||
|
if index < text.length():
|
||
|
emit_signal("spoke", text[index - 1], dialogue.get_speed(index))
|
||
|
else:
|
||
|
type_next(delta, seconds_needed)
|
||
|
|
||
|
|
||
|
func type_out() -> void:
|
||
|
bbcode_text = dialogue.dialogue
|
||
|
percent_visible = 0
|
||
|
index = 0
|
||
|
has_finished = false
|
||
|
waiting_seconds = 0
|
||
|
# Text isn't calculated until the next frame
|
||
|
yield(get_tree(), "idle_frame")
|
||
|
if not get_total_character_count():
|
||
|
emit_signal("finished")
|
||
|
queue_free()
|
||
|
return
|
||
|
percent_per_index = 100.0 / float(get_total_character_count()) / 100.0
|
||
|
is_typing = true
|