class_name MainMenu extends Control signal load_game_request(save_data: SaveData, slot_index: int) signal quit_request const USER_SETTINGS_PATH: String = "user://settings.ini" const SAVES_DIR: String = "user://saves/" const SAVE_DATA_PATH: String = SAVES_DIR + "%s/save_data.tres" @onready var continue_button: Button = %ContinueButton @onready var load_button: Button = %LoadButton @onready var new_game_button: Button = %NewGameButton @onready var options_button: Button = %OptionsButton @onready var quit_button: Button = %QuitButton @onready var saves_scroll_container: ScrollContainer = %SavesScrollContainer @onready var saves_container: VBoxContainer = %SavesContainer @onready var settings_menu: SettingsMenu = %SettingsMenu static func get_save_slots() -> PackedInt32Array: if not DirAccess.dir_exists_absolute(SAVES_DIR): return [] var dirs: PackedStringArray = DirAccess.get_directories_at(SAVES_DIR) var index: int = 0 while index < dirs.size(): var dir_name: String = dirs[index] if dir_name.is_valid_int() and not (dir_name.begins_with("+") or dir_name.begins_with("-")): index += 1 else: dirs.remove_at(index) return type_convert(dirs, TYPE_PACKED_INT32_ARRAY) static func get_unique_save_slot_index() -> int: var index: int = 0 var taken_slots: PackedInt32Array = get_save_slots() while taken_slots.has(index): index += 1 return index static func get_save_path(slot_index: int) -> String: return SAVE_DATA_PATH % slot_index func _ready() -> void: continue_button.pressed.connect(_on_continue_pressed) load_button.pressed.connect(_on_load_pressed) new_game_button.pressed.connect(_on_new_game_pressed) options_button.pressed.connect(_on_options_pressed) quit_button.pressed.connect(_on_quit_pressed) settings_menu.close_request.connect(_on_settings_close_request) continue_button.visible = has_save() func has_save() -> bool: var config: ConfigFile = Utils.load_config(USER_SETTINGS_PATH) return config.has_section_key("save", "last_slot") func populate_save_entries() -> void: for child: Node in saves_container.get_children(): child.queue_free() for save_slot: int in get_save_slots(): var save_path: String = get_save_path(save_slot) var button := SaveEntryButton.construct_save_entry_button(saves_container, save_path, save_slot) button.pressed.connect(_on_save_entry_pressed.bind(save_slot)) func _on_continue_pressed() -> void: var config: ConfigFile = Utils.load_config(USER_SETTINGS_PATH) var slot: int = config.get_value("save", "last_slot", 0) var path: String = get_save_path(slot) if not FileAccess.file_exists(path): slot = 0 # Try the first save slot. path = get_save_path(slot) if not FileAccess.file_exists(path): _on_new_game_pressed() return config.set_value("save", "last_slot", slot) config.save(USER_SETTINGS_PATH) var save_data: SaveData = load(path) load_game_request.emit(save_data, slot) func _on_load_pressed() -> void: saves_scroll_container.show() populate_save_entries() func _on_new_game_pressed() -> void: var save_data: SaveData = Game.INITIAL_SAVE_DATA.duplicate() var slot_index: int = get_unique_save_slot_index() load_game_request.emit(save_data, slot_index) var config: ConfigFile = Utils.load_config(USER_SETTINGS_PATH) config.set_value("save", "last_slot", slot_index) config.save(USER_SETTINGS_PATH) func _on_options_pressed() -> void: settings_menu.show() func _on_quit_pressed() -> void: quit_request.emit() func _on_save_entry_pressed(save_slot: int) -> void: var config: ConfigFile = Utils.load_config(USER_SETTINGS_PATH) config.set_value("save", "last_slot", save_slot) config.save(USER_SETTINGS_PATH) var save_path: String = get_save_path(save_slot) if not FileAccess.file_exists(save_path): _on_new_game_pressed() return var save_data: SaveData = load(save_path) load_game_request.emit(save_data, save_slot) func _on_settings_close_request() -> void: settings_menu.hide()