You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
161 lines
4.3 KiB
161 lines
4.3 KiB
6 months ago
|
class_name DialogicNode_DialogText
|
||
|
extends RichTextLabel
|
||
|
|
||
|
## Dialogic node that can reveal text at a given (changeable speed).
|
||
|
|
||
|
signal started_revealing_text()
|
||
|
signal continued_revealing_text(new_character : String)
|
||
|
signal finished_revealing_text()
|
||
|
enum Alignment {LEFT, CENTER, RIGHT}
|
||
|
|
||
|
@export var enabled := true
|
||
|
@export var alignment := Alignment.LEFT
|
||
|
@export var textbox_root : Node = self
|
||
|
|
||
|
@export var hide_when_empty := false
|
||
|
@export var start_hidden := true
|
||
|
|
||
|
var revealing := false
|
||
|
var base_visible_characters := 0
|
||
|
|
||
|
# The used speed per revealed character.
|
||
|
# May be overwritten when syncing reveal speed to voice.
|
||
|
var active_speed: float = 0.01
|
||
|
|
||
|
var speed_counter: float = 0
|
||
|
|
||
|
func _set(property: StringName, what: Variant) -> bool:
|
||
|
if property == 'text' and typeof(what) == TYPE_STRING:
|
||
|
|
||
|
text = what
|
||
|
|
||
|
if hide_when_empty:
|
||
|
textbox_root.visible = !what.is_empty()
|
||
|
|
||
|
return true
|
||
|
return false
|
||
|
|
||
|
return false
|
||
|
|
||
|
|
||
|
func _ready() -> void:
|
||
|
# add to necessary
|
||
|
add_to_group('dialogic_dialog_text')
|
||
|
meta_hover_ended.connect(_on_meta_hover_ended)
|
||
|
meta_hover_started.connect(_on_meta_hover_started)
|
||
|
meta_clicked.connect(_on_meta_clicked)
|
||
|
gui_input.connect(on_gui_input)
|
||
|
bbcode_enabled = true
|
||
|
if textbox_root == null:
|
||
|
textbox_root = self
|
||
|
|
||
|
if start_hidden:
|
||
|
textbox_root.hide()
|
||
|
text = ""
|
||
|
|
||
|
|
||
|
# this is called by the DialogicGameHandler to set text
|
||
|
|
||
|
func reveal_text(_text: String, keep_previous:=false) -> void:
|
||
|
if !enabled:
|
||
|
return
|
||
|
show()
|
||
|
|
||
|
if !keep_previous:
|
||
|
text = _text
|
||
|
base_visible_characters = 0
|
||
|
|
||
|
if alignment == Alignment.CENTER:
|
||
|
text = '[center]'+text
|
||
|
elif alignment == Alignment.RIGHT:
|
||
|
text = '[right]'+text
|
||
|
visible_characters = 0
|
||
|
|
||
|
else:
|
||
|
base_visible_characters = len(text)
|
||
|
visible_characters = len(get_parsed_text())
|
||
|
text = text + _text
|
||
|
|
||
|
# If Auto-Skip is enabled and we append the text (keep_previous),
|
||
|
# we can skip revealing the text and just show it all at once.
|
||
|
if DialogicUtil.autoload().Inputs.auto_skip.enabled:
|
||
|
visible_characters = 1
|
||
|
return
|
||
|
|
||
|
revealing = true
|
||
|
speed_counter = 0
|
||
|
started_revealing_text.emit()
|
||
|
|
||
|
|
||
|
func set_speed(delay_per_character:float) -> void:
|
||
|
if DialogicUtil.autoload().Text.is_text_voice_synced() and DialogicUtil.autoload().Voice.is_running():
|
||
|
var total_characters := get_total_character_count() as float
|
||
|
var remaining_time: float = DialogicUtil.autoload().Voice.get_remaining_time()
|
||
|
var synced_speed := remaining_time / total_characters
|
||
|
active_speed = synced_speed
|
||
|
|
||
|
else:
|
||
|
active_speed = delay_per_character
|
||
|
|
||
|
|
||
|
## Reveals one additional character.
|
||
|
func continue_reveal() -> void:
|
||
|
if visible_characters <= get_total_character_count():
|
||
|
revealing = false
|
||
|
|
||
|
var current_index := visible_characters - base_visible_characters
|
||
|
await DialogicUtil.autoload().Text.execute_effects(current_index, self, false)
|
||
|
|
||
|
if visible_characters == -1:
|
||
|
return
|
||
|
|
||
|
revealing = true
|
||
|
visible_characters += 1
|
||
|
|
||
|
if visible_characters > -1 and visible_characters <= len(get_parsed_text()):
|
||
|
continued_revealing_text.emit(get_parsed_text()[visible_characters-1])
|
||
|
else:
|
||
|
finish_text()
|
||
|
# if the text finished organically, add a small input block
|
||
|
# this prevents accidental skipping when you expected the text to be longer
|
||
|
DialogicUtil.autoload().Inputs.block_input(ProjectSettings.get_setting('dialogic/text/advance_delay', 0.1))
|
||
|
|
||
|
|
||
|
## Reveals the entire text instantly.
|
||
|
func finish_text() -> void:
|
||
|
visible_ratio = 1
|
||
|
DialogicUtil.autoload().Text.execute_effects(-1, self, true)
|
||
|
revealing = false
|
||
|
DialogicUtil.autoload().current_state = DialogicGameHandler.States.IDLE
|
||
|
|
||
|
finished_revealing_text.emit()
|
||
|
|
||
|
|
||
|
## Checks if the next character in the text can be revealed.
|
||
|
func _process(delta: float) -> void:
|
||
|
if !revealing or DialogicUtil.autoload().paused:
|
||
|
return
|
||
|
|
||
|
speed_counter += delta
|
||
|
|
||
|
while speed_counter > active_speed and revealing and !DialogicUtil.autoload().paused:
|
||
|
speed_counter -= active_speed
|
||
|
continue_reveal()
|
||
|
|
||
|
|
||
|
|
||
|
func _on_meta_hover_started(_meta:Variant) -> void:
|
||
|
DialogicUtil.autoload().Inputs.action_was_consumed = true
|
||
|
|
||
|
func _on_meta_hover_ended(_meta:Variant) -> void:
|
||
|
DialogicUtil.autoload().Inputs.action_was_consumed = false
|
||
|
|
||
|
func _on_meta_clicked(_meta:Variant) -> void:
|
||
|
DialogicUtil.autoload().Inputs.action_was_consumed = true
|
||
|
|
||
|
|
||
|
## Handle mouse input
|
||
|
func on_gui_input(event:InputEvent) -> void:
|
||
|
DialogicUtil.autoload().Inputs.handle_node_gui_input(event)
|
||
|
|