Initial commit
This commit is contained in:
@@ -0,0 +1,148 @@
|
||||
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
|
||||
Reference in New Issue
Block a user