149 lines
4.5 KiB
GDScript
149 lines
4.5 KiB
GDScript
extends CanvasLayer
|
|
|
|
|
|
@onready var audio_stream_player: AudioStreamPlayer = $AudioStreamPlayer
|
|
@onready var dialogue_label: DialogueLabel = $DialogueLabel
|
|
@onready var responses_menu: DialogueResponsesMenu = %DialogueResponsesMenu
|
|
|
|
|
|
## The dialogue resource
|
|
var resource: DialogueResource
|
|
|
|
## Temporary game states
|
|
var temporary_game_states: Array = []
|
|
|
|
## See if we are waiting for the player
|
|
var is_waiting_for_input: bool = false
|
|
|
|
# Who is talking
|
|
var dialogue_marker: DialogueMarker
|
|
|
|
## The current line
|
|
var dialogue_line: DialogueLine:
|
|
set(value):
|
|
if not value:
|
|
queue_free()
|
|
else:
|
|
dialogue_line = value
|
|
update_dialogue_line()
|
|
get:
|
|
return dialogue_line
|
|
|
|
|
|
func _ready() -> void:
|
|
dialogue_label.hide()
|
|
|
|
Engine.get_singleton("DialogueManager").mutated.connect(_on_mutated)
|
|
|
|
|
|
func _unhandled_input(_event: InputEvent) -> void:
|
|
# Only the balloon is allowed to handle input while it's showing
|
|
get_viewport().set_input_as_handled()
|
|
|
|
|
|
## Start some dialogue
|
|
func start(dialogue_resource: DialogueResource, title: String, extra_game_states: Array = []) -> void:
|
|
if not is_node_ready():
|
|
await ready
|
|
temporary_game_states = extra_game_states
|
|
is_waiting_for_input = false
|
|
resource = dialogue_resource
|
|
dialogue_line = await resource.get_next_dialogue_line(title, temporary_game_states)
|
|
|
|
|
|
## Go to the next line
|
|
func next(next_id: String) -> void:
|
|
dialogue_line = await resource.get_next_dialogue_line(next_id, temporary_game_states)
|
|
|
|
|
|
#region Helpers
|
|
|
|
|
|
func update_dialogue_line() -> void:
|
|
responses_menu.responses = []
|
|
|
|
dialogue_line.text = dialogue_line.text
|
|
|
|
dialogue_label.hide()
|
|
dialogue_label.dialogue_line = dialogue_line
|
|
|
|
# Set the colour and attach the dialogue to the character
|
|
dialogue_marker = DialogueMarker.find_for_character(dialogue_line.character)
|
|
if is_instance_valid(dialogue_marker):
|
|
dialogue_label.set("theme_override_colors/default_color", dialogue_marker.color)
|
|
dialogue_label.set("theme_override_colors/font_outline_color", dialogue_marker.color.darkened(0.4))
|
|
dialogue_label.global_position = dialogue_marker.global_position - Vector2(dialogue_label.size.x * 0.5, dialogue_label.get_content_height())
|
|
|
|
dialogue_label.show()
|
|
dialogue_label.type_out()
|
|
|
|
# Play sound and wait for sound to finish
|
|
var voice_path: String = "res://l10n/voice/en/%s.ogg" % [dialogue_line.static_id]
|
|
if ResourceLoader.exists(voice_path):
|
|
var stream = load(voice_path)
|
|
audio_stream_player.stream = stream
|
|
audio_stream_player.play()
|
|
|
|
Events.character_started_talking.emit(dialogue_line.character)
|
|
await audio_stream_player.finished
|
|
Events.character_finished_talking.emit(dialogue_line.character)
|
|
else:
|
|
printerr("Voice missing: %s" % [voice_path])
|
|
Events.character_started_talking.emit(dialogue_line.character)
|
|
await get_tree().create_timer(dialogue_line.text.length() * 0.05).timeout
|
|
Events.character_finished_talking.emit(dialogue_line.character)
|
|
|
|
dialogue_label.hide()
|
|
|
|
if dialogue_line.responses.size() == 0:
|
|
next(dialogue_line.next_id)
|
|
else:
|
|
responses_menu.responses = dialogue_line.responses
|
|
for item: RichTextLabel in responses_menu.get_menu_items():
|
|
item.mouse_entered.connect(_on_response_mouse_entered.bind(item))
|
|
item.focus_entered.connect(_on_response_focus_entered.bind(item))
|
|
item.focus_exited.connect(_on_response_focus_exited.bind(item))
|
|
item.gui_input.connect(_on_response_gui_input.bind(item))
|
|
_on_response_focus_entered(responses_menu.get_menu_items()[0])
|
|
|
|
#endregion
|
|
|
|
#region Signals
|
|
|
|
|
|
func _on_mutated(_mutation: Dictionary) -> void:
|
|
is_waiting_for_input = false
|
|
|
|
|
|
func _on_response_mouse_entered(item: Control) -> void:
|
|
if "Disallowed" in item.name: return
|
|
|
|
item.grab_focus()
|
|
|
|
|
|
func _on_response_gui_input(event: InputEvent, item: Control) -> void:
|
|
if "Disallowed" in item.name: return
|
|
|
|
get_viewport().set_input_as_handled()
|
|
|
|
if event is InputEventMouseButton and event.is_pressed() and event.button_index == 1:
|
|
next(dialogue_line.responses[item.get_index()].next_id)
|
|
elif event.is_action_pressed("ui_accept") and item in responses_menu.get_menu_items():
|
|
next(dialogue_line.responses[item.get_index()].next_id)
|
|
|
|
|
|
func _on_response_focus_entered(item):
|
|
item.set("theme_override_colors/default_color", DialogueMarker.find_for_character("Jimmy").color)
|
|
|
|
|
|
func _on_response_focus_exited(item):
|
|
item.set("theme_override_colors/default_color", Color.WHITE)
|
|
|
|
|
|
func _on_dialogue_label_resized() -> void:
|
|
if is_instance_valid(dialogue_marker):
|
|
dialogue_label.global_position = dialogue_marker.global_position - Vector2(dialogue_label.size.x * 0.5, dialogue_label.get_content_height())
|
|
|
|
|
|
#endregion
|