extends Node var failures: Array[String] = [] func check(condition: bool, message: String) -> void: if not condition: failures.append(message) push_error(message) func _ready() -> void: run.call_deferred() func run() -> void: GameState.start_new_run() var game: Node = load("res://scenes/game/game.tscn").instantiate() get_tree().root.add_child(game) get_tree().current_scene = game await get_tree().process_frame await get_tree().process_frame game.set_physics_process(false) var ship: Node = game.get_node("PlayerShip") ship.set_physics_process(false) var inventory: Node = ship.get_node("ShipInventory") GameState.captain.credits = 4321 GameState.captain.minerals.iron = 321 GameState.captain.expedition.alien_skills["general"] = true GameState.captain.expedition.crew["cabin_1"] = {"name":"Test","level":4} GameState.captain.skill_offers.assign(["electrician", "lucky"]) GameState.captain.skill_cooldowns["electrician"] = 12.0 inventory.ammunition = 123 inventory.unlocked_weapon_slots = 2 inventory.weapon_slots[0].damage_min = 13.5 inventory.weapon_slots[0].damage_max = 29.25 inventory.weapon_slots[0].special_orbs.assign(["piercing"]) ship.position = Vector2(840,610) ship.hull = 37.0 GameState.cleared_systems[GameState.system_level] = true GameState.cleared_systems[2] = true GameState.explored_pois["%d:1" % GameState.system_seed] = true GameState.captain.skill_durations["reactor_overload"] = 4.0 inventory.extension_cooldowns["test"] = 5.0 GameState.captain.expedition.laboratory_project = "machine_gun" GameState.captain.expedition.laboratory_duration = 600 GameState.captain.expedition.laboratory_remaining = 387.5 GameState.captain.expedition.alien_project = "hull" GameState.captain.expedition.alien_duration = 600 GameState.captain.expedition.alien_remaining = 245.25 var enemies_before: int = game.get_remaining_enemies() check(GameState.save_game() == OK,"save writes successfully") check(GameState.has_save(),"continue detects valid save") var saved := GameState.SAVES.read_save() check(saved.captain.credits == 4321,"captain credits serialized") check(saved.inventory.ammunition == 123,"ammunition serialized") GameState.captain.credits = 8765 check(GameState.save_game() == OK,"second save replaces first") check(GameState.SAVES.read_save(GameState.SAVES.BACKUP).captain.credits == 4321,"backup retains previous save") game.free() check(GameState.continue_game(),"save restores state") check(GameState.captain.credits == 8765,"latest credits restored") check(GameState.captain.expedition.laboratory_project == "machine_gun" and is_equal_approx(GameState.captain.expedition.laboratory_remaining,387.5),"SAVE preserves laboratory project and exact remaining time") check(GameState.captain.expedition.alien_project == "hull" and is_equal_approx(GameState.captain.expedition.alien_remaining,245.25),"SAVE preserves alien project and exact remaining time") check(GameState.captain.expedition.crew.cabin_1.level == 4,"crew restored") check(GameState.captain.expedition.alien_skills.general,"research restored") check(not GameState.cleared_systems.has(GameState.system_level),"current level encounters restart") check(GameState.cleared_systems.has(2),"other level progress retained") check(not GameState.explored_pois.has("%d:1" % GameState.system_seed),"current level exploration restarts") game = load("res://scenes/game/game.tscn").instantiate() get_tree().root.add_child(game) get_tree().current_scene = game await get_tree().process_frame await get_tree().process_frame ship = game.get_node("PlayerShip") inventory = ship.get_node("ShipInventory") check(inventory.ammunition == 123,"inventory restored into live ship") check(inventory.unlocked_weapon_slots == 2,"unlocked slots restored") check(is_equal_approx(inventory.weapon_slots[0].damage_min,13.5),"individual item damage restored") check(is_equal_approx(inventory.weapon_slots[0].damage_max,29.25),"individual item roll restored") check("piercing" in inventory.weapon_slots[0].special_orbs,"item orb effects restored") check(ship.position.distance_to(game.system_data.player_start) < 1,"load starts at level spawn") check(is_equal_approx(ship.hull,ship.max_hull),"load restores full hull") check(game.get_remaining_enemies() == enemies_before,"enemy population restored") check(GameState.captain.skill_cooldowns.is_empty(),"load clears skill cooldowns") check(GameState.captain.skill_durations.is_empty(),"load clears temporary effects") check(inventory.extension_cooldowns.is_empty(),"load clears extension cooldowns") # Surface-save normalization must leave the active live expedition untouched. var progress: Resource = GameState.captain.expedition progress.active = true progress.cargo = {"iron":7} progress.cargo_credits = 23 check(GameState.save_game() == OK,"surface save succeeds") check(progress.active and progress.cargo.get("iron",0) == 7,"surface save does not alter live cargo") saved = GameState.SAVES.read_save() check(not saved.captain.expedition.active,"surface save resumes in orbit") check(saved.captain.minerals.iron == 328,"surface cargo retained") check(GameState.captain.minerals.iron == 321,"snapshot does not modify live captain") progress.active = false for code in GameSettings.LOCALES: GameSettings.locale = code GameSettings.apply() check(not str(TranslationServer.translate("Zapisz grę")).is_empty(),"language available: "+code) if code != "pl": check(str(TranslationServer.translate("Zapisz grę")) != "Zapisz grę","menu is translated: "+code) check(str(TranslationServer.translate("Kredyty: 123")) != "Kredyty: 123","formatted strings translated: "+code) else: check(str(TranslationServer.translate("Zapisz grę")) == "Zapisz grę","Polish menu stays Polish") check(str(TranslationServer.translate("Kredyty: 123")) == "Kredyty: 123","Polish formatted text stays Polish") GameSettings.locale = "en" GameSettings.apply() check(str(TranslationServer.translate("Kredyty: 123")) == "Credits: 123","formatted numeric value retained") check(str(TranslationServer.translate("Działko plazmowe · poziom 3")) == "Plasma cannon · level 3","formatted phrase and captured item name translated") GameSettings.volume = 0.0 GameSettings.apply() check(AudioServer.is_bus_mute(0),"master mute applied") check(GameSettings.save_settings() == OK,"settings saved") var config := ConfigFile.new() check(config.load(GameSettings.PATH) == OK,"settings readable from disk") check(config.get_value("language","locale") == "en","language persisted") check(is_zero_approx(config.get_value("audio","master")),"volume persisted") var options := CanvasLayer.new() options.set_script(load("res://scripts/ui/options_dialog.gd")) get_tree().root.add_child(options) check(options.get("_language").item_count == 5,"all five languages in options") options._close() await get_tree().process_frame var pause_menu := game.get_node("SessionMenu") var escape := InputEventKey.new() escape.keycode = KEY_ESCAPE escape.pressed = true Input.parse_input_event(escape) await get_tree().process_frame check(get_tree().paused,"session menu pauses game") check(pause_menu._save(),"manual save button works") pause_menu._open_options() check(not pause_menu._dialog.visible,"options temporarily hides pause dialog") pause_menu._options._close() await get_tree().process_frame check(pause_menu._dialog.visible and get_tree().paused,"closing options restores paused menu") pause_menu._close() check(not get_tree().paused,"session menu resumes game") # Damaged primary file must fall back to the last verified backup. var file := FileAccess.open(GameState.SAVES.PATH,FileAccess.WRITE) file.store_string("corrupted test save") file.close() check(GameState.has_save(),"backup offered when primary corrupted") check(GameState.continue_game(),"corrupted primary falls back to backup") game.queue_free() await get_tree().process_frame print("SAVE_SETTINGS_TEST: ", "PASS" if failures.is_empty() else "FAIL", " (",failures.size()," failures)") get_tree().quit(0 if failures.is_empty() else 1)