Untitled

 avatar
unknown
python
a year ago
4.4 kB
16
Indexable
class_name DialogueBox
extends Control

enum MEMBER_TYPE {Dialogue, Choice, Animation}

@onready var speaker_label: Label = $%Name
@onready var text_label: RichTextLabel = $%Text
@onready var choice_container: HBoxContainer = %ChoiceContainer
@onready var name_box: TextureRect = %NameBox
@onready var animation_player: AnimationPlayer = $AnimationPlayer
@onready var tag_handler: TagHandler = %TagHandler
@onready var continue_label: Label = %ContinueLabel

const DEFAULT_TEXT_SPEED = 0.016

var conversation: Array
var text_speed: float = DEFAULT_TEXT_SPEED
var skip_pressed: bool = false
var dialogue_index: int
var break_dialogue: bool = false

var name_positions: Dictionary = {
	"move_name_in": -49,
	"move_name_out": 0,
}

func _ready() -> void:
	continue_label.visible = false
	var tween: Tween = create_tween()
	modulate.a = 0
	tween.tween_property(self, "modulate:a", 1, 0.5)
	var json: String = FileAccess.get_file_as_string("res://tools/dialogue/test_dialogue.json")
	parse_dialogue_json(json)

func _unhandled_input(_event: InputEvent) -> void:
	if Input.is_action_just_pressed("primary_attack") && !skip_pressed:
		skip_pressed = true

func parse_dialogue_json(json: String) -> void:
	if len(json) == 0:
		json = FileAccess.get_file_as_string("res://tools/dialogue/error_dialogue.json")
	conversation = JSON.parse_string(json)
	assign_next(conversation[0])
	
func assign_next(member: Dictionary) -> void:
	match int(member.get("type", MEMBER_TYPE.Dialogue)):
		MEMBER_TYPE.Dialogue:
			handle_dialogue(member)
		MEMBER_TYPE.Choice:
			handle_choices(member)
		MEMBER_TYPE.Animation:
			pass
			
func handle_dialogue(dialogue: Dictionary) -> void:
	text_speed = DEFAULT_TEXT_SPEED
	speaker_label.text = dialogue.get("name", "")
	
	if speaker_label.text == "":
		if name_box.position.y != name_positions["move_name_out"]:
			animation_player.play("move_name_in")
	else:
		if name_box.position.y != name_positions["move_name_in"]:
			animation_player.play("move_name_out")
			

	var text: String = dialogue.get("text", "An error has occured! Please report this to the developers.")
	dialogue_index = conversation.find(dialogue)

	tag_handler.find_pauses(text)
	text = tag_handler.extract_tags(text)
	text_label.text = text
	text_label.visible_characters = 0
	skip_pressed = false
	for index in text.length():
		text_label.visible_characters = index + 1
		await handle_tag(text_label.visible_characters - 1)
		if break_dialogue:
			break_dialogue = false
			goto_next()
			return
		if skip_pressed && !"skip" in dialogue.get("text"):
			text_label.visible_characters = -1
			continue_label.time = 0
			await get_tree().process_frame
			break
		continue_label.time = 0
		await get_tree().create_timer(text_speed).timeout
		
	while true:
		continue_label.visible = true
		if Input.is_action_just_pressed("primary_attack"):
			break
		await get_tree().process_frame
	
	continue_label.visible = false
	goto_next()
		
func goto_next() -> void:
	if dialogue_index < conversation.size() - 1:
		speaker_label.text = ""
		text_label.text = ""
		assign_next(conversation[dialogue_index + 1])
	else:
		var tween: Tween = create_tween()
		tween.tween_property(self, "modulate:a", 0, 0.5)
		tween.finished.connect(tween_finished)
		
func handle_tag(_string_pos: int) -> void:
	for tag: Tag in tag_handler.tags:
		if tag.pos == _string_pos:
			match tag.type:
				"pause":
					await get_tree().create_timer(tag.value).timeout
				"speed":
					text_speed = tag.value
				"skip":
					break_dialogue = true
	
func tween_finished() -> void:
	queue_free()

func handle_choices(member: Dictionary) -> void:
	if name_box.position.y != name_positions["move_name_out"]:
		animation_player.play("move_name_in")
	var choices: Dictionary = member.get("choices", {})
	var flag: String = member.get("flag", "default")
	for choice: String in choices:
		var button := ChoiceButton.new()
		button.text = choice
		choice_container.add_child(button)
		button.connect("button_down", choice_made.bind(flag, choice, choices[choice]))
		
func choice_made(flag: String, choice: String, next_json: String) -> void:
	for button in choice_container.get_children():
		button.queue_free()
	if flag != "default":
		Flags.flags[flag] = choice
	parse_dialogue_json(FileAccess.get_file_as_string(next_json))
Editor is loading...
Leave a Comment