src / dialogue / dialogue.gd

Code

extends CanvasLayer

signal finished
signal event(event_name: String)

@export_file_path("*.rb") var boot_file : String
@export var speakers : Array[DialogueSpeaker] = []
@onready var started : bool = false
@onready var controller := ReDScribe.new()
var current_speaker : String = ''
var waiting : bool = false


func _ready() -> void:
	controller.boot_file = boot_file
	controller.channel.connect(_handle)


func start() -> void:
	show()
	continue_dialogue()
	started = true
	Player.playable = false


func continue_dialogue() -> void:
	controller.perform('continue')


func says(
	speaker_name: String, content: String, position: StringName,
	face: String,
) -> void:
	if current_speaker != speaker_name:
		current_speaker = speaker_name
		%AnimationPlayer.play("show")
	if position == &'left':
		%LeftSpeakerImage.visible = true
		%RightSpeakerImage.visible = false
	else:
		%LeftSpeakerImage.visible = false
		%RightSpeakerImage.visible = true
	set_speaker_image(speaker_name, position, face)
	%Content.text = content


func set_speaker_image(speaker_name: String, position: StringName, face: String) -> void:
	var speaker_idx = speakers.find_custom(func(s):
		return s.speaker_name == speaker_name)
	if speaker_idx < 0: return
	var speaker = speakers[speaker_idx]
	var target = %LeftSpeakerImage if position == &'left' \
		else %RightSpeakerImage
	target.texture = speaker.texture
	target.hframes = speaker.faces.size() + 1
	var face_idx = speaker.faces.find(face)
	if face_idx >= 0:
		target.frame = face_idx + 1
	else:
		target.frame = 0


func _input(_event: InputEvent) -> void:
	if not started: return
	if waiting: return
	if _event.is_action_pressed('ui_accept'):
		continue_dialogue()


func _handle(key: StringName, payload: Variant) -> void:
	match key:
		&'says':
			var content = payload['content']
			if content is Array: content = "\n".join(content)
			says(payload['name'], content, payload['position'], payload['face'])
		&'event':
			event.emit(payload)
		&'wait':
			waiting = true
			%EventTimer.start(payload)
		&'finished':
			finished.emit()
		_: print_debug("[%s]: %s" % [key, payload])


func _on_event(_event_name: String) -> void:
	current_speaker = ''
	%AnimationPlayer.play("hide")


func _on_event_timer_timeout() -> void:
	waiting = false
	continue_dialogue()


func _on_finished() -> void:
	%AnimationPlayer.play("hide")
	await get_tree().create_timer(1.0).timeout
	Player.playable = true
	queue_free()