extends Control # load from dialog vm const Dialog = preload("res://dialog_vm.gd") const DialogController = preload("res://dialog_controller.gd") # classes from there const DialogSegment = Dialog.DialogSegment const DialogWithSubjectSegment = Dialog.DialogWithSubjectSegment const DialogWithSubjectExpressionSegment = Dialog.DialogWithSubjectExpressionSegment const QuestionSegment = Dialog.QuestionSegment const ChoiceSegment = Dialog.ChoiceSegment const ChoiceWithJump = Dialog.ChoiceWithJump const Choice = Dialog.Choice const WaitSegment = Dialog.YieldCallSegment # resources specific to this dialogy thingy const DialogChoices = preload("res://ui/dialog_choices.tscn") const DialogChoice = preload("res://ui/dialog_choice.tscn") var IS_DEBUG = false var current_dialog var current_dialog_controller # ui elements onready var advance_button = get_node("top_panel/auto_btn") onready var fastforward_button = get_node("top_panel/ffwd_btn") onready var title_label = get_node("body_container/bottom_panel/subject_margin/subject_panel/subject_label") onready var body_container = get_node("body_container") onready var body_label = get_node("body_container/bottom_panel/body_margin/body_label") # clickable regions, for accessibility onready var top_panel = get_node("top_panel") onready var audio_player = get_node("audio_player") # params to set from outside var dialog_path # activeness var active # tween to fade in/out var tween # timer var timer # anim player, if any var anim_player # linkin in ur get_node relative to where you want var get_node_fnc # various main dialog related constants # signals signal entered_dialog signal exited_frame # character related signals signal on_speaker_expression_changed(spkr, expr) signal on_dialog_init(d) signal on_dialog_completed(d) # setters func set_auto_advance(v): current_dialog_controller.set_advance_state(v) advance_button.pressed = v # signals from dialog controller func _on_printing_changed(v): pass # next_arrow.visible = v func _on_reading_speed_changed(new_value): current_dialog_controller.set_reading_speed(new_value) func set_advance_state(): current_dialog_controller.set_advance_state(advance_button.is_pressed()) func set_fastforward_state(): var ffwd_pressed = fastforward_button.is_pressed() current_dialog_controller.set_fastforward_state(fastforward_button.is_pressed()) advance_button.set_disabled(ffwd_pressed) # init functions, must be called before use func set_dialog_path(path): dialog_path = path func set_dialog_vm(vm): current_dialog = vm func set_dialog_controller(c): current_dialog_controller = c func set_dialog_anim_player(p): anim_player = p func set_get_character_function(fnc): get_node_fnc = fnc func _ready(): advance_button.connect("pressed", self, "set_advance_state") fastforward_button.connect("pressed", self, "set_fastforward_state") # clicking to advance body_container.connect("gui_input", self, "_on_body_click") top_panel.connect("gui_input", self, "_on_body_click") Game.connect("on_reading_speed_changed", self, "_on_reading_speed_changed") Game.connect("on_settings_enter", self, "_on_settings_enter") Game.connect("on_settings_exit", self, "_on_settings_exit") tween = Tween.new() add_child(tween) timer = Timer.new() add_child(timer) func _on_body_click(ev): current_dialog_controller._on_body_click(is_active(), ev) func _register_func(r, reg_name, func_name): if r.has(reg_name): r[reg_name].set_instance(self) else: r[reg_name] = funcref(self, func_name) func _register_functions(): var r = current_dialog.get_local_registry() # normal functions _register_func(r, "SET_EXPR", "_set_expr_fnc") _register_func(r, "FLIP", "_flip_char") _register_func(r, "HIDE", "_hide_char") _register_func(r, "SHOW", "_show_char") # yieldy function _register_func(r, "WAIT", "_wait_dialog_fnc") # anim shite, also yieldy _register_func(r, "PLAY_ANIM", "_play_anim_fnc") # PLAY AND WAIT; HOW ABOUT DEM APPLES _register_func(r, "PLAY_ANIM_WITH_WAIT", "_play_wait_with_anim_fnc") func _play_wait_with_anim_fnc(args): if args.size() == 2: var anim_name = args[0] var wait_time = float(args[1]) if anim_player: anim_player.play(anim_name) timer.one_shot = true timer.wait_time = wait_time timer.start() return [timer, "timeout"] func _play_anim_fnc(args): if args.size() == 1: var anim_name = args[0] if anim_player: anim_player.play(anim_name) return [anim_player, "animation_finished"] func _wait_dialog_fnc(args): if args.size() == 1: var time = float(args[0]) print("Dialog: waiting for: %f seconds" % time) timer.wait_time = time timer.one_shot = true timer.start() return [timer, "timeout"] func _set_expr_fnc(args): if args.size() == 2: var speaker = args[0] var expr = args[1] _set_speaker_expression(speaker, expr) func _show_char(args): var char_name = args[0] var character = get_node_fnc.call(char_name) _do_show_char(character) func _do_show_char(c): tween.interpolate_property( c, "modulate:a", c.modulate.a, 1.0, 1.0, Tween.TRANS_QUAD, Tween.EASE_IN_OUT ) tween.start() func _hide_char(args): var char_name = args[0] var character = get_node_fnc.call(char_name) _do_hide_char(character) func _do_hide_char(c): tween.interpolate_property( c, "modulate:a", c.modulate.a, 0.0, 1.0, Tween.TRANS_QUAD, Tween.EASE_IN_OUT ) tween.start() func _flip_char(args): var char_name = args[0] var character = get_node_fnc.call(char_name) _do_flip_char(character) func _do_flip_char(c): c.flip_h = !c.flip_h func _on_settings_enter(s): if is_active(): visible = false func _on_settings_exit(s): if is_active(): visible = true func reload_dialog(): initialize_dialog() func get_local_registry(): return current_dialog.get_local_registry() func initialize_dialog(): assert(dialog_path != null) var dialog_file = File.new() dialog_file.open(dialog_path, File.READ) var text = dialog_file.get_as_text() dialog_file.close() var dialog = Dialog.dialog_from_text(text) current_dialog = dialog # also setup kv store for dialog variables current_dialog.set_registry(Game.current_registry) # set up controller too yes current_dialog_controller = DialogController.new(dialog, audio_player) # register functions _register_functions() # signals current_dialog_controller.connect("on_update_dialog", self, "_on_update_dialog") current_dialog_controller.connect("on_dialog_completed", self, "_on_dialog_completed") current_dialog_controller.connect("on_printing_changed", self, "_on_printing_changed") emit_signal("on_dialog_init", self) func _on_dialog_completed(d): emit_signal("on_dialog_completed", self) exit_frame() func _on_update_dialog(s): _update_dialog(s) func _fade_in(): var FADE_TIME = 1.0 tween.interpolate_property( self, "modulate:a", 0.0, 1.0, FADE_TIME, Tween.TRANS_QUAD, Tween.EASE_IN ) tween.start() func _fade_out(): var FADE_TIME = 1.0 tween.interpolate_property( self, "modulate:a", 1.0, 0.0, FADE_TIME, Tween.TRANS_QUAD, Tween.EASE_OUT ) tween.start() yield(tween, "tween_completed") visible = false func enter_frame(): _fade_in() var r = Game.current_registry r["IS_IN_DIALOG"] = true # reload if is debug if IS_DEBUG: reload_dialog() active = true visible = true current_dialog.reset() # next_arrow.visible = false emit_signal("entered_dialog") # dialogs var first_segment = current_dialog.advance() _update_dialog(first_segment) func is_active(): return active func exit_frame(): _fade_out() # HACK: cludge to reset state advance_button.set_pressed(false) fastforward_button.set_pressed(false) advance_button.emit_signal("pressed") fastforward_button.emit_signal("pressed") current_dialog_controller.reset() active = false var r = Game.current_registry r["IS_IN_DIALOG"] = false emit_signal("exited_frame") func _set_speaker_subject(subject): if Game.Characters.has(subject): var data = Game.Characters[subject] var subject_name = data.name var subject_colour = data.name_colour var subject_voice = data.voice current_dialog_controller.chars_per_second = Game.DEFAULT_CHARS_PER_SECOND * data.talking_speed _set_speaker_name(subject_name, subject_colour) if subject_voice != null: _set_speaker_voice(subject_voice) else: var subject_name = subject current_dialog_controller.chars_per_second = Game.DEFAULT_CHARS_PER_SECOND _set_speaker_name(subject_name, Color(1, 1, 1)) func _get_speaker_name(): return title_label.text func _set_speaker_name(speaker_name, colour = Color(1, 1, 1)): title_label.set_text(speaker_name) title_label.modulate = colour func _set_speaker_voice(voice_sample): audio_player.stream = voice_sample func _set_speaker_expression(speaker, expression): emit_signal("on_speaker_expression_changed", speaker, expression) # temporary maybe func _setup_question(new_question): body_container.add_child(new_question) current_dialog_controller.waiting_for_answer = true func _question_answered_yes(qs): body_container.remove_child(qs) current_dialog_controller.waiting_for_answer = false current_dialog_controller._advance_dialog() func _question_answered_no(qs): body_container.remove_child(qs) current_dialog_controller.waiting_for_answer = false exit_frame() func _choice_made(choice_modal, choice): if IS_DEBUG: print("chose: ", choice.get_choice()) # Game.add_history_entry("you", choice.get_choice()) remove_child(choice_modal) if choice is ChoiceWithJump: # HACK: fix this later or make this unnecessary var current_segment = current_dialog.jump(choice.target) call_deferred("_update_dialog", current_segment) else: _update_dialog(choice) current_dialog_controller.waiting_for_answer = false # loop de loop func _update_dialog(segment): if segment is ChoiceSegment: var choices = segment.get_choices() # create new dialog choices and shit var new_choices = DialogChoices.instance() var vbox = new_choices.get_node("vbox") for choice in choices: var new_choice = DialogChoice.instance() new_choice.text = choice.get_choice() new_choice.connect("pressed", self, "_choice_made", [new_choices, choice]) vbox.add_child(new_choice) add_child(new_choices) elif segment is Choice: var new_content = segment.get_response() if typeof(new_content) == TYPE_OBJECT and (new_content is DialogWithSubjectSegment or new_content is DialogWithSubjectExpressionSegment): _update_dialog(new_content) else: body_label.text = new_content # Game.add_history_entry(_get_speaker_name(), new_content) elif segment is DialogSegment or segment is DialogWithSubjectSegment or segment is DialogWithSubjectExpressionSegment: var new_content = segment.get_content() body_label.visible_characters = 0 body_label.text = new_content if segment is DialogWithSubjectSegment: _set_speaker_subject(segment.subject) # Game.add_history_entry(_get_speaker_name(), new_content) elif segment is DialogWithSubjectExpressionSegment: _set_speaker_subject(segment.subject) _set_speaker_expression(segment.subject, segment.expression) # Game.add_history_entry("%s (%s)" % [_get_speaker_name(), segment.expression], new_content) else: pass # Game.add_history_entry(_get_speaker_name(), new_content) elif segment is WaitSegment: var new_content = segment.get_content() body_label.visible_characters = 0 body_label.text = new_content # whatever subject you want during functions to wait on, animations and such _set_speaker_subject("") else: print("encountered unknown segment: " + segment.get_content()) current_dialog_controller.update_logic_dialog(segment) func _process(delta): if is_active(): current_dialog_controller.tick(delta, body_label)