extends Node2D var can_advance_text = true var vn_current_name = null var vn_save_state = null var fishing_minigame_label = "" var fishing_minigame_finished = false var fishing_minigame_active = false const SHOULD_SAVE_PARSED_BUFFERS = false const START_VN_NAME = "00_content_warning" signal autosaved signal quick_saved func _ready(): if not FileGlobals.has_loaded: await FileGlobals.loaded if not MusicManager.has_loaded: await MusicManager.loaded #if SHOULD_SAVE_PARSED_BUFFERS: # parse_all_txt_scenes() $FishingMinigame.visible = false $ChatLog.visible = false # Get current load source from file globals load_game(FileGlobals.current_load_source, FileGlobals.current_load_file) #run_visual_novel(vn_current_name, FileGlobals.current_load_source == FileGlobals.VNLoadSource.NEW_GAME, vn_save_state) run_visual_novel(vn_current_name, false, vn_save_state) func _process(_delta): if Input.is_action_just_pressed("quicksave"): if save_game(FileGlobals.VNSaveTarget.MANUAL_SAVE): quick_saved.emit() elif Input.is_action_just_pressed("log"): toggle_chatlog() elif Input.is_action_just_pressed("ui_accept"): if should_process_click(): #if $Textbox.is_ready(): if $Textbox.is_idle(): can_advance_text = false $TimerCanAdvanceText.start() vn_step() else: $Textbox.skip() elif Input.is_action_just_pressed("click"): if should_process_click(): if $Textbox.is_idle(): var mouse_position = get_global_mouse_position() if mouse_position.x <= 60 and mouse_position.y <= 60: toggle_chatlog() else: can_advance_text = false $TimerCanAdvanceText.start() vn_step() else: $Textbox.skip() #if should_advance_textbox(): # if $Textbox.is_ready(): # vn_step() # else: # $Textbox.skip() func should_process_click() -> bool: return can_advance_text and not fishing_minigame_active and not $ChatLog.visible #func should_advance_textbox() -> bool: # if fishing_minigame_active or $ChatLog.visible: # return false # if Input.is_action_just_pressed("ui_accept"): # return true # if Input.is_action_just_pressed("click"): # var mouse_position = get_global_mouse_position() # if mouse_position.x <= 60 and mouse_position.y <= 60: # toggle_chatlog() # return false # return true # return false func toggle_chatlog(): if $ChatLog.visible: $ChatLog.visible = false $VNInterpreter.advance_sfx() elif $Textbox.is_ready(): $ChatLog.visible = true #$ChatLog.scroll_to_end() $ChatLog/CloseChatLogButtonContainer/CloseChatLogButton.grab_focus() $VNInterpreter.advance_sfx() else: print_debug("Can't open chatlog right now!") func load_game(load_source: FileGlobals.VNLoadSource, load_file): var save_data = FileGlobals.load_save_file(load_source, load_file) vn_current_name = save_data.get("current_vn", START_VN_NAME) vn_save_state = save_data.get("save_state", {}) func save_game(save_target: FileGlobals.VNSaveTarget): #if $FishingMinigame.visible or $ChatLog.visible or not $VNInterpreter.can_save(): if $FishingMinigame.visible or not $VNInterpreter.can_save(): print_debug("Can't save VN right now!") return false vn_save_state = $VNInterpreter.save_vn() FileGlobals.create_save_file(save_target, {"current_vn": vn_current_name, "save_state": vn_save_state}, vn_save_state["title"]) return true func parse_all_txt_scenes(): DirAccess.make_dir_absolute("user://compiled_scenes") for path in DirAccess.get_files_at("res://scenes/visual_novels"): if path.ends_with(".txt"): var data = $VNInterpreter.parse_vn_file("res://scenes/visual_novels/%s" % path) var file = FileAccess.open("user://compiled_scenes/%s.buf" % path.left(-4), FileAccess.WRITE) file.store_buffer(var_to_bytes_with_objects(data)) file.close() func run_visual_novel(vn_scene, should_autosave: bool = false, save_state = {}): vn_current_name = vn_scene # Find source for current file var file = null # Try pre-parsed scene first var should_parse = false var vn_file = "res://scenes/visual_novels/%s.buf" % vn_current_name file = FileAccess.open(vn_file, FileAccess.READ) if file: file.close() else: # Try unparsed scene should_parse = true vn_file = "res://scenes/visual_novels/%s.txt" % vn_current_name file = FileAccess.open(vn_file, FileAccess.READ) if file: file.close() else: assert(false, "Cannot find next VN scene '%s'!" % vn_scene) push_warning("Visual novel (%s) not found. Restarting visual novel..." % vn_scene) vn_current_name = START_VN_NAME save_state = {} var data = null if should_parse: # Parse the original file data = $VNInterpreter.parse_vn_file(vn_file) # Store parsed data if SHOULD_SAVE_PARSED_BUFFERS: DirAccess.make_dir_absolute("user://compiled_scenes") file = FileAccess.open("user://compiled_scenes/%s.buf" % vn_current_name, FileAccess.WRITE) file.store_buffer(var_to_bytes_with_objects(data)) file.close() else: # Load previously parsed data directly file = FileAccess.open(vn_file, FileAccess.READ) data = bytes_to_var_with_objects(file.get_buffer(file.get_length())) file.close() # Make sure MusicManager is ready before proceeding if not MusicManager.has_loaded: await MusicManager.loaded await $VNInterpreter.load_vn_data(data, save_state) # Autosave only when loading a new VN if should_autosave: var saved = save_game(FileGlobals.VNSaveTarget.AUTOSAVE) if vn_scene != START_VN_NAME and saved: autosaved.emit() vn_step() func vn_step(label = null): while true: var vn_value = await $VNInterpreter.advance_vn(label) label = null match vn_value: []: return ["@escape", ..]: match vn_value.slice(1): # @escape print my_var $my_var ["print", var value]: print("@print ", value) # @escape store_global name john_doe ["store_global", var key, var value]: FileGlobals.set_global_data(key, value) # @escape fishing done_fishing 0.5 false {"name":"label_for_fishing_01","sprite":"sprite_name_01"} {...} ["fishing", var label_finished, var difficulty_str, var boat_is_moving_str, ..]: fishing_minigame_label = label_finished var difficulty = float(difficulty_str) var is_moving = boat_is_moving_str == "true" fishing_minigame_finished = false var targets = [] for target_json in vn_value.slice(5): var target = JSON.parse_string(target_json) target["sprite"] = load("res://images/sprites/fishing_targets/%s.png" % target["sprite"]) targets.append(target) $FishingMinigame.start_fishing_minigame(targets, difficulty, is_moving) fishing_minigame_active = true $FishingMinigame.visible = true #$FishingMinigame/Net.can_move = true $TimerNetCanMove.start() $Sprites.visible = false $Textbox.visible = false $ChatLog/QuicksaveButtonContainer/QuicksaveButton.visible = false $OverlayColor.visible = false $Prompt.visible = false # $ChatLog.visible = false can_advance_text = false return ["return_to_fishing"]: if fishing_minigame_finished: $FishingMinigame.visible = false #$FishingMinigame/Net.can_move = false $Sprites.visible = true $Textbox.visible = true $ChatLog/QuicksaveButtonContainer/QuicksaveButton.visible = true $OverlayColor.visible = true $Prompt.visible = true # $ChatLog.visible = true label = fishing_minigame_label else: fishing_minigame_active = true #$FishingMinigame/Net.can_move = true $TimerNetCanMove.start() $Sprites.visible = false $Textbox.visible = false $OverlayColor.visible = false $Prompt.visible = false # $ChatLog.visible = false return _: push_warning("Unhandled @escape ", vn_value.slice(1)) return ["@load", var next_scene, ..]: run_visual_novel(next_scene, true) return ["@eof"]: push_warning("Reached end of VN instead of exiting gracefully!") get_tree().change_scene_to_file("res://scenes/screens/main_menu.tscn") return ["@quit"]: get_tree().change_scene_to_file("res://scenes/screens/main_menu.tscn") return _: push_warning("Unknown interrupt ", vn_value) func _on_fishing_minigame_fished(target_name): can_advance_text = false $TimerCanAdvanceText.start() fishing_minigame_active = false $FishingMinigame/Net.can_move = false $Sprites.visible = true $Textbox.visible = true $OverlayColor.visible = true $Prompt.visible = true # $ChatLog.visible = true vn_step(target_name) func _on_fishing_minigame_fished_all_targets(): fishing_minigame_finished = true func _on_timer_net_can_move_timeout(): $FishingMinigame/Net.can_move = true func _on_timer_can_advance_text_timeout(): can_advance_text = true func _on_close_chat_log_button_pressed(): toggle_chatlog() func _on_quicksave_button_pressed(): if save_game(FileGlobals.VNSaveTarget.MANUAL_SAVE): quick_saved.emit()