From 8244f85790fa457ec3340302fa0625538645e2fc Mon Sep 17 00:00:00 2001 From: betalars Date: Wed, 3 Jun 2026 14:40:20 +0200 Subject: [PATCH] re-implement dynamic loading during menu --- src/dev-util/room.gd | 16 +- src/dev-util/savegame.gd | 35 +- src/logic-scenes/card_burner/card_burner.gd | 5 +- src/logic-scenes/card_picker/card_picker.gd | 2 +- src/singletons/global_state.gd | 5 +- src/singletons/main/main.gd | 204 ++-- src/singletons/main/main.tscn | 1003 +++++++++++++++++-- src/ui/curtain/curtain.gd | 64 +- 8 files changed, 1181 insertions(+), 153 deletions(-) diff --git a/src/dev-util/room.gd b/src/dev-util/room.gd index 7631327a..6892d5e1 100644 --- a/src/dev-util/room.gd +++ b/src/dev-util/room.gd @@ -6,7 +6,8 @@ class_name Room @onready var ui: Control = %UI ## Tells the main loop to proceed to the next scene -signal proceed(next_scene_path: String) +signal prepare_next(room_id: Room.ids) +signal proceed_to(room_id: Room.ids) enum ids { NULL, @@ -49,19 +50,18 @@ func get_ready_async(): func start_room_async(): prints("----------", "START_ROOM", self.name, "--------------") + await Main.curtain.open() + get_tree().paused = false await get_tree().process_frame # so this registers as a coroutine in IDE -func play() -> String: - for i in range(20): await get_tree().process_frame #HACK - can probably be removed - +func play() -> void: await get_ready_async() await start_room_async() - var next_room : StringName = await proceed - prints("----------", "PROCEEDING", next_room, "--------------") - return next_room - +func prepare_for_unload(next_room: Room.ids): + prints("----------", "PREPARE_UNLOAD", Room.ids.keys()[id], "PREPARE_LOAD", Room.ids.keys()[next_room], "--------------") + prepare_next.emit(next_room) func pull_save_state(save: SaveGame) -> void: # Override this function to load the state of the chapter from State.save_game diff --git a/src/dev-util/savegame.gd b/src/dev-util/savegame.gd index 5ec3f7b9..390aa193 100644 --- a/src/dev-util/savegame.gd +++ b/src/dev-util/savegame.gd @@ -8,8 +8,8 @@ class_name SaveGame extends Resource @export var unique_save_name: String = "" @export var current_room: Room.ids = Room.ids.NULL -@export_flags("Intro", "Childhood", "Voice Training", "Jui Jutsu") var mementos_complete: int = 0 -@export_flags_2d_physics var sequences_enabled: int = 63 +@export_flags_2d_physics var mementos_complete: int = 0 +@export_flags_2d_physics var sequences_enabled: int = 0 # Board state - properly typed fields @export var board_positions: Dictionary[StringName, Vector2] = {} # Position of all cards and stickies @@ -19,7 +19,7 @@ class_name SaveGame extends Resource @export var seen : Array[StringName] = [] @export var childhood_board_complete: bool = false -@export var subway_burnout : bool = false +@export var subway_uni : bool = false @export var player_position : Vector3 = Vector3.ZERO @export var player_yaw : float = 0.0 @@ -35,7 +35,7 @@ var current_room_path: String: get: return Main.room_paths[current_room] if Main else "" var is_empty: bool: - get: return not FileAccess.file_exists(file_name) or (current_room == State.rooms.NULL) + get: return not FileAccess.file_exists(file_name) or (current_room == Room.ids.NULL) var completed_sequences: int: get: @@ -53,7 +53,8 @@ var total_connections: int: # === State Variables / External Data === ## Where to save the savegame to / where it was loaded from var file_name: String = "" - +## This ensures compatibility with Steam, because it will give absolute paths only. +var absolute_path: String = "" ## Screenshot or placeholder image var thumbnail: Texture = preload("res://import/interface-elements/empty_save_slot.png") @@ -102,7 +103,16 @@ static func load_from_file(save_filepath: String) -> SaveGame: if not loaded.is_valid: push_error("SaveGame: Validation failed: %s" % save_filepath) return null - + + if not save_filepath.is_absolute_path(): + var helper:= FileAccess.open(save_filepath, FileAccess.READ) + loaded.absolute_path = helper.get_path_absolute() + helper.close() + else: + loaded.absolute_path = save_filepath + + Steamworks.save_list[loaded.absolute_path] = loaded + return loaded ## Helper to load thumbnail from separate PNG file @@ -148,6 +158,9 @@ func save_to_file(screen_shot: Texture2D) -> void: capture_player_state() last_saved = int(Time.get_unix_time_from_system()) + if Steamworks.steam_cloud_on: + Steam.beginFileWriteBatch() + # Save thumbnail _save_thumbnail(screen_shot) @@ -157,6 +170,16 @@ func save_to_file(screen_shot: Texture2D) -> void: push_error("Failed to save resource to: %s (Error: %d)" % [file_name, result]) else: print("Successfully saved to: %s" % file_name) + + if not file_name.is_absolute_path(): + var helper:= FileAccess.open(file_name, FileAccess.READ) + absolute_path = helper.get_path_absolute() + helper.close() + else: + absolute_path = file_name + + if Steamworks.steam_cloud_on: + Steam.endFileWriteBatch() ## Processes and saves thumbnail as PNG func _save_thumbnail(screen_shot: Texture2D) -> void: diff --git a/src/logic-scenes/card_burner/card_burner.gd b/src/logic-scenes/card_burner/card_burner.gd index ccefdbeb..8e8aae9c 100644 --- a/src/logic-scenes/card_burner/card_burner.gd +++ b/src/logic-scenes/card_burner/card_burner.gd @@ -24,8 +24,8 @@ func _ready(): func vanish(): super.vanish() - await Main.curtain.black() # Go straight to loading screen - State.room.proceed.emit(Main.transition_room_path) + await Main.curtain.blackout() # Go straight to loading screen + State.active_room.proceed_to.emit(Room.ids.TRANSITION) ## Main play coroutine - simple linear flow for burning a card @@ -43,6 +43,7 @@ func play() -> void: await $AnimationPlayer.animation_finished print("CardBurner: Sequence complete") + vanish() func _populate() -> void: diff --git a/src/logic-scenes/card_picker/card_picker.gd b/src/logic-scenes/card_picker/card_picker.gd index 81eff1c9..3ea3c05d 100644 --- a/src/logic-scenes/card_picker/card_picker.gd +++ b/src/logic-scenes/card_picker/card_picker.gd @@ -229,7 +229,7 @@ func pick_cards(id: Scenes.id): if id == Scenes.id.YOUTH_DRAVEN: $Meaning.play() - State.room.scene_player.play("intro") + State.active_room.scene_player.play("intro") await cards_picked hide() diff --git a/src/singletons/global_state.gd b/src/singletons/global_state.gd index 67c9cfbc..35c0ce82 100644 --- a/src/singletons/global_state.gd +++ b/src/singletons/global_state.gd @@ -12,8 +12,9 @@ var all_ready: bool: return _settings_initialized and _savegame_initialized func saves_loaded(save: SaveGame): - save_game = save - _savegame_initialized = true + if not _savegame_initialized: + save_game = save + _savegame_initialized = true var active_room: Room diff --git a/src/singletons/main/main.gd b/src/singletons/main/main.gd index ac7a55df..e102e588 100644 --- a/src/singletons/main/main.gd +++ b/src/singletons/main/main.gd @@ -1,14 +1,15 @@ extends Control var normal_boot : bool = false -@onready var menu_animation: AnimationNodeStateMachinePlayback = %MenuAnimationTree.get("parameters/playback") +@onready var menu_animation: AnimationPlayer = %MenuAnimationPlayer +@onready var load_animation: AnimationPlayer = %LoadAnimation @export_file(".tscn") var youth_room_path: String @export_file(".tscn") var transition_room_path: String @export_file(".tscn") var adulthood_room_path: String @export_file(".tscn") var ending_path: String -@onready var curtain: Panel = %Curtain +@onready var curtain: Curtain = %Curtain @onready var credits_roll: Control = %CreditsRoll @onready var main_menu: MainMenu = %MainMenu @onready var pause_menu: PauseMenu = %PauseMenu @@ -25,24 +26,39 @@ enum AppState {INIT, LOADING, MENU, PLAY, PAUSE, CREDITS} var state: AppState = AppState.INIT: set(value): - print("main.gd: app_state changing to: %s" % str(state)) + print("main.gd: app_state changing to: %s" % str(value)) match value: AppState.INIT: - pass - AppState.LOADING: - %MenuAnimationTree["parameters/conditions/loading_done"] = false + credits_roll.hide() + main_menu.hide() + pause_menu.hide() AppState.MENU: - menu_animation.travel("loading_menu") - await main_menu.execute() + credits_roll.hide() + pause_menu.hide() + main_menu.execute() + hotswap_ready = true + AppState.LOADING: + credits_roll.hide() + main_menu.hide() + pause_menu.hide() AppState.PLAY: - menu_animation.travel("start_game") - await_ui_clear() - hide() + credits_roll.hide() + main_menu.hide() + pause_menu.hide() + hotswap_ready = false + menu_animation.play("hide_pause_menu") + if state == AppState.PAUSE: + menu_animation.play("hide_pause_menu") AppState.PAUSE: - menu_animation.travel("reveal_pause_menu") + credits_roll.hide() + main_menu.hide() + pause_menu.appear() + menu_animation.play("reveal_pause_menu") AppState.CREDITS: - menu_animation.travel("credits_roll") - + main_menu.hide() + pause_menu.hide() + credits_roll.play() + state = value func _enter_tree() -> void: @@ -52,94 +68,164 @@ func _ready() -> void: print("main.gd: _ready()") main_menu.continue_button.pressed.connect(func(): state = AppState.PLAY) main_menu.credits_button.pressed.connect(func(): state = AppState.CREDITS) + State.savegame_changed.connect(_on_savegame_changed) - #await get_tree().process_frame - await await_boot_completed() + await _boot_completed() if normal_boot: print("main.gd: normal boot (loading last save and showing main menu)") - call_deferred("start_menu") + startup.call_deferred() else: + curtain.open() print("main.gd: direct boot (hiding menus and entering main loop)") state = AppState.PLAY -func start_menu(): - - if Steam.resume_from_steamdeck(): - start_game() - - initialise_room(State.save_game.current_room) - state = AppState.MENU - +#region sequence handling -func await_boot_completed(): +func _boot_completed(): print("main.gd: Awaiting Boot Completion ...") while not State.all_ready: await get_tree().process_frame print("main.gd: Boot Completed.") -func await_ui_clear(): - print("main.gd: Awaiting Menu Clear ...") - while not menu_animation.get_current_node() == "start_game": - await get_tree().process_frame - print("main.gd: Menu Cleared.") +func startup(): + state = AppState.MENU + initialise_room(State.get_room_id()) func start_game(save: SaveGame = State.save_game) -> void: print("main.gd: play_game()") - initialise_room(save.current_room) - State.active_room.play() - state = AppState.PLAY + if await initialise_room(save.current_room): + State.active_room.play() + State.active_room.prepare_next.connect(prepare_next_room) + State.active_room.proceed_to.connect(swap_room) + state = AppState.PLAY + else: + push_error("main.gd: Room failed to load during game startup!") - # Ending? Roll credits? +func prepare_next_room(new_room: Room.ids): + _load_room(room_paths.get(new_room, youth_room_path) as String) + +func swap_room(new_room: Room.ids): + print("main.gd: Swapping rooms ...") + get_tree().paused = true + state = AppState.LOADING + State.save_game.current_room = new_room + # initialize_room is blocked from completing because of hotswap being false + start_game() + await curtain.blackout() + hotswap_ready = true + # room will start as soon as loading is done. + func is_game_active() -> bool: return state == AppState.PLAY or state == AppState.PAUSE -func initialise_room(room_id: Room.ids): +func initialise_room(room_id: Room.ids) -> bool: if State.active_room: if State.active_room.id == room_id: - return - else: - menu_animation.travel("change_savegame") - _load_room(room_paths.get(room_id, youth_room_path) as String) + return true + return await _load_room(room_paths.get(room_id, youth_room_path) as String) -func _load_room(scene_path: String) -> void: - ResourceLoader.load_threaded_request(scene_path, "PackedScene", true) +## Loops for at least one frame and until a room is safely loaded. +func assure_room_initialized(): + # just to make extra sure there is no room put to queue_free. + await get_tree().physics_frame + while not (current_loadpath == null and State.active_room): + await get_tree().physics_frame - await get_tree().create_timer(0.1).timeout +func handle_save_update(files_changed: PackedStringArray, files_deleted: PackedStringArray): + main_menu.save_game_list.reload_all_saves() + + if files_deleted.has(State.save_game.absolute_path): + State.save_game = main_menu.save_game_list.get_most_recent_save() + elif files_changed.has(State.save_game.absolute_path): + State.save_game = Steamworks.save_list[State.save_game.absolute_path] + +#region load handling + +var load_id: int +var current_loadpath: String +var hotswap_ready: bool = true + +## Unloads the current room, there is no harm in calling this multiple times. +func _unload_current_room(): if State.active_room: State.active_room.unload() State.active_room.queue_free() State.active_room = null - while true: +## This function starts loading a new room in the background. Calling it twice will result in the previous load being abandoned. +func _load_room(scene_path: String) -> bool: + var this_load_id := randi() + + var error:= ResourceLoader.load_threaded_request(scene_path, "PackedScene", true) + + if error == Error.OK: + %LoadAnimation.play("LoadAnimation/loading_idle") + load_id = this_load_id + current_loadpath = scene_path + + while true: + await get_tree().process_frame + var load_state := ResourceLoader.load_threaded_get_status(scene_path) + if this_load_id != load_id: + push_warning("main.gd: Interrupt while loading a room, aborting.") + if current_loadpath != scene_path: + call_deferred("_clear_loader_cache", scene_path) + return false + match load_state: + ResourceLoader.THREAD_LOAD_LOADED: + while not hotswap_ready: + await get_tree().process_frame + _unload_current_room() + var next_scene := ResourceLoader.load_threaded_get(scene_path) as PackedScene + current_loadpath = "" + State.active_room = next_scene.instantiate() as Room + %Stage.add_child(State.active_room) + await get_tree().process_frame + load_animation.play("LoadAnimation/loading_done") + curtain.open() + return true + ResourceLoader.THREAD_LOAD_FAILED: + break + + push_error("main.gd: Couldn't load room %s" % scene_path) + else: + push_error(error_string(error)) + return false + +# As a load request cannot be aborted, this makes sure the Cache is cleared. +func _clear_loader_cache(path): + while ResourceLoader.load_threaded_get_status(path) == ResourceLoader.THREAD_LOAD_IN_PROGRESS: await get_tree().process_frame - var load_state := ResourceLoader.load_threaded_get_status(scene_path) - match load_state: - ResourceLoader.THREAD_LOAD_LOADED: - var next_scene := ResourceLoader.load_threaded_get(scene_path) as PackedScene - State.active_room = next_scene.instantiate() as Room - %Stage.add_child(State.active_room) - await get_tree().process_frame - %MenuAnimationTree["parameters/conditions/loading_done"] = true - return - ResourceLoader.THREAD_LOAD_FAILED: - push_error("Failed to load room.") - break - - assert(false, "Couldn't load room %s" % scene_path) + if ResourceLoader.load_threaded_get_status(path) == ResourceLoader.THREAD_LOAD_LOADED: + var dump = ResourceLoader.load_threaded_get(path) +func _on_savegame_changed(): + if is_game_active(): + push_warning("SaveGame change during active play. Might be unintentional.") + get_tree().paused = true + await curtain.blackout() + if State.active_room.id != State.save_game.current_room: + state = AppState.MENU + _unload_current_room() + else: + Prompts.display_hint("reload_hint", 5) + await State.active_room.play() + return + + initialise_room(State.save_game.current_room) var last_mode := DisplayServer.WINDOW_MODE_WINDOWED func _unhandled_input(event: InputEvent) -> void: #if event.is_actionxxx_type(): print_debug("Unhandled Input", event) - if event.is_action_pressed("ui_pause") and state == AppState.PLAY: + if event.is_action_pressed("pause") and state == AppState.PLAY: state = AppState.PAUSE if not Engine.is_editor_hint(): diff --git a/src/singletons/main/main.tscn b/src/singletons/main/main.tscn index 5b11bb15..9007fd3f 100644 --- a/src/singletons/main/main.tscn +++ b/src/singletons/main/main.tscn @@ -1,16 +1,19 @@ -[gd_scene load_steps=17 format=3 uid="uid://befxf8uruwnrl"] +[gd_scene format=3 uid="uid://befxf8uruwnrl"] [ext_resource type="Script" uid="uid://k8yppfbkq0xv" path="res://singletons/main/main.gd" id="1_rqkns"] [ext_resource type="PackedScene" uid="uid://gldtxysavetf" path="res://logic-scenes/startup/startup.tscn" id="1_v5rpm"] -[ext_resource type="PackedScene" uid="uid://cml5liawokdch" path="res://ui/curtain/curtain.tscn" id="2_nbcxq"] +[ext_resource type="Script" uid="uid://cg7sc173lvchp" path="res://ui/curtain/curtain.gd" id="2_fo06q"] [ext_resource type="PackedScene" uid="uid://b51wdql4mby47" path="res://ui/menu_main/main_menu.tscn" id="3_ik73t"] -[ext_resource type="PackedScene" uid="uid://d38f0a333kki1" path="res://ui/loading/loading.tscn" id="5_dxvjq"] [ext_resource type="PackedScene" uid="uid://6aaxpvoepqrm" path="res://logic-scenes/disclaimer/disclaimer.tscn" id="7_t45fc"] [ext_resource type="Script" uid="uid://0h0lrkntx0uh" path="res://ui/menu_main/pause_menu.gd" id="9_ihfph"] [ext_resource type="Texture2D" uid="uid://ds1n0xhxqlp4b" path="res://base-environments/youth_room/shaders/universe_noise.png" id="9_l7v4b"] +[ext_resource type="Texture2D" uid="uid://d031kxe5m4ihh" path="res://import/interface-elements/loading_rect_clip.png" id="10_4r37y"] [ext_resource type="Texture2D" uid="uid://bdyg065h8vcdi" path="res://base-environments/youth_room/shaders/starlight-textures.png" id="10_pipov"] +[ext_resource type="Texture2D" uid="uid://bqf82f8dk4yun" path="res://import/interface-elements/loading_rect_frame.png" id="11_fo06q"] [ext_resource type="PackedScene" uid="uid://cbpcjk1qr2iiu" path="res://ui/credits_roll/credits_roll.tscn" id="11_wtpde"] [ext_resource type="Script" uid="uid://sa15wakvpj2e" path="res://dev-util/bug_button.gd" id="12_cegan"] +[ext_resource type="Texture2D" uid="uid://dpftqdvtrkioh" path="res://import/interface-elements/loading_rect_deco.png" id="12_p5e7r"] +[ext_resource type="AudioStream" uid="uid://fej7yw25lgqy" path="res://import/menu_music/Ambient 6.ogg" id="13_man8y"] [sub_resource type="GDScript" id="GDScript_8sq0u"] script/source = "extends Label @@ -83,7 +86,837 @@ fill = 1 fill_from = Vector2(0.538462, 0.491453) fill_to = Vector2(1.3, -0.3) -[node name="main" type="Control"] +[sub_resource type="GDScript" id="GDScript_jqvqy"] +script/source = "extends Label + +@export var animation_speed: float = 0.2 + +var _base_text: String +func _ready() -> void: + _base_text = text + + +var _accumulate_delta: float = 0 +var _frame: int = 0 +func _process(delta: float) -> void: + _accumulate_delta += delta + if _accumulate_delta > animation_speed: + _frame += 1 + _accumulate_delta = 0 + var dots: String + match _frame % 4: + 1: dots = \".\" + 2: dots = \"..\" + 3: dots = \"...\" + _: dots = \"\" + text = \"%s %s\" % [TranslationServer.translate(_base_text), dots] + +" + +[sub_resource type="Animation" id="Animation_y6s08"] +resource_name = "RESET" +length = 0.001 +tracks/0/type = "value" +tracks/0/imported = false +tracks/0/enabled = true +tracks/0/path = NodePath(".:modulate") +tracks/0/interp = 1 +tracks/0/loop_wrap = true +tracks/0/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [Color(1, 1, 1, 0)] +} +tracks/1/type = "value" +tracks/1/imported = false +tracks/1/enabled = true +tracks/1/path = NodePath(".:rotation") +tracks/1/interp = 1 +tracks/1/loop_wrap = true +tracks/1/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [1.5708] +} +tracks/2/type = "value" +tracks/2/imported = false +tracks/2/enabled = true +tracks/2/path = NodePath("frame/deco:rotation") +tracks/2/interp = 1 +tracks/2/loop_wrap = true +tracks/2/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [-0.314159] +} +tracks/3/type = "value" +tracks/3/imported = false +tracks/3/enabled = true +tracks/3/path = NodePath("frame/deco:modulate") +tracks/3/interp = 1 +tracks/3/loop_wrap = true +tracks/3/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [Color(1, 1, 1, 0)] +} +tracks/4/type = "value" +tracks/4/imported = false +tracks/4/enabled = true +tracks/4/path = NodePath("%Curtain:modulate") +tracks/4/interp = 1 +tracks/4/loop_wrap = true +tracks/4/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [Color(0, 0, 0, 1)] +} +tracks/5/type = "value" +tracks/5/imported = false +tracks/5/enabled = true +tracks/5/path = NodePath("%MainMenu:modulate") +tracks/5/interp = 1 +tracks/5/loop_wrap = true +tracks/5/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [Color(1, 1, 1, 1)] +} +tracks/6/type = "value" +tracks/6/imported = false +tracks/6/enabled = true +tracks/6/path = NodePath("%MainMenu:visible") +tracks/6/interp = 1 +tracks/6/loop_wrap = true +tracks/6/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 1, +"values": [true] +} +tracks/7/type = "value" +tracks/7/imported = false +tracks/7/enabled = true +tracks/7/path = NodePath("%Curtain:visible") +tracks/7/interp = 1 +tracks/7/loop_wrap = true +tracks/7/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 1, +"values": [false] +} +tracks/8/type = "value" +tracks/8/imported = false +tracks/8/enabled = true +tracks/8/path = NodePath("../../PauseMenu/TextureRect:modulate") +tracks/8/interp = 1 +tracks/8/loop_wrap = true +tracks/8/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [Color(1, 1, 1, 1)] +} +tracks/9/type = "value" +tracks/9/imported = false +tracks/9/enabled = true +tracks/9/path = NodePath("../../PauseMenu/PauseBackground/VBoxContainer:modulate") +tracks/9/interp = 1 +tracks/9/loop_wrap = true +tracks/9/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [Color(1, 1, 1, 0)] +} +tracks/10/type = "value" +tracks/10/imported = false +tracks/10/enabled = true +tracks/10/path = NodePath("../../PauseMenu/PauseBackground:modulate") +tracks/10/interp = 1 +tracks/10/loop_wrap = true +tracks/10/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [Color(1, 1, 1, 1)] +} +tracks/11/type = "value" +tracks/11/imported = false +tracks/11/enabled = true +tracks/11/path = NodePath("%MainMenu:visible") +tracks/11/interp = 1 +tracks/11/loop_wrap = true +tracks/11/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 1, +"values": [true] +} +tracks/12/type = "value" +tracks/12/imported = false +tracks/12/enabled = true +tracks/12/path = NodePath("%MainMenu:modulate") +tracks/12/interp = 1 +tracks/12/loop_wrap = true +tracks/12/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [Color(1, 1, 1, 1)] +} +tracks/13/type = "value" +tracks/13/imported = false +tracks/13/enabled = true +tracks/13/path = NodePath("../../CreditsRoll:visible") +tracks/13/interp = 1 +tracks/13/loop_wrap = true +tracks/13/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 1, +"values": [false] +} +tracks/14/type = "value" +tracks/14/imported = false +tracks/14/enabled = true +tracks/14/path = NodePath("../../CreditsRoll:modulate") +tracks/14/interp = 1 +tracks/14/loop_wrap = true +tracks/14/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [Color(1, 1, 1, 0)] +} +tracks/15/type = "value" +tracks/15/imported = false +tracks/15/enabled = true +tracks/15/path = NodePath("../../CreditsRoll:position") +tracks/15/interp = 1 +tracks/15/loop_wrap = true +tracks/15/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [Vector2(0, 220)] +} +tracks/16/type = "value" +tracks/16/imported = false +tracks/16/enabled = true +tracks/16/path = NodePath("../LoadingLabel:visible") +tracks/16/interp = 1 +tracks/16/loop_wrap = true +tracks/16/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 1, +"values": [false] +} +tracks/17/type = "value" +tracks/17/imported = false +tracks/17/enabled = true +tracks/17/path = NodePath("../LoadingLabel:modulate") +tracks/17/interp = 1 +tracks/17/loop_wrap = true +tracks/17/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [Color(1, 1, 1, 1)] +} +tracks/18/type = "value" +tracks/18/imported = false +tracks/18/enabled = true +tracks/18/path = NodePath("../LoadingLabel:position") +tracks/18/interp = 1 +tracks/18/loop_wrap = true +tracks/18/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [Vector2(100, -37)] +} +tracks/19/type = "value" +tracks/19/imported = false +tracks/19/enabled = true +tracks/19/path = NodePath("%PauseMenu:visible") +tracks/19/interp = 1 +tracks/19/loop_wrap = true +tracks/19/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 1, +"values": [false] +} +tracks/20/type = "value" +tracks/20/imported = false +tracks/20/enabled = true +tracks/20/path = NodePath("%PauseMenu:modulate") +tracks/20/interp = 1 +tracks/20/loop_wrap = true +tracks/20/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [Color(1, 1, 1, 1)] +} + +[sub_resource type="Animation" id="Animation_sfr6l"] +resource_name = "credits_roll" +length = 130.003 +tracks/0/type = "value" +tracks/0/imported = false +tracks/0/enabled = true +tracks/0/path = NodePath("%MainMenu:visible") +tracks/0/interp = 0 +tracks/0/loop_wrap = true +tracks/0/keys = { +"times": PackedFloat32Array(0.6666667, 0.9), +"transitions": PackedFloat32Array(1, 1), +"update": 1, +"values": [true, false] +} +tracks/1/type = "audio" +tracks/1/imported = false +tracks/1/enabled = true +tracks/1/path = NodePath("../../MenuAnimationPlayer/AudioStreamPlayer") +tracks/1/interp = 1 +tracks/1/loop_wrap = true +tracks/1/keys = { +"clips": [{ +"end_offset": 0.0, +"start_offset": 2.68, +"stream": ExtResource("13_man8y") +}], +"times": PackedFloat32Array(0.0133328) +} +tracks/1/use_blend = true +tracks/2/type = "value" +tracks/2/imported = false +tracks/2/enabled = true +tracks/2/path = NodePath("%Curtain:visible") +tracks/2/interp = 1 +tracks/2/loop_wrap = true +tracks/2/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 1, +"values": [true] +} +tracks/3/type = "value" +tracks/3/imported = false +tracks/3/enabled = true +tracks/3/path = NodePath("%Curtain:modulate") +tracks/3/interp = 1 +tracks/3/loop_wrap = true +tracks/3/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [Color(0, 0, 0, 1)] +} +tracks/4/type = "value" +tracks/4/imported = false +tracks/4/enabled = true +tracks/4/path = NodePath("../../CreditsRoll:visible") +tracks/4/interp = 1 +tracks/4/loop_wrap = true +tracks/4/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 1, +"values": [true] +} +tracks/5/type = "value" +tracks/5/imported = false +tracks/5/enabled = true +tracks/5/path = NodePath("../../CreditsRoll:modulate") +tracks/5/interp = 1 +tracks/5/loop_wrap = true +tracks/5/keys = { +"times": PackedFloat32Array(0, 2), +"transitions": PackedFloat32Array(1, 1), +"update": 0, +"values": [Color(1, 1, 1, 0), Color(1, 1, 1, 1)] +} +tracks/6/type = "value" +tracks/6/imported = false +tracks/6/enabled = true +tracks/6/path = NodePath("../../CreditsRoll:position") +tracks/6/interp = 1 +tracks/6/loop_wrap = true +tracks/6/keys = { +"times": PackedFloat32Array(1.86667, 121.188), +"transitions": PackedFloat32Array(1.46409, 1), +"update": 0, +"values": [Vector2(0, 220), Vector2(0, -4134)] +} +tracks/7/type = "value" +tracks/7/imported = false +tracks/7/enabled = true +tracks/7/path = NodePath("%MainMenu:modulate") +tracks/7/interp = 1 +tracks/7/loop_wrap = true +tracks/7/keys = { +"times": PackedFloat32Array(0, 0.63), +"transitions": PackedFloat32Array(1, 1), +"update": 0, +"values": [Color(1, 1, 1, 1), Color(1, 1, 1, 0)] +} + +[sub_resource type="Animation" id="Animation_lh4gu"] +resource_name = "hide_pause_menu" +length = 1.5 +tracks/0/type = "value" +tracks/0/imported = false +tracks/0/enabled = true +tracks/0/path = NodePath("%PauseMenu:visible") +tracks/0/interp = 0 +tracks/0/loop_wrap = true +tracks/0/keys = { +"times": PackedFloat32Array(0, 2), +"transitions": PackedFloat32Array(1, 1), +"update": 1, +"values": [true, false] +} +tracks/1/type = "value" +tracks/1/imported = false +tracks/1/enabled = true +tracks/1/path = NodePath("../../PauseMenu/TextureRect:modulate") +tracks/1/interp = 1 +tracks/1/loop_wrap = true +tracks/1/keys = { +"times": PackedFloat32Array(0, 1.4666667), +"transitions": PackedFloat32Array(1, 1), +"update": 0, +"values": [Color(1, 1, 1, 1), Color(1, 1, 1, 0)] +} +tracks/2/type = "value" +tracks/2/imported = false +tracks/2/enabled = true +tracks/2/path = NodePath("%PauseMenu:modulate") +tracks/2/interp = 1 +tracks/2/loop_wrap = true +tracks/2/keys = { +"times": PackedFloat32Array(0.13333334, 0.36666667), +"transitions": PackedFloat32Array(1, 1), +"update": 0, +"values": [Color(1, 1, 1, 1), Color(1, 1, 1, 0)] +} +tracks/3/type = "value" +tracks/3/imported = false +tracks/3/enabled = true +tracks/3/path = NodePath("../../PauseMenu/PauseBackground/VBoxContainer:modulate") +tracks/3/interp = 1 +tracks/3/loop_wrap = true +tracks/3/keys = { +"times": PackedFloat32Array(0.26666668, 0.93333334), +"transitions": PackedFloat32Array(1, 1), +"update": 0, +"values": [Color(1, 1, 1, 1), Color(1, 1, 1, 0)] +} + +[sub_resource type="Animation" id="Animation_l5ynk"] +resource_name = "init" +length = 0.5 +tracks/0/type = "value" +tracks/0/imported = false +tracks/0/enabled = true +tracks/0/path = NodePath("%Curtain:modulate") +tracks/0/interp = 1 +tracks/0/loop_wrap = true +tracks/0/keys = { +"times": PackedFloat32Array(0, 0.5), +"transitions": PackedFloat32Array(1, 1), +"update": 0, +"values": [Color(0, 0, 0, 1), Color(1, 1, 1, 1)] +} +tracks/1/type = "value" +tracks/1/imported = false +tracks/1/enabled = true +tracks/1/path = NodePath("%Curtain:visible") +tracks/1/interp = 1 +tracks/1/loop_wrap = true +tracks/1/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 1, +"values": [true] +} +tracks/2/type = "value" +tracks/2/imported = false +tracks/2/enabled = true +tracks/2/path = NodePath("%MainMenu:visible") +tracks/2/interp = 1 +tracks/2/loop_wrap = true +tracks/2/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 1, +"values": [true] +} +tracks/3/type = "value" +tracks/3/imported = false +tracks/3/enabled = true +tracks/3/path = NodePath("%MainMenu:modulate") +tracks/3/interp = 1 +tracks/3/loop_wrap = true +tracks/3/keys = { +"times": PackedFloat32Array(0, 0.5), +"transitions": PackedFloat32Array(1, 1), +"update": 0, +"values": [Color(1, 1, 1, 0), Color(1, 1, 1, 1)] +} + +[sub_resource type="Animation" id="Animation_s5m6i"] +resource_name = "reveal_pause_menu" +tracks/0/type = "value" +tracks/0/imported = false +tracks/0/enabled = true +tracks/0/path = NodePath("../../PauseMenu/TextureRect:modulate") +tracks/0/interp = 1 +tracks/0/loop_wrap = true +tracks/0/keys = { +"times": PackedFloat32Array(0, 0.933333), +"transitions": PackedFloat32Array(1, 1), +"update": 0, +"values": [Color(1, 1, 1, 0), Color(1, 1, 1, 1)] +} +tracks/1/type = "value" +tracks/1/imported = false +tracks/1/enabled = true +tracks/1/path = NodePath("../../PauseMenu/PauseBackground/VBoxContainer:modulate") +tracks/1/interp = 1 +tracks/1/loop_wrap = true +tracks/1/keys = { +"times": PackedFloat32Array(0.233333, 0.433333), +"transitions": PackedFloat32Array(1, 1), +"update": 0, +"values": [Color(1, 1, 1, 0), Color(1, 1, 1, 1)] +} +tracks/2/type = "value" +tracks/2/imported = false +tracks/2/enabled = true +tracks/2/path = NodePath("../../PauseMenu/PauseBackground:modulate") +tracks/2/interp = 1 +tracks/2/loop_wrap = true +tracks/2/keys = { +"times": PackedFloat32Array(0, 0.3), +"transitions": PackedFloat32Array(1, 1), +"update": 0, +"values": [Color(1, 1, 1, 0), Color(1, 1, 1, 1)] +} +tracks/3/type = "value" +tracks/3/imported = false +tracks/3/enabled = true +tracks/3/path = NodePath("%PauseMenu:visible") +tracks/3/interp = 1 +tracks/3/loop_wrap = true +tracks/3/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 1, +"values": [true] +} +tracks/4/type = "value" +tracks/4/imported = false +tracks/4/enabled = true +tracks/4/path = NodePath("%PauseMenu:modulate") +tracks/4/interp = 1 +tracks/4/loop_wrap = true +tracks/4/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [Color(1, 1, 1, 1)] +} + +[sub_resource type="AnimationLibrary" id="AnimationLibrary_dxvjq"] +_data = { +&"RESET": SubResource("Animation_y6s08"), +&"credits_roll": SubResource("Animation_sfr6l"), +&"hide_pause_menu": SubResource("Animation_lh4gu"), +&"init": SubResource("Animation_l5ynk"), +&"reveal_pause_menu": SubResource("Animation_s5m6i") +} + +[sub_resource type="Animation" id="Animation_fo06q"] +resource_name = "RESET" +length = 0.001 +tracks/0/type = "value" +tracks/0/imported = false +tracks/0/enabled = true +tracks/0/path = NodePath(".:modulate") +tracks/0/interp = 1 +tracks/0/loop_wrap = true +tracks/0/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [Color(1, 1, 1, 0)] +} +tracks/1/type = "value" +tracks/1/imported = false +tracks/1/enabled = true +tracks/1/path = NodePath(".:rotation") +tracks/1/interp = 1 +tracks/1/loop_wrap = true +tracks/1/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [1.5708] +} +tracks/2/type = "value" +tracks/2/imported = false +tracks/2/enabled = true +tracks/2/path = NodePath("frame/deco:rotation") +tracks/2/interp = 1 +tracks/2/loop_wrap = true +tracks/2/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [-0.314159] +} +tracks/3/type = "value" +tracks/3/imported = false +tracks/3/enabled = true +tracks/3/path = NodePath("frame/deco:modulate") +tracks/3/interp = 1 +tracks/3/loop_wrap = true +tracks/3/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [Color(1, 1, 1, 0)] +} +tracks/4/type = "value" +tracks/4/imported = false +tracks/4/enabled = true +tracks/4/path = NodePath("../LoadingLabel:visible") +tracks/4/interp = 1 +tracks/4/loop_wrap = true +tracks/4/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 1, +"values": [false] +} +tracks/5/type = "value" +tracks/5/imported = false +tracks/5/enabled = true +tracks/5/path = NodePath("../LoadingLabel:modulate") +tracks/5/interp = 1 +tracks/5/loop_wrap = true +tracks/5/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [Color(1, 1, 1, 1)] +} +tracks/6/type = "value" +tracks/6/imported = false +tracks/6/enabled = true +tracks/6/path = NodePath("../LoadingLabel:position") +tracks/6/interp = 1 +tracks/6/loop_wrap = true +tracks/6/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [Vector2(100, -37)] +} + +[sub_resource type="Animation" id="Animation_p5e7r"] +resource_name = "loading_done" +length = 1.5 +tracks/0/type = "value" +tracks/0/imported = false +tracks/0/enabled = true +tracks/0/path = NodePath(".:rotation") +tracks/0/interp = 1 +tracks/0/loop_wrap = true +tracks/0/keys = { +"times": PackedFloat32Array(0, 1.4), +"transitions": PackedFloat32Array(2.2974, 1), +"update": 0, +"values": [0.261799, -1.5708] +} +tracks/1/type = "value" +tracks/1/imported = false +tracks/1/enabled = true +tracks/1/path = NodePath("frame/deco:rotation") +tracks/1/interp = 1 +tracks/1/loop_wrap = true +tracks/1/keys = { +"times": PackedFloat32Array(0, 1.4), +"transitions": PackedFloat32Array(2.2974, 1), +"update": 0, +"values": [-0.261799, 1.5708] +} +tracks/2/type = "value" +tracks/2/imported = false +tracks/2/enabled = true +tracks/2/path = NodePath(".:modulate") +tracks/2/interp = 1 +tracks/2/loop_wrap = true +tracks/2/keys = { +"times": PackedFloat32Array(0.933333, 1.36667), +"transitions": PackedFloat32Array(1, 1), +"update": 0, +"values": [Color(1, 1, 1, 1), Color(1, 1, 1, 0)] +} +tracks/3/type = "value" +tracks/3/imported = false +tracks/3/enabled = true +tracks/3/path = NodePath("../LoadingLabel:visible") +tracks/3/interp = 1 +tracks/3/loop_wrap = true +tracks/3/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 1, +"values": [true] +} +tracks/4/type = "value" +tracks/4/imported = false +tracks/4/enabled = true +tracks/4/path = NodePath("../LoadingLabel:modulate") +tracks/4/interp = 1 +tracks/4/loop_wrap = true +tracks/4/keys = { +"times": PackedFloat32Array(1.1666666, 1.5), +"transitions": PackedFloat32Array(1, 1), +"update": 0, +"values": [Color(1, 1, 1, 1), Color(1, 1, 1, 0)] +} +tracks/5/type = "value" +tracks/5/imported = false +tracks/5/enabled = true +tracks/5/path = NodePath("../LoadingLabel:position") +tracks/5/interp = 1 +tracks/5/loop_wrap = true +tracks/5/keys = { +"times": PackedFloat32Array(0.93333334, 1.5), +"transitions": PackedFloat32Array(1.6788809, 1), +"update": 0, +"values": [Vector2(170, -37), Vector2(100, -37)] +} + +[sub_resource type="Animation" id="Animation_man8y"] +resource_name = "loading_idle" +length = 2.0 +loop_mode = 1 +tracks/0/type = "value" +tracks/0/imported = false +tracks/0/enabled = true +tracks/0/path = NodePath(".:modulate") +tracks/0/interp = 1 +tracks/0/loop_wrap = true +tracks/0/keys = { +"times": PackedFloat32Array(0, 0.166667, 1.76667), +"transitions": PackedFloat32Array(1, 1, 1), +"update": 0, +"values": [Color(1, 1, 1, 0), Color(1, 1, 1, 1), Color(1, 1, 1, 1)] +} +tracks/1/type = "value" +tracks/1/imported = false +tracks/1/enabled = true +tracks/1/path = NodePath(".:rotation") +tracks/1/interp = 1 +tracks/1/loop_wrap = true +tracks/1/keys = { +"times": PackedFloat32Array(0.0333333, 1.76667, 2), +"transitions": PackedFloat32Array(0.406126, 1, 1), +"update": 0, +"values": [1.5708, 0.261799, 0.0] +} +tracks/2/type = "value" +tracks/2/imported = false +tracks/2/enabled = true +tracks/2/path = NodePath("frame/deco:rotation") +tracks/2/interp = 1 +tracks/2/loop_wrap = true +tracks/2/keys = { +"times": PackedFloat32Array(0.0333368, 1.76667, 2), +"transitions": PackedFloat32Array(0.406126, 1, 1), +"update": 0, +"values": [-1.5708, -0.261799, 0.0] +} +tracks/3/type = "value" +tracks/3/imported = false +tracks/3/enabled = true +tracks/3/path = NodePath("frame/deco:modulate") +tracks/3/interp = 1 +tracks/3/loop_wrap = true +tracks/3/keys = { +"times": PackedFloat32Array(0, 0.366667, 1.66667), +"transitions": PackedFloat32Array(1, 1, 1), +"update": 0, +"values": [Color(1, 1, 1, 0), Color(1, 1, 1, 0), Color(1, 1, 1, 1)] +} +tracks/4/type = "value" +tracks/4/imported = false +tracks/4/enabled = true +tracks/4/path = NodePath("../LoadingLabel:visible") +tracks/4/interp = 1 +tracks/4/loop_wrap = true +tracks/4/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 1, +"values": [true] +} +tracks/5/type = "value" +tracks/5/imported = false +tracks/5/enabled = true +tracks/5/path = NodePath("../LoadingLabel:modulate") +tracks/5/interp = 1 +tracks/5/loop_wrap = true +tracks/5/keys = { +"times": PackedFloat32Array(0.06666672, 1.1666666), +"transitions": PackedFloat32Array(1, 1), +"update": 0, +"values": [Color(1, 1, 1, 0), Color(1, 1, 1, 1)] +} +tracks/6/type = "value" +tracks/6/imported = false +tracks/6/enabled = true +tracks/6/path = NodePath("../LoadingLabel:position") +tracks/6/interp = 1 +tracks/6/loop_wrap = true +tracks/6/keys = { +"times": PackedFloat32Array(0.93333334), +"transitions": PackedFloat32Array(1.6788809), +"update": 0, +"values": [Vector2(170, -37)] +} + +[sub_resource type="AnimationLibrary" id="AnimationLibrary_jqvqy"] +_data = { +&"RESET": SubResource("Animation_fo06q"), +&"loading_done": SubResource("Animation_p5e7r"), +&"loading_idle": SubResource("Animation_man8y") +} + +[sub_resource type="GDScript" id="GDScript_fo06q"] +script/source = "extends TextureRect + + +func _ready() -> void: + pass +" + +[node name="main" type="Control" unique_id=1939617648] process_mode = 3 z_index = 110 z_as_relative = false @@ -99,137 +932,193 @@ youth_room_path = "uid://b3b0gyvklqn50" transition_room_path = "uid://fgp3tbah7msy" adulthood_room_path = "uid://flisupth27th" -[node name="Stage" type="Node" parent="."] +[node name="Stage" type="Node" parent="." unique_id=142574116] unique_name_in_owner = true +process_mode = 1 -[node name="Curtain" parent="." instance=ExtResource("2_nbcxq")] -unique_name_in_owner = true -z_index = -1 -layout_mode = 1 - -[node name="Loading" parent="." instance=ExtResource("5_dxvjq")] -unique_name_in_owner = true -layout_mode = 1 -offset_bottom = 0.0 - -[node name="MainMenu" parent="." instance=ExtResource("3_ik73t")] +[node name="Curtain" type="Panel" parent="." unique_id=497418172] unique_name_in_owner = true visible = false +modulate = Color(0, 0, 0, 1) +z_index = -1 +layout_mode = 1 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +mouse_filter = 2 +script = ExtResource("2_fo06q") + +[node name="MainMenu" parent="." unique_id=28661943 instance=ExtResource("3_ik73t")] +unique_name_in_owner = true z_index = 10 layout_mode = 1 -[node name="FPSLabel" type="Label" parent="."] +[node name="FPSLabel" type="Label" parent="." unique_id=1905493725] visible = false layout_mode = 0 offset_right = 40.0 offset_bottom = 35.0 script = SubResource("GDScript_8sq0u") -[node name="Startup Menu" parent="." instance=ExtResource("1_v5rpm")] +[node name="Startup Menu" parent="." unique_id=2061007289 instance=ExtResource("1_v5rpm")] visible = false layout_mode = 1 -[node name="Disclaimer" parent="." instance=ExtResource("7_t45fc")] +[node name="Disclaimer" parent="." unique_id=582854161 instance=ExtResource("7_t45fc")] visible = false layout_mode = 1 -[node name="CreditsRoll" parent="." instance=ExtResource("11_wtpde")] +[node name="PauseMenu" type="CenterContainer" parent="." unique_id=605493864] unique_name_in_owner = true visible = false -modulate = Color(1, 1, 1, 0) -layout_mode = 1 - -[node name="PauseMenu" type="Panel" parent="."] -unique_name_in_owner = true -process_mode = 2 -visible = false -z_index = 125 layout_mode = 1 anchors_preset = 15 anchor_right = 1.0 anchor_bottom = 1.0 +offset_left = -64.0 +offset_top = -484.0 +offset_right = 64.0 +offset_bottom = 484.0 grow_horizontal = 2 grow_vertical = 2 -focus_mode = 2 script = ExtResource("9_ihfph") -[node name="TextureRect" type="TextureRect" parent="PauseMenu"] +[node name="TextureRect" type="TextureRect" parent="PauseMenu" unique_id=1213851146] material = SubResource("ShaderMaterial_knlqd") -layout_mode = 1 -anchors_preset = 15 -anchor_right = 1.0 -anchor_bottom = 1.0 -grow_horizontal = 2 -grow_vertical = 2 +custom_minimum_size = Vector2(2048, 2048) +layout_mode = 2 texture = SubResource("GradientTexture2D_swtmc") expand_mode = 5 -[node name="PauseContainer" type="CenterContainer" parent="PauseMenu"] -layout_mode = 1 -anchors_preset = 15 -anchor_right = 1.0 -anchor_bottom = 1.0 -grow_horizontal = 2 -grow_vertical = 2 - -[node name="VBoxContainer" type="VBoxContainer" parent="PauseMenu/PauseContainer"] -unique_name_in_owner = true +[node name="PauseBackground" type="PanelContainer" parent="PauseMenu" unique_id=1224860062] layout_mode = 2 -[node name="Label" type="Label" parent="PauseMenu/PauseContainer/VBoxContainer"] +[node name="VBoxContainer" type="VBoxContainer" parent="PauseMenu/PauseBackground" unique_id=122278313] +unique_name_in_owner = true +modulate = Color(1, 1, 1, 0) +layout_mode = 2 + +[node name="Label" type="Label" parent="PauseMenu/PauseBackground/VBoxContainer" unique_id=2124020849] layout_mode = 2 theme_type_variation = &"HeaderLarge" text = "Game Paused" -[node name="ResumeButton" type="Button" parent="PauseMenu/PauseContainer/VBoxContainer"] +[node name="ResumeButton" type="Button" parent="PauseMenu/PauseBackground/VBoxContainer" unique_id=887325002] unique_name_in_owner = true layout_mode = 2 text = "Resume" -[node name="BugButton" type="Button" parent="PauseMenu/PauseContainer/VBoxContainer"] +[node name="BugButton" type="Button" parent="PauseMenu/PauseBackground/VBoxContainer" unique_id=2030807015] layout_mode = 2 text = "Bug Report" script = ExtResource("12_cegan") metadata/_custom_type_script = "uid://sa15wakvpj2e" -[node name="ToMenuButton" type="Button" parent="PauseMenu/PauseContainer/VBoxContainer"] +[node name="ToMenuButton" type="Button" parent="PauseMenu/PauseBackground/VBoxContainer" unique_id=1865380141] unique_name_in_owner = true visible = false layout_mode = 2 text = "Return to Menu" -[node name="ToSettingsButton" type="Button" parent="PauseMenu/PauseContainer/VBoxContainer"] +[node name="ToSettingsButton" type="Button" parent="PauseMenu/PauseBackground/VBoxContainer" unique_id=539752754] unique_name_in_owner = true visible = false layout_mode = 2 text = "Open Settings" -[node name="ToDesktopButton" type="Button" parent="PauseMenu/PauseContainer/VBoxContainer"] +[node name="ToDesktopButton" type="Button" parent="PauseMenu/PauseBackground/VBoxContainer" unique_id=2096410515] unique_name_in_owner = true layout_mode = 2 text = "Quit to Desktop" -[node name="HSeparator" type="HSeparator" parent="PauseMenu/PauseContainer/VBoxContainer"] +[node name="HSeparator" type="HSeparator" parent="PauseMenu/PauseBackground/VBoxContainer" unique_id=875019345] custom_minimum_size = Vector2(0, 20) layout_mode = 2 -[node name="FindHelplineButton" type="Button" parent="PauseMenu/PauseContainer/VBoxContainer"] +[node name="FindHelplineButton" type="Button" parent="PauseMenu/PauseBackground/VBoxContainer" unique_id=944318011] unique_name_in_owner = true layout_mode = 2 text = "Find Help-Lines" -[node name="Label2" type="Label" parent="PauseMenu/PauseContainer/VBoxContainer"] +[node name="Label2" type="Label" parent="PauseMenu/PauseBackground/VBoxContainer" unique_id=887687356] layout_mode = 2 text = "opens findahelpline.com" horizontal_alignment = 1 -[node name="SkipStoryButton" type="Button" parent="PauseMenu/PauseContainer/VBoxContainer"] +[node name="SkipStoryButton" type="Button" parent="PauseMenu/PauseBackground/VBoxContainer" unique_id=288933053] unique_name_in_owner = true visible = false layout_mode = 2 text = "Skip this Story" -[node name="AudioStreamPlayer" type="AudioStreamPlayer" parent="."] +[node name="CreditsRoll" parent="." unique_id=1216295988 instance=ExtResource("11_wtpde")] +unique_name_in_owner = true +visible = false +modulate = Color(1, 1, 1, 0) +layout_mode = 1 +offset_top = 220.0 +offset_bottom = 220.0 + +[node name="AudioStreamPlayer" type="AudioStreamPlayer" parent="." unique_id=1830046294] bus = &"music" +[node name="Control" type="Control" parent="." unique_id=1277696119] +layout_mode = 1 +anchors_preset = 2 +anchor_top = 1.0 +anchor_bottom = 1.0 +offset_top = -40.0 +offset_right = 40.0 +grow_vertical = 0 + +[node name="mask" type="Sprite2D" parent="Control" unique_id=624649824] +modulate = Color(1, 1, 1, 0) +clip_children = 1 +position = Vector2(98, -47) +rotation = 1.5708 +texture = ExtResource("10_4r37y") + +[node name="frame" type="Sprite2D" parent="Control/mask" unique_id=529937105] +clip_children = 1 +texture = ExtResource("11_fo06q") + +[node name="deco" type="Sprite2D" parent="Control/mask/frame" unique_id=2090757901] +modulate = Color(1, 1, 1, 0) +rotation = -0.314159 +texture = ExtResource("12_p5e7r") + +[node name="LoadingLabel" type="Label" parent="Control" unique_id=1654101457] +visible = false +layout_mode = 0 +offset_left = 100.0 +offset_top = -37.0 +offset_right = 239.9986 +offset_bottom = 9.0 +text = "loading" +script = SubResource("GDScript_jqvqy") + +[node name="LoadAnimation" type="AnimationPlayer" parent="Control" unique_id=1882379663] +unique_name_in_owner = true +root_node = NodePath("../mask") +libraries/ = SubResource("AnimationLibrary_dxvjq") +libraries/LoadAnimation = SubResource("AnimationLibrary_jqvqy") +autoplay = &"LoadAnimation/RESET" + +[node name="MenuAnimationPlayer" type="AnimationPlayer" parent="." unique_id=1521789934] +unique_name_in_owner = true +root_node = NodePath("../Control/mask") +libraries/ = SubResource("AnimationLibrary_dxvjq") +autoplay = &"init" + +[node name="AudioStreamPlayer" type="AudioStreamPlayer" parent="MenuAnimationPlayer" unique_id=1687297359] +bus = &"music" + +[node name="TextureRect" type="TextureRect" parent="." unique_id=1174916127] +layout_mode = 0 +offset_right = 40.0 +offset_bottom = 40.0 +script = SubResource("GDScript_fo06q") + [connection signal="on_read" from="Disclaimer" to="Startup Menu" method="starting"] diff --git a/src/ui/curtain/curtain.gd b/src/ui/curtain/curtain.gd index 17fbe7b1..4b3cd05b 100644 --- a/src/ui/curtain/curtain.gd +++ b/src/ui/curtain/curtain.gd @@ -6,34 +6,62 @@ var _tween : Tween = null func _ready() -> void: print("curtain.gd: ready()") visible = true - _check_boot.call_deferred() + _check_boot() func _check_boot(): self.visible = Main.normal_boot + if visible: + self.modulate = Color.BLACK + _tween_with_interrupt(Color.WHITE, 1.0, true) ## Conceals the Game Stage -func close() -> void: - visible = true - print("curtain.gd: show()") - if _tween: _tween.kill() - _tween = create_tween() - _tween.tween_property(self, "modulate", Color.WHITE, 0.7) - await _tween.finished +func close() -> bool: + if visible and modulate == Color.WHITE: + return true + if await blackout(): + return await _tween_with_interrupt(Color.WHITE, 0.7, true) + return false ## Conceals the Game Stage -func black() -> void: +func blackout() -> bool: + if visible and modulate == Color.BLACK: + return true visible = true print("curtain.gd: show()") - if _tween: _tween.kill() - _tween = create_tween() - _tween.tween_property(self, "modulate", Color.BLACK, 0.7) - await _tween.finished + return await _tween_with_interrupt(Color.BLACK, 0.2, true) ## Makes the Game Stage Visible -func open() -> void: +func open() -> bool: + if not visible: + return true print("curtain.gd: hide()") - if _tween: _tween.kill() + if not visible: return true + var no_interrupt = await _tween_with_interrupt(Color.TRANSPARENT, 0.2, false) + if no_interrupt: + visible = false + return true + else: + return false + +signal _tween_finished(successful: bool) +var _target_visibility: bool = false +## This allows multiple places to call the curtain close to each other with the only interference caused by mismatched visibility requirements. +func _tween_with_interrupt(to_color: Color, for_duration: float, target_visible: bool) -> bool: + if _tween: + if target_visible and _target_visibility: + return await _tween_finished + else: + _tween.kill() + _tween = create_tween() - _tween.tween_property(self, "modulate", Color.TRANSPARENT, 0.7) - await _tween.finished - visible = false + _tween.tween_property(self, "modulate", to_color, for_duration) + while true: + if _tween.is_valid(): + if not _tween.is_running(): + _tween_finished.emit(true) + return true + await get_tree().process_frame + else: + _tween_finished.emit(false) + return false + return false