diff --git a/src/base-environments/youth_room/room_handle.gd b/src/base-environments/youth_room/room_handle.gd index 4efb9af..9adff7e 100644 --- a/src/base-environments/youth_room/room_handle.gd +++ b/src/base-environments/youth_room/room_handle.gd @@ -2,10 +2,6 @@ extends RoomTemplate signal ini_room -@onready var mask_memento: CollectableUi = %MaskMemento.ui -@onready var clothes_memento: CollectableUi = %ClothesMemento.ui -@onready var comic_memento: CollectableUi = %ComicMemento.ui -@onready var ceiling_memento: CollectableUi = %CeilingMemento.ui @onready var board_trigger: InteractiveSprite = %MindBoard @onready var door_trigger: InteractiveSprite = %DoorTrigger @onready var card_board: CardBoard = %Board @@ -13,25 +9,26 @@ signal ini_room func start_room(): save_game = State.active_save_game - ##TODO: make sure this is done automagically! - # Setting Memento user interface elemnts as collected based on the savegame. - #mask_memento.collected = save_game.mementos_complete && 1 >> Scenes.id.YOUTH_CHILDHOOD > 0 - #clothes_memento.collected = save_game.mementos_complete && 1 >> Scenes.id.YOUTH_JUI_JUTSU > 0 - #comic_memento.collected = save_game.mementos_complete && 1 >> Scenes.id.YOUTH_VOICE_TRAINING > 0 - #ceiling_memento.collected = save_game.mementos_complete && 1 >> Scenes.id.YOUTH_DRAEVEN > 0 - + save_game.current_room = State.rooms.YOUTH + Scenes.completed_sequences = save_game.mementos_complete + Scenes.started_sequences = save_game.mementos_complete + card_board.initialise_from_save(save_game) $logic/PlayerController.process_mode = Node.PROCESS_MODE_INHERIT ini_room.emit() - Scenes.start_sequence(Scenes.id.YOUTH_DRAEVEN) - State.queue_for_stage(%PlayerController) + if not Scenes.is_sequence_repeating(Scenes.id.YOUTH_DRAEVEN): + Scenes.start_sequence(Scenes.id.YOUTH_DRAEVEN) + State.queue_for_stage(%PlayerController) + else: + State.pass_stage_to(%PlayerController) + %LightAnimation.lights_on() func get_ready(): - self.show() - $sfx/distant_rain.play() - $"sfx/rain on window".play() - await get_tree().create_timer(0.1).timeout - $logic/UI/board.hide() + self.show() + $sfx/distant_rain.play() + $"sfx/rain on window".play() + await get_tree().create_timer(0.1).timeout + $logic/UI/board.hide() func _ready(): Scenes.scene_finished.connect(_on_scene_finished) @@ -43,11 +40,11 @@ func _ready(): func pull_save_state(save: SaveGame) -> void: save.board_state = card_board.get_save_dict() + save.current_room = State.rooms.YOUTH + save.mementos_complete = Scenes.completed_sequences func _on_scene_finished(id: int, _repeat:bool): - # need to properly implement saving and loading - return - save_game.mementos_complete &= 1 << id + await get_tree().create_timer(3).timeout save_room() #FIXME forgot to comment what this means, just marking it for removal diff --git a/src/base-environments/youth_room/youth_room.tscn b/src/base-environments/youth_room/youth_room.tscn index a6f192a..67d5525 100644 --- a/src/base-environments/youth_room/youth_room.tscn +++ b/src/base-environments/youth_room/youth_room.tscn @@ -1201,10 +1201,10 @@ func _ready() -> void: Scenes.scene_finished.connect(lights_on) Scenes.scene_starting.connect(lights_off) -func lights_off(_id: int, _repeat: bool): +func lights_off(_id: int = -1, _repeat: bool = false): queue(\"lights_out\") -func lights_on(_id: int, _repeat: bool): +func lights_on(_id: int = -1, _repeat: bool = false): queue(\"light_up\") " @@ -1420,6 +1420,7 @@ script = ExtResource("1_aitp0") [node name="PlayerController" parent="logic" groups=["camera_owner"] instance=ExtResource("3_foj4y")] unique_name_in_owner = true +process_mode = 4 transform = Transform3D(0.686123, 0, 0.727485, 0, 1, 0, -0.727485, 0, 0.686123, 0.63, 0, 0.925) [node name="colission" type="Node3D" parent="logic"] @@ -2088,7 +2089,8 @@ shadow_enabled = true omni_range = 2.17653 omni_attenuation = 1.41421 -[node name="light_animation" type="AnimationPlayer" parent="visuals/lights" groups=["scene_actors"]] +[node name="LightAnimation" type="AnimationPlayer" parent="visuals/lights" groups=["scene_actors"]] +unique_name_in_owner = true libraries = { &"": SubResource("AnimationLibrary_k8op5") } @@ -2246,7 +2248,7 @@ light_array = Array[Vector3]([Vector3(-0.545, 0.915, 1.035), Vector3(-0.47, 0.85 [connection signal="ini_room" from="." to="logic/PlayerController" method="_on_ini_room"] [connection signal="ini_room" from="." to="logic/ScenePlayer" method="_on_ini_room"] -[connection signal="ini_room" from="." to="visuals/lights/light_animation" method="_on_ini_room"] +[connection signal="ini_room" from="." to="visuals/lights/LightAnimation" method="_on_ini_room"] [connection signal="ui_entered" from="logic/PlayerController" to="SceneUI" method="show"] [connection signal="ui_exited" from="logic/PlayerController" to="SceneUI" method="hide"] [connection signal="body_entered" from="logic/Bed and Ladders/ladder_trigger" to="logic/PlayerController" method="_on_bed_enter"] diff --git a/src/dev-util/room_template.gd b/src/dev-util/room_template.gd index af23927..a799bee 100644 --- a/src/dev-util/room_template.gd +++ b/src/dev-util/room_template.gd @@ -19,4 +19,4 @@ func pull_save_state(save: SaveGame) -> void: func save_room(): pull_save_state(save_game) - save_game.save_to_file.call_deferred(get_tree().root.get_texture()) + save_game.save_to_file(get_tree().root.get_texture()) diff --git a/src/dev-util/savegame.gd b/src/dev-util/savegame.gd index 97c3f6b..9ce2ea5 100644 --- a/src/dev-util/savegame.gd +++ b/src/dev-util/savegame.gd @@ -1,58 +1,111 @@ @tool class_name SaveGame extends Resource -@export var filepath: String -@export var unique_save_name: String = "frame_of_mind_%s_%s" % [Time.get_date_string_from_system(), Time.get_time_string_from_system()] -@export var current_room: State.rooms = State.rooms.YOUTH -@export var mementos_complete: int = 0 -@export var board_state: Dictionary = {} -@export var thumbnail: Texture = preload("res://import/interface-elements/empty_save_slot.png") -@export var last_saved: int = int(Time.get_unix_time_from_system()) +var _is_initialised: bool = false -@export var is_save_file_valid: bool = false +@export var filepath: String: + set(value): + filepath = value + if _is_initialised: + read_save_file() + changed.emit() +@export var unique_save_name: String = "frame_of_mind_%s_%s" % [Time.get_date_string_from_system(), Time.get_time_string_from_system().replace(":", "-")]: + set(value): + unique_save_name = value + if _is_initialised: changed.emit() +@export var current_room: State.rooms = State.rooms.NULL: + set(value): + current_room = value + if _is_initialised: changed.emit() +@export_flags("Intro", "Childhood", "Voice Training", "Jui Jutsu") var mementos_complete: int = 0: + set(value): + mementos_complete = value + if _is_initialised: changed.emit() +@export var board_state: Dictionary = {"cards": {}, "stickies": {}}: + set(value): + board_state = value + if _is_initialised: changed.emit() +@export var thumbnail: Texture = preload("res://import/interface-elements/empty_save_slot.png"): + set(value): + thumbnail = value + if _is_initialised: changed.emit() +@export var last_saved: int = int(Time.get_unix_time_from_system()): + set(value): + last_saved = value + if _is_initialised: changed.emit() +@export var is_valid: bool = false +@export var is_empty: bool = true: + get(): + return not FileAccess.file_exists("%s.json:" % filepath) +@export var save_manually: bool = false: + set(val): + if val: save_to_file(thumbnail) + func _validate_property(property: Dictionary): + if property.name == filepath: + property.usage |= PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED if property.name == "thumbnail": - property.usage = not PROPERTY_USAGE_STORAGE - + property.usage |= PROPERTY_USAGE_READ_ONLY + if property.name == "is_valid": + property.usage |= PROPERTY_USAGE_READ_ONLY + if property.name == "is_empty": + property.usage |= PROPERTY_USAGE_READ_ONLY func _init(initial_filepath = "") -> void: - if initial_filepath == "": filepath = "%s/%s" % [State.user_saves_path, unique_save_name] else: filepath = initial_filepath + unique_save_name = initial_filepath.get_file() read_save_file() + _is_initialised = true func read_save_file(): - - if FileAccess.file_exists("%s.json:" % filepath): - - - var file = FileAccess.open("%s.json:" % filepath, FileAccess.READ) - var raw_json = FileAccess.get_file_as_string("%s.json:" % filepath) + print("Opening Savegame: %s.json" % filepath) + + if FileAccess.file_exists("%s.json" % filepath): + var file = FileAccess.open("%s.json" % filepath, FileAccess.READ) + var raw_json = FileAccess.get_file_as_string("%s.json" % filepath) file.close() var parsed: Dictionary = JSON.parse_string(raw_json) var tmp_img: Image - if FileAccess.file_exists("%s/thumbnails/%s.png" % [State.user_saves_path, filepath]): - tmp_img = Image.load_from_file("%s/thumbnails/%s.png" % [State.user_saves_path, filepath]) + + if FileAccess.file_exists("%s/thumbnails/%s.png" % [filepath.get_base_dir(), unique_save_name]): + tmp_img = Image.load_from_file("%s/thumbnails/%s.png" % [filepath.get_base_dir(), unique_save_name]) - is_save_file_valid = ( + var are_types_valid = ( parsed["unique_save_name"] is String and - parsed["current_room"] is int and - parsed["mementos_complete"] is int and - parsed["coard_state"] is Dictionary and - parsed["last_saved"] is float and last_saved != 0 and - parsed["tmp_img"] is Image + parsed["current_room"] is float and + parsed["mementos_complete"] is float and + parsed["board_state"] is Dictionary and + parsed["last_saved"] is float and last_saved != 0 ) - if is_save_file_valid: + if are_types_valid: for key in parsed.keys(): set(key, parsed[key]) + for dict:Dictionary in board_state.values(): + for key in dict.keys(): + if dict[key] is String: + if dict[key].begins_with("("): + dict[key] = parse_vec_from_string(dict[key]) + + is_valid = are_types_valid \ + and current_room >= 0 \ + and current_room < State.rooms.keys().size() \ + and validate_board_state() + + if not is_valid: + push_error("Parsing of Save failed.") + if tmp_img != null: thumbnail = ImageTexture.create_from_image(tmp_img) + is_empty = false + else: + is_valid = true func _get_save_dict() -> Dictionary: return { @@ -64,13 +117,54 @@ func _get_save_dict() -> Dictionary: } func save_to_file(current_screen: Texture): - return last_saved = Time.get_unix_time_from_system() var thumbnail_image: Image = current_screen.get_image() thumbnail_image.resize(384, 261, Image.INTERPOLATE_LANCZOS) # nonexistent call in ViewportTexturew - thumbnail_image.save_png("%s/thumbnails/%s.png" % [State.user_saves_path, filepath]) + var thumbnail_path: String = "%s/thumbnails/%s.png" % [filepath.get_base_dir(), unique_save_name] + var save_dir = DirAccess.open(filepath.get_base_dir()) + if not save_dir.dir_exists("thumbnails"): + save_dir.make_dir("thumbnails") - var file = FileAccess.open("%s.json:" % filepath, FileAccess.WRITE) + thumbnail_image.save_png("%s/thumbnails/%s.png" % [filepath.get_base_dir(), unique_save_name]) + #thumbnail_image.save_png("%s/test.png" % State.user_saves_path) + print(filepath.get_base_dir()) + var file = FileAccess.open("%s.json" % filepath, FileAccess.WRITE) file.store_string(JSON.stringify(_get_save_dict())) + file.close() + + +func calculate_completed_sequences() -> int: + var i: int = mementos_complete - ((mementos_complete >> 1) & 0x55555555); + i = (i & 0x33333333) + ((i >> 2) & 0x33333333); + i = (i + (i >> 4)) & 0x0F0F0F0F; + i *= 0x01010101; + return i >> 24; + +func calculate_total_connections() -> int: + var connections:= 0 + + for sticky_position in board_state.stickies.values(): + connections += int(sticky_position is String) + + return connections + +func validate_board_state() -> bool: + if board_state.keys().has("cards") and board_state.keys().has("stickies"): + for card in board_state.cards.values(): + if not card is Vector2: + push_error("Save %s could not be parsed: Corrupted Cards." % unique_save_name) + return false + for sticky in board_state.stickies.values(): + if not (sticky == -1 or sticky is Vector2 or board_state.cards.keys.has(sticky)): + push_error("Save %s could not be parsed: Corrupted Sticky Notes.") + return false + + return true + + return false + +func parse_vec_from_string(string: String) -> Vector2: + var string_array = string.replace("(", "").replace(")", "").split(", ") + return Vector2(float(string_array[0]), float(string_array[1])) diff --git a/src/logic-scenes/board/card-board.gd b/src/logic-scenes/board/card-board.gd index 1a07d71..63d6c55 100644 --- a/src/logic-scenes/board/card-board.gd +++ b/src/logic-scenes/board/card-board.gd @@ -128,6 +128,8 @@ func _ready(): has_stage = has_stage get_viewport().gui_focus_changed.connect(reclaim_lost_focus) + + print(get_save_dict()) func reclaim_lost_focus(): @@ -396,19 +398,25 @@ func get_save_dict() -> Dictionary: for child in dropzone.get_children(): if child is Card: - if child.has_sticky_note_attached(): - stickies[child.get_attached_sticky_note().name] = child.name + # Save position of Card. cards[child.name] = child.transform.origin + + if child.has_sticky_note_attached(): + # Saves Card Name as position of it's children. + stickies[child.get_attached_sticky_note().name] = child.name + elif child is StickyNote: + # Save position of StickyNote. cards[child.name] = child.transform.origin for child in sticky_note_container.get_children(): if child is StickyNotePanel: + # Saves all collected Stickies that are not on board. stickies[child.attached_sticky_note.name] = -1 return { "cards": cards, "stickies": stickies - } if cards != {} and stickies != {} else {} + } func initialise_from_save(savegame: SaveGame): if savegame.board_state == {}: return @@ -419,12 +427,13 @@ func initialise_from_save(savegame: SaveGame): for card:Card in card_pile["cards"]: add_card(card) - card.transform.origin = cards[card.name] + card.transform.origin = cards[card.name] # Replacing position reference with card reference! Needed in next loop. cards[card.name] = card + for sticky:StickyNote in card_pile["sticky_notes"]: - if stickies[sticky.name] == -1: + if stickies[sticky.name] == -1.0: add_sticky_note(sticky) - if stickies[sticky.name] is String: + elif stickies[sticky.name] is String: cards[stickies[sticky.name]].attach_sticky_note(sticky) else: insert_area(dropzone, sticky) diff --git a/src/logic-scenes/main menu/main_menu.gd b/src/logic-scenes/main menu/main_menu.gd index c16104e..fb0e689 100644 --- a/src/logic-scenes/main menu/main_menu.gd +++ b/src/logic-scenes/main menu/main_menu.gd @@ -6,8 +6,8 @@ var has_stage: bool = false: if is_node_ready(): if has_stage: new_game_button.grab_focus() new_game_button.disabled = not has_stage - continue_button.disabled = not has_stage - load_game_button.disabled = not has_stage + continue_button.disabled = not has_stage or save_game_handle.get_most_recent_save().current_room == 0 + load_game_button.disabled = not has_stage or not save_game_handle.has_existing_saves() settings_button.disabled = not has_stage credits_button.disabled = not has_stage quit_button.disabled = not has_stage @@ -31,14 +31,14 @@ signal roll_credits var await_new_game: bool = false - # Called when the node enters the scene tree for the first time. func _ready() -> void: save_game_handle.picked.connect(_on_save_picked) - continue_button.visible = save_game_handle.get_most_recent_save().current_room != 0 + continue_button.disabled = save_game_handle.get_most_recent_save().current_room == 0 continue_button.pressed.connect(func(): start_game.emit(save_game_handle.get_most_recent_save())) new_game_button.pressed.connect(func(): save_game_handle.pick_save_slot(true)) load_game_button.pressed.connect(func(): save_game_handle.pick_save_slot(false)) + load_game_button.disabled = not save_game_handle.has_existing_saves() settings_button.get_popup().index_pressed.connect(settings_popup.show_settings) quit_button.pressed.connect(get_tree().quit) diff --git a/src/logic-scenes/main menu/save_game_display.gd b/src/logic-scenes/main menu/save_game_display.gd index 538e9ef..97185ba 100644 --- a/src/logic-scenes/main menu/save_game_display.gd +++ b/src/logic-scenes/main menu/save_game_display.gd @@ -1,82 +1,119 @@ +@tool class_name SaveGameDisplay extends Button -func _init(save: SaveGame, id: int) -> void: - var base_container:= HBoxContainer.new() - base_container.alignment = BoxContainer.ALIGNMENT_CENTER - add_child(base_container) +var _is_built: bool = false + +@export var save: SaveGame: + set(new_save): + save = new_save + if _is_built: rebuild() +@export var id: int: + set(new_id): + id = new_id + if _is_built: rebuild() + +func _init(new_save: SaveGame = SaveGame.new(), new_id: int = 0) -> void: + self.save = new_save + self.id = new_id + +func _ready() -> void: + save.changed.connect(rebuild) + rebuild() + _is_built = true - var texture:= TextureRect.new() - texture.texture = save.thumbnail - texture.size_flags_vertical = Control.SIZE_SHRINK_CENTER +func rebuild(): + for child in get_children(true): + remove_child(child) + child.queue_free() - base_container.add_child(texture) - var heading_split:= HSplitContainer.new() - var heading:= Label.new() - - heading.text = "Slot %d" % id - heading.theme_type_variation = "HeaderLarge" - - var localised_date_time: String - var localised_weekday: PackedStringArray - var date_time: Dictionary = Time.get_datetime_dict_from_unix_time(save.last_saved) - - match TranslationServer.get_locale(): - "de": - localised_weekday = ["Montag", "Dienstag", "Mittwoch", "Donnerstag", "Freitag", "Samstag", "Sonntag"] - localised_date_time = "%s, %d.%d.%d um %d:%02d" % [localised_weekday[date_time["weekday"]], - date_time["day"], - date_time["month"], - date_time["year"], - date_time["hour"], - date_time["minute"] - ] - _: - localised_weekday = ["Monday", "Tuseday", "Wensday", "Thursday", "Friday", "Saturday", "Sunday"] - localised_date_time = "%s, %d/%d/%d - %d:%02d (%s)" % [localised_weekday[date_time["weekday"]], + if not save.is_valid: + disabled = true + text = "Slot %d corrupted." % id + else: + disabled = false + text = "" + + var base_container := HBoxContainer.new() + base_container.alignment = BoxContainer.ALIGNMENT_CENTER + add_child(base_container) + + var texture := TextureRect.new() + texture.texture = save.thumbnail + texture.size_flags_vertical = Control.SIZE_SHRINK_CENTER + + base_container.add_child(texture) + var heading_split := HSplitContainer.new() + var heading := Label.new() + + heading.text = "Slot %d" % id + heading.theme_type_variation = "HeaderLarge" + + var localised_date_time: String + var localised_weekday: PackedStringArray + var date_time: Dictionary = Time.get_datetime_dict_from_unix_time(save.last_saved) + + match TranslationServer.get_locale(): + "de": + localised_weekday = ["Montag", "Dienstag", "Mittwoch", "Donnerstag", "Freitag", "Samstag", "Sonntag"] + localised_date_time = "%s, %d.%d.%d um %d:%02d" % [localised_weekday[date_time["weekday"]], date_time["day"], date_time["month"], date_time["year"], - date_time["hour"] % 12 if date_time["hour"] % 12 > 1 else 12 if date_time["hour"] == 12 or date_time["minute"] == 0 else 0, - date_time["minute"], - "AM" if date_time["hour"] < 12 else "PM"] - - var time:= Label.new() - time.text = localised_date_time if not save.current_room == 0 else "Start new game." - - var info:= VBoxContainer.new() - base_container.add_child(info) - - info.add_child(heading_split) - heading_split.add_child(heading) - heading_split.add_child(time) - - var room:= Label.new() - room.theme_type_variation = "HeaderMedium" - match save.current_room: - State.rooms.MENU: - room.text = "Empty Slot" - State.rooms.DRAVEN: - room.text = "Intro Sequence" - State.rooms.YOUTH: - room.text = "Inside youth room." - State.rooms.TRANSITION: - room.text = "Transitioning to Adulthood." - State.rooms.ADULTHOOD: - room.text = "Exploring Adulthood." - State.rooms.ENDING: - room.text = "Ending" - - var state: = Label.new() - state.text = (""" - Mementos collected: 1/4 - Connections found: 1/8 - Secrets found: 1/4 - """).strip_edges() - - info.add_child(room) - info.add_child(state) - info.size_flags_vertical = Control.SIZE_SHRINK_CENTER - - custom_minimum_size = base_container.get_combined_minimum_size() + Vector2(64, 32) + date_time["hour"], + date_time["minute"] + ] + _: + localised_weekday = ["Monday", "Tuseday", "Wensday", "Thursday", "Friday", "Saturday", "Sunday"] + localised_date_time = "%s, %d/%d/%d - %d:%02d (%s)" % [localised_weekday[date_time["weekday"]], + date_time["day"], + date_time["month"], + date_time["year"], + date_time["hour"] % 12 if date_time["hour"] % 12 > 1 else 12 if date_time["hour"] == 12 or date_time["minute"] == 0 else 0, + date_time["minute"], + "AM" if date_time["hour"] < 12 else "PM"] + + var time_label := Label.new() + time_label.text = localised_date_time if not save.current_room == State.rooms.NULL else "Start new game" + + var info:= VBoxContainer.new() + base_container.add_child(info) + + info.add_child(heading_split) + heading_split.add_child(heading) + heading_split.add_child(time_label) + + var room:= Label.new() + room.theme_type_variation = "HeaderMedium" + match save.current_room: + State.rooms.NULL: + room.text = "Empty Slot" + State.rooms.YOUTH: + if save.mementos_complete == 0: + room.text = "Youth Room" + else: + room.text = "Intro Sequence" + State.rooms.TRANSITION: + room.text = "Transitioning to Adulthood" + State.rooms.ADULTHOOD: + room.text = "Exploring Adulthood" + State.rooms.ENDING: + room.text = "Ending" + + var state: = Label.new() + state.text = TranslationServer.translate((""" + Mementos collected: %d/4 + Connections found: %d/8 + """).strip_edges()) % [save.calculate_completed_sequences(), save.calculate_total_connections()] + #Secrets found: 1/4 + + info.add_child(room) + info.add_child(state) + info.size_flags_vertical = Control.SIZE_SHRINK_CENTER - theme_type_variation = "SaveButton" + theme_type_variation = "SaveButton" + + call_deferred("resize") + +func resize(): + custom_minimum_size = get_child(0, true).get_combined_minimum_size() + Vector2(64, 32) + get_child(0, true).position = Vector2(32, 16) diff --git a/src/logic-scenes/main menu/save_game_list.gd b/src/logic-scenes/main menu/save_game_list.gd index 05afa9c..61389a8 100644 --- a/src/logic-scenes/main menu/save_game_list.gd +++ b/src/logic-scenes/main menu/save_game_list.gd @@ -18,9 +18,12 @@ var scroll_container: ScrollContainer var override_save_slot: bool = false +func _validate_property(property: Dictionary) -> void: + if property.name == "saves": + property.usage = PROPERTY_USAGE_READ_ONLY + PROPERTY_USAGE_SCRIPT_VARIABLE + PROPERTY_USAGE_EDITOR + + func _ready() -> void: - #FIXME: stop this from creating countless save games! - return var dir = DirAccess.open(State.user_saves_path) print(DirAccess.get_open_error()) # Invalid Error being raised when Directory does not exist. @@ -28,31 +31,39 @@ func _ready() -> void: dir = DirAccess.open("user://") dir.make_dir_recursive(State.user_saves_path) load_games() + for i in range(save_buttons.size()): + save_buttons[i].pressed.connect(func(): picked.emit(saves[i])) + print("connect ", i) func load_games(): + saves = [] var save_game_dir := DirAccess.open(State.user_saves_path) var filepaths: PackedStringArray = save_game_dir.get_files() for path in filepaths: if path.ends_with(".json"): - saves.append(SaveGame.new(path)) + saves.append(SaveGame.new("%s/%s" % [State.user_saves_path, path.get_basename()])) saves.append(SaveGame.new()) #purging the current state save_buttons = [] if scroll_container != null: - scroll_container.free() + scroll_container.queue_free() scroll_container = ScrollContainer.new() scroll_container.horizontal_scroll_mode = ScrollContainer.SCROLL_MODE_DISABLED + scroll_container.custom_minimum_size = Vector2(0, ProjectSettings.get_setting("display/window/size/viewport_height") - 256) add_child(scroll_container) + var save_box := VBoxContainer.new() + save_box.add_theme_constant_override("separation", 16) + scroll_container.add_child(save_box) for i in range(saves.size()): var new_button := SaveGameDisplay.new(saves[i], i+1) - scroll_container.add_child(new_button) + save_box.add_child(new_button) save_buttons.append(new_button) new_button.pressed.connect(func(): _on_game_picked(i)) @@ -68,8 +79,11 @@ func _on_game_picked(id: int): # This function is called when the user us supposed to choose a slot to load or create a new game. func pick_save_slot(create_new_game: bool): - State.take_stage(self) - self.override_save_slot = create_new_game + if saves.size() == 1: + picked.emit(saves[0]) + else: + State.take_stage(self) + self.override_save_slot = create_new_game func get_most_recent_save() -> SaveGame: var most_recent_time := 0.0 @@ -80,3 +94,10 @@ func get_most_recent_save() -> SaveGame: most_recent_time = saves[i].last_saved return saves[most_recent_index] if most_recent_time > 0 else SaveGame.new() + +func has_existing_saves() -> bool: + return saves.size() > 1 + +func _input(event: InputEvent) -> void: + if event.is_action_pressed("ui_cancel"): + State.leave_stage(self) diff --git a/src/main.gd b/src/main.gd index 4394b31..413343a 100644 --- a/src/main.gd +++ b/src/main.gd @@ -38,8 +38,8 @@ var currently_loading_room: String = "": # Called when the node enters the scene tree for the first time. func _ready(): - currently_loading_room = youth_room_path - + currently_loading_room = get_room_path_from_id(main_menu.save_game_handle.get_most_recent_save().current_room) + main_menu.start_game.connect(load_save) get_tree().tree_process_mode_changed.connect(pause_mode_changed) func _process(_delta: float) -> void: @@ -52,10 +52,6 @@ func _process(_delta: float) -> void: currently_loading_room = "" room_loaded.emit() - if Input.is_action_just_pressed("reset_demo") and (OS.has_feature("demo") or true): - State.stage_list = [self] - _return_to_menu() - $"Messe-Menue".show() if Input.is_action_just_pressed("ui_menu") and in_game: toggle_pause_menu() @@ -94,10 +90,10 @@ func _return_to_menu(): func load_save(save: SaveGame): - #if currently_loading_room != "": - # await(room_loaded) + if currently_loading_room != "": + await(room_loaded) - if save.current_room != current_room_id: + if get_room_path_from_id(save.current_room) != get_room_path_from_id(current_room_id): # TODO Prevent race condition from appearing when save is loaded while room is still loading. currently_loading_room = get_room_path_from_id(save.current_room) await(room_loaded) @@ -106,6 +102,7 @@ func load_save(save: SaveGame): State.active_save_game = save in_game = true + current_room.start_room() func _on_ready_to_unload(): if get_child(0) is Node3D: @@ -113,7 +110,7 @@ func _on_ready_to_unload(): func get_room_path_from_id(id: State.rooms) -> String: match id: - State.rooms.YOUTH, State.rooms.MENU, State.rooms.DRAVEN: + State.rooms.YOUTH, State.rooms.NULL: return youth_room_path State.rooms.TRANSITION: return transition_room_path diff --git a/src/singletons/global_state.gd b/src/singletons/global_state.gd index c5d4e31..5d1f39f 100644 --- a/src/singletons/global_state.gd +++ b/src/singletons/global_state.gd @@ -294,8 +294,7 @@ func queue_for_stage(target: Object, index: int = 1): #region play state enum rooms { - MENU, - DRAVEN, + NULL, YOUTH, TRANSITION, ADULTHOOD, @@ -317,4 +316,4 @@ enum sequences { BURNOUT } -var current_room = rooms.MENU +var current_room = rooms.NULL