extends Node const GEAR := preload("res://scripts/planets/captain_equipment.gd") var screen: Control func settle() -> void: for frame in 5: await get_tree().process_frame await RenderingServer.frame_post_draw func capture(name: String) -> void: await settle() assert(get_viewport().get_texture().get_image().save_png("res://artifacts/freighter_operations_%s.png" % name) == OK) func click_room(id: String) -> void: var section: Dictionary = screen.deck.room(id) var point: Vector2 = screen.deck.design_to_local((section.rect as Rect2).get_center()) assert(screen.deck.section_at(point) == id) var event := InputEventMouseButton.new() event.button_index = MOUSE_BUTTON_LEFT event.pressed = true event.position = point screen.deck._gui_input(event) assert(screen._tab == id) func button_starting(text: String) -> Button: for node in screen._content.find_children("*","Button",true,false): if node.text.begins_with(text): return node as Button return null func _ready() -> void: GameState.system_seed = 8428159 GameState.selected_ship_path = "res://assets/Ships/player/bastion.png" GameState.captain.parts = 100 GameState.captain.credits = 2000 for key in ["silicon","copper","nickel","iron","tungsten","titanium"]: GameState.captain.minerals[key] = 500 GameState.captain.expedition.lander_hp = 63 GameState.captain.expedition.freighter_rooms.clear() var game := preload("res://scenes/game/game.tscn").instantiate() add_child(game) await settle() var manager := game.get_node("PlanetExpeditions") assert(manager.freighter.z_index < game.player.z_index) var music: AudioStreamPlayer = game.get_node("GameMusic") assert(music.playing and not music.stream_paused) var music_before := music.get_playback_position() manager.open_freighter() await get_tree().create_timer(0.18,true).timeout assert(music.can_process() and music.playing and not music.stream_paused) assert(music.get_playback_position() > music_before,"Music must continue from its current position during docking") screen = manager.screen assert(screen.scene_file_path == "res://scenes/planets/freighter_interior.tscn") assert(get_tree().paused and game.player.is_docked) assert(screen.deck.ship_texture == game.player.get_node("Sprite2D").texture) assert(screen.deck.ship_name == "Bastion") assert(screen.deck.ROOMS.size() == 11) assert(screen.deck._art.get_image().has_mipmaps()) var active := 0 var upper_locked := 0 var lower_locked := 0 for section in screen.deck.ROOMS: active += int(section.active) upper_locked += int(str(section.id).begins_with("expansion")) lower_locked += int(str(section.id).begins_with("cabin")) var point: Vector2 = screen.deck.design_to_local((section.rect as Rect2).get_center()) assert(screen.deck.section_at(point) == section.id) assert(active == 2 and upper_locked == 3 and lower_locked == 5) assert(not screen._drawer.visible) var before: float = screen.deck._time await capture("overview") assert(screen.deck._time > before,"Deck lights must animate while space is paused") click_room("workshop") await capture("workshop") assert(screen._drawer.get_global_rect().end.x <= get_viewport().get_visible_rect().size.x) assert(screen._drawer.get_global_rect().end.y <= get_viewport().get_visible_rect().size.y) var build := screen._content.find_child("CraftGear_breathing",true,false) as Button assert(build != null and not build.disabled) build.pressed.emit() assert(GEAR.level(GameState.captain,"breathing") == 2) assert(GameState.captain.parts == 90) screen._close_section() click_room("expansion_2") await capture("renovation") assert(button_starting("WYTWÓRZ") == null) click_room("cabin_3") assert(screen._drawer_title.text == "KAJUTA 03") var escape := InputEventKey.new() escape.pressed = true escape.keycode = KEY_ESCAPE screen._input(escape) assert(not screen._drawer.visible and get_tree().paused) click_room("hangar") await capture("hangar") var repair := screen._content.find_child("RepairLander",true,false) as Button assert(repair != null and not repair.disabled) repair.pressed.emit() assert(GameState.captain.expedition.lander_hp == 100) assert(GameState.captain.parts == 53) # Full cargo must not lose the expedition's recovered module. var inventory: ShipInventory = game.player.get_node("ShipInventory") var module := preload("res://scripts/items/item_generator.gd").generate_for_definition(preload("res://resources/items/reinforced_shield.tres"),3) for index in inventory.get_cargo_capacity(): inventory.cargo[index] = module GameState.captain.expedition.delivered_modules.append(module) screen._refresh() screen._content.find_child("CollectRecovered",true,false).pressed.emit() assert(GameState.captain.expedition.delivered_modules.size() == 1) inventory.cargo[0] = null screen._content.find_child("CollectRecovered",true,false).pressed.emit() assert(GameState.captain.expedition.delivered_modules.is_empty()) var credits_before: int = GameState.captain.credits var parts_before: float = GameState.captain.parts var minerals_before: Dictionary = GameState.captain.minerals.duplicate() assert(screen.deck.room_nodes.size() == 8) for id in ["expansion_1","expansion_2","expansion_3","cabin_1","cabin_2","cabin_3","cabin_4","cabin_5"]: click_room(id) assert(not screen.deck.is_built(id)) var construct := button_starting("ZBUDUJ") assert(construct != null) construct.pressed.emit() assert(screen.deck.is_built(id)) assert(screen.deck.room_nodes[id].built) assert(screen.deck.room(id).status == "ZBUDOWANO") assert(button_starting("ZBUDUJ") == null) screen._construct_room(id) # Repeated requests must be harmless. assert(GameState.captain.expedition.freighter_rooms.size() == 8) assert(GameState.captain.credits == credits_before) assert(GameState.captain.parts == parts_before) assert(GameState.captain.minerals == minerals_before) screen._select_section("storage") await capture("storage_menu") screen._select_section("hangar") screen._refresh() await capture("hangar_upgrades") assert(screen._content.find_child("UnlockWeapon",true,false) != null) # Compact drawer layout still fits when the usable area becomes narrower. screen.size = Vector2(640,600) screen._select_section("storage") await settle() assert(screen._storage_columns.columns == 1) assert(screen._drawer.get_global_rect().end.x <= 640) assert(screen._drawer.get_global_rect().end.y <= 600) assert(screen._drawer.find_child("workshopTab",true,false) == null) screen._select_section("workshop") assert(screen._tab == "workshop") screen.size = get_viewport().get_visible_rect().size screen._layout() # Room state is an exported resource field, ready for game save serialization. assert(ResourceSaver.save(GameState.captain.expedition,"user://freighter_rooms_test.tres") == OK) var restored: Resource = ResourceLoader.load("user://freighter_rooms_test.tres","",ResourceLoader.CACHE_MODE_IGNORE) assert(restored.freighter_rooms == GameState.captain.expedition.freighter_rooms) DirAccess.remove_absolute("user://freighter_rooms_test.tres") screen._close_section() await capture("built") var leave := InputEventKey.new() leave.pressed = true leave.keycode = KEY_L screen._input(leave) assert(not get_tree().paused and not game.player.is_docked) manager.open_freighter() screen = manager.screen assert(screen.deck.room_nodes.size() == 8) for id in GameState.captain.expedition.freighter_rooms: assert(screen.deck.is_built(id) and screen.deck.room_nodes[id].built) screen.closed.emit() game.queue_free() await get_tree().process_frame # The scene can also be opened directly in the editor without a live inventory. GameState.selected_ship_path = "res://assets/Ships/player/zmija.png" screen = preload("res://scenes/planets/freighter_interior.tscn").instantiate() add_child(screen) await capture("second_ship") assert(screen.deck.ship_texture.resource_path == GameState.selected_ship_path) screen.queue_free() await get_tree().process_frame print("FREIGHTER INTERIOR PASS: 8 free replaceable rooms, duplicate construction, resource serialization, redocking persistence, real ship, workshop, repair, cargo and ESC/L") get_tree().quit()