extends Node var is_runner := false var failures: Array[String] = [] const GENERATOR := preload("res://scripts/levels/distant_sector_generator.gd") const ORBS := preload("res://scripts/items/special_orbs.gd") const LOOT := preload("res://scripts/game/distant_loot.gd") func _ready() -> void: if not is_runner: var runner = get_script().new() runner.is_runner = true get_tree().root.add_child.call_deferred(runner) else: _run.call_deferred() func check(value: bool, message: String) -> void: if not value: failures.append(message); push_error("DISTANT_TEST: "+message) func frames(count: int = 4) -> void: for index in count: await get_tree().process_frame func freeze_game(game: Node) -> void: game.get_node("PlayerShip").set_physics_process(false) for enemy in get_tree().get_nodes_in_group("enemies"): enemy.set_physics_process(false) func _run() -> void: var map_checks := preload("res://tests/distant_expeditions_checks.gd").new() var map_report: Dictionary = map_checks.run_checks() for failure in map_report.failures: check(false, str(failure)) map_checks.free() for level in [1,60,120,125,500]: var ordinary := preload("res://scripts/levels/level_balance.gd").enemy_tiers(level) var tiers := GENERATOR.enemy_tiers(level) check(tiers.count(2)==1,"One boss") check(tiers.count(0)==ordinary.count(0)*2,"Double normals") check(tiers.count(1)==ordinary.count(1)*2,"Double elites") check(preload("res://scripts/levels/level_balance.gd").enemy_stat_scale(125)>preload("res://scripts/levels/level_balance.gd").enemy_stat_scale(120),"Stats beyond 120") check(LOOT.roll(125,false,2,0.149,0.0).size()==1,"Map 15 percent") check(LOOT.roll(125,false,2,0.15,0.0).is_empty(),"Map boundary and no regular orb") for seed_value in 100: for chance in [0.0,0.15,1.0]: var boss_drops := LOOT.roll(125,true,seed_value,chance,1.0) check(boss_drops.size()==2 and boss_drops[0].has("map") and boss_drops[1].has("orb"),"Exactly one guaranteed boss map and orb") var next_map: Dictionary = LOOT.roll(125,false,2,0.0,1.0)[0].map check(int(next_map.level)>125 and int(next_map.level)<=130,"Map chain") GameState.start_new_run() GameState.system_level = 7 GameState.system_seed = 777 GameState.remember_system() GameState.captain.expedition.distant_maps["integration"] = {"id":"integration","level":125,"seed":123456,"name":"Sektor testowy","source_planet":"Test","source_level":120} GameState.captain.expedition.deuter = 124999 check(not GameState.depart_distant("integration"),"No flight without fuel") check(GameState.system_level==7 and GameState.captain.expedition.deuter==124999,"Failed departure preserved state") GameState.captain.expedition.deuter = 125000 get_tree().change_scene_to_file("res://scenes/game/game.tscn") await frames() var game := get_tree().current_scene freeze_game(game) var player := game.get_node("PlayerShip") var inventory := player.get_node("ShipInventory") player.is_docked = true var weapon: ItemInstance = inventory.weapon_slots[0] var engine := ItemInstance.new() engine.definition = preload("res://resources/items/engine_extension.tres") inventory.module_slots[2] = engine var progress: Resource = GameState.captain.expedition progress.orbs = {"piercing":2,"booster":1} check(not ORBS.apply(progress,inventory,engine,"piercing"),"Piercing category restriction") check(not ORBS.apply(progress,inventory,weapon,"booster"),"Booster category restriction") check(ORBS.apply(progress,inventory,weapon,"piercing"),"Apply piercing") check(not ORBS.apply(progress,inventory,weapon,"piercing") and progress.orbs.piercing==1,"No stacking or extra cost") check(ORBS.apply(progress,inventory,engine,"booster"),"Apply booster") check(player.has_free_mini_boost(),"Equipped engine") Input.action_press("ship_mini_boost") player.energy = 0 player._update_mini_boost(1.0) check(player._mini_boost_active and player.energy==0,"Free TAB with empty generator") Input.action_release("ship_mini_boost") inventory.module_slots[2] = null check(not player.has_free_mini_boost(),"Unequipped engine no effect") inventory.module_slots[2] = engine check(game.travel_to_distant("integration"),"Flight requested") await frames(3) check(game.has_node("FreighterWarpDeparture") and get_tree().paused,"Departure cinematic freezes combat") check(not game.travel_to_distant("integration"),"Cannot pay again during warp") var warp_deadline := Time.get_ticks_msec()+7000 while get_tree().current_scene == game and Time.get_ticks_msec()=1 and orbs<=2,"Actual boss death drops map, guaranteed orb and optional replication") check(get_tree().get_nodes_in_group("time_crystal_pickups").size()==1,"Boss also drops time crystals") game.get_node("DistantSector")._physics_process(0.3) check(game.system_cleared,"Sector cleared") player.landing_combat_lock = 0 var controller := game.get_node("PlanetExpeditions") player.is_docked = false player.position = controller.freighter.position controller.land_nearby() check(is_instance_valid(controller.screen) and player.is_docked,"Normal docking during expedition") check(controller.screen.find_child("ReturnFromDistant",true,false)!=null,"Return button inside freighter") controller.screen._return_from_distant() await frames(8) game = get_tree().current_scene freeze_game(game) check(GameState.active_distant_map.is_empty() and GameState.system_level==7 and GameState.system_seed==777,"Return home") check(GameState.captain.expedition.deuter==0,"Return free") check(game.has_node("PlanetExpeditions") and game.has_node("CelestialBodies"),"Normal scene restored") check(is_instance_valid(game.get_node("PlanetExpeditions").screen) and game.get_node("PlayerShip").is_docked,"Return docks at freighter") var combat_checks := preload("res://tests/items/combat_orbs_checks.gd").new() for failure in combat_checks.run(game): check(false,str(failure)) print("DISTANT_INTEGRATION_RESULT: "+JSON.stringify({"failures":failures,"passed":failures.is_empty()}))