extends Node const GAME_SCENE := preload("res://scenes/game/game.tscn") const ITEM_GENERATOR := preload("res://scripts/items/item_generator.gd") func _ready() -> void: GameState.start_new_run() GameState.system_seed = 314159 var game := GAME_SCENE.instantiate() as Node2D get_tree().root.call_deferred("add_child", game) await get_tree().process_frame await get_tree().process_frame get_tree().current_scene = game _freeze(game) _assert_boss_and_health(game) var star := game.get_node("CelestialBodies/CentralStar") var star_light: PointLight2D = star.get_node("StarLight") assert(star_light.shadow_enabled and star_light.energy < 0.5) assert(star_light.position == Vector2.ZERO) assert(star_light.shadow_filter == Light2D.SHADOW_FILTER_PCF5) assert(star_light.color == preload("res://scripts/levels/celestial_texture_catalog.gd").star_light_color(star.get("body_texture"))) assert(star.get_node("HullLight").get("range_item_cull_mask") == 2) assert(GameState.system_level == 1 and int(game.call("get_remaining_enemies")) == 4) assert(not game.has_node("WeaponTestTarget")) assert(game.get_node("CelestialBodies").get_child_count() >= 2) var player := game.get_node("PlayerShip") as CharacterBody2D var inventory := player.get_node("ShipInventory") as ShipInventory var weapon := ITEM_GENERATOR.generate_for_definition(preload("res://resources/items/beam_laser.tres"), 1) weapon.damage_min = 1 weapon.damage_max = 5 var free_slot := inventory.cargo.find(null) assert(inventory.add_item(weapon)) assert(inventory.move_item("cargo", free_slot, "weapon", 0)) var module := ITEM_GENERATOR.generate_for_definition(preload("res://resources/items/hull_plating.tres"), 1) free_slot = inventory.cargo.find(null) assert(inventory.add_item(module)) assert(inventory.move_item("cargo", free_slot, "module", 1)) var equipped_module := inventory.get_item("module", 1) var tooltip := weapon.get_tooltip_text() var initial_data: Dictionary = game.get("system_data") var initial_seed := GameState.system_seed var planet: Node2D = game.get("protected_planet") player.position = planet.position game.call("_physics_process", 0.0) var menu: Control = game.get("services_menu") assert(not menu.visible and not bool(game.call("advance_to_next_level"))) assert(not bool(game.call("open_wormhole"))) _clear_enemies(game) player.velocity = Vector2(30, 0) game.call("_physics_process", 0.0) assert(menu.visible and not bool(player.get("is_docked"))) assert(player.velocity == Vector2(30, 0)) assert(bool(game.get("system_cleared")) and bool(planet.get("is_safe"))) Input.action_press("ship_thrust") player.call("_physics_process", 0.1) Input.action_release("ship_thrust") assert(player.velocity.y < 0.0) game.call("_physics_process", 0.0) assert(menu.visible) GameState.captain.credits = inventory.get_ammunition_buy_cost() var ammunition_before := inventory.ammunition menu.get_node("Center/Panel/Contents/BuyAmmunitionButton").emit_signal("pressed") assert(inventory.ammunition == ammunition_before + ShipInventory.AMMUNITION_BUY_AMOUNT and GameState.captain.credits == 0) var learning_points_before := GameState.captain.learning_points assert(GameState.captain.train_skill("gunner")) GameState.captain.credits = GameState.captain.get_skill_reset_cost() GameState.captain.emit_changed() var reset_button: Button = menu.get_node("Center/Panel/Contents/ResetSkillsButton") assert(not reset_button.disabled) reset_button.emit_signal("pressed") assert(GameState.captain.get_skill_rank("gunner") == 0) assert(GameState.captain.learning_points == learning_points_before and GameState.captain.credits == 0) assert(reset_button.disabled) player.position = initial_data["player_start"] game.call("_physics_process", 0.0) assert(not menu.visible) assert(not bool(game.call("open_wormhole"))) player.position = planet.position game.call("_physics_process", 0.0) assert(menu.visible) player.position = initial_data["player_start"] player.call("take_damage", 100000.0) await get_tree().create_timer(1.3).timeout game = get_tree().current_scene as Node2D _freeze(game) player = game.get_node("PlayerShip") as CharacterBody2D inventory = player.get_node("ShipInventory") as ShipInventory assert(GameState.system_level == 1 and GameState.system_seed == initial_seed) assert(game.get("system_data") == initial_data) assert(int(game.call("get_remaining_enemies")) == 4) assert(inventory.get_item("weapon", 0) == weapon) assert(inventory.get_item("module", 1) == equipped_module) assert(weapon.get_tooltip_text() == tooltip) _assert_full_resources(player) _clear_enemies(game) planet = game.get("protected_planet") player.position = planet.position game.call("_physics_process", 0.0) assert(not bool(game.call("advance_to_next_level"))) menu = game.get("services_menu") menu.get_node("Center/Panel/Contents/NextButton").emit_signal("pressed") var portal: Node2D = game.get("wormhole") assert(is_instance_valid(portal)) assert(GameState.system_level == 1) assert(is_equal_approx(portal.global_position.distance_to(planet.global_position), game.WORMHOLE_PLANET_DISTANCE)) assert(not bool(game.call("open_wormhole"))) assert(not bool(game.call("advance_to_next_level"))) player.position = portal.position + Vector2(game.WORMHOLE_ENTRY_RADIUS + 10, 0) game.call("_physics_process", 0.0) assert(not menu.visible and GameState.system_level == 1) player.position = planet.position game.call("_physics_process", 0.0) assert(menu.visible and bool(menu.get_node("Center/Panel/Contents/NextButton").get("disabled"))) player.position = portal.position game.call("_physics_process", 0.0) assert(not bool(game.call("advance_to_next_level"))) await get_tree().process_frame await get_tree().process_frame await get_tree().process_frame game = get_tree().current_scene as Node2D _freeze(game) player = game.get_node("PlayerShip") as CharacterBody2D inventory = player.get_node("ShipInventory") as ShipInventory assert(GameState.system_level == 2 and GameState.system_seed != initial_seed) assert(game.get("wormhole") == null) assert(game.get("system_data") != initial_data) assert(inventory.get_item("weapon", 0) == weapon and inventory.get_item("module", 1) == equipped_module) assert(weapon.get_tooltip_text() == tooltip) _assert_full_resources(player) var enemy := get_tree().get_nodes_in_group("enemies")[0] as CharacterBody2D enemy.call("apply_level_settings", 2, 2) assert(is_equal_approx(float(enemy.get("max_hull")), 420.0)) enemy.call("take_damage", 100000.0) await get_tree().process_frame await get_tree().process_frame var found_level_two_loot := false for loot in get_tree().get_nodes_in_group("loot"): if game.is_ancestor_of(loot): assert(int(loot.get("item").get("item_level")) == 2) found_level_two_loot = true assert(found_level_two_loot) inventory.preserve_for_restart() GameState.system_level = 1000 assert(get_tree().reload_current_scene() == OK) await get_tree().process_frame await get_tree().process_frame await get_tree().process_frame game = get_tree().current_scene as Node2D _freeze(game) assert(int(game.call("get_remaining_enemies")) == 39) _clear_enemies(game) player = game.get_node("PlayerShip") as CharacterBody2D planet = game.get("protected_planet") player.position = planet.position game.call("_physics_process", 0.0) menu = game.get("services_menu") assert(menu.visible) assert(bool(menu.get_node("Center/Panel/Contents/NextButton").get("disabled"))) assert(not bool(game.call("advance_to_next_level"))) assert(not bool(game.call("open_wormhole"))) print("SYSTEM_LIFECYCLE_TEST: PASS (proximity services, free steering, ammo purchase, wormhole request/entry, retry, inventory preservation, boss stats/HP, next level and level cap)") func _freeze(game: Node2D) -> void: game.set_physics_process(false) var star: Node2D = game.get_node("CelestialBodies/CentralStar") for body in game.get_node("CelestialBodies").get_children(): if body == star: continue var sprite: Sprite2D = body.get_node("BodySprite") var lit_direction := preload("res://scripts/levels/celestial_texture_catalog.gd").PLANET_LIT_DIRECTION.rotated(sprite.global_rotation) var toward_star: Vector2 = (star.global_position - body.global_position).normalized() assert(lit_direction.dot(toward_star) > 0.999) assert(is_zero_approx(body.global_rotation)) game.get_node("PlayerShip").set_physics_process(false) game.get_node("PlayerShip/WeaponController").set_physics_process(false) assert(game.get_node("PlayerShip/Sprite2D/ShipShadow") is LightOccluder2D) for enemy in get_tree().get_nodes_in_group("enemies"): if game.is_ancestor_of(enemy): var data: Dictionary = game.get("system_data") assert(enemy.get_node("Sprite2D").get("texture") == game.ENEMY_TEXTURES[int(data["enemy_texture_index"])]) var shadow: LightOccluder2D = enemy.get_node("Sprite2D/ShipShadow") assert(shadow.occluder.polygon.size() >= 3) assert(shadow.global_scale.is_equal_approx(enemy.get_node("Sprite2D").global_scale)) enemy.set_physics_process(false) func _assert_boss_and_health(game: Node2D) -> void: var boss: CharacterBody2D var normal: CharacterBody2D for enemy in get_tree().get_nodes_in_group("enemies"): if game.is_ancestor_of(enemy): if enemy.loot_tier == 2: assert(boss == null) boss = enemy elif enemy.loot_tier == 0: normal = enemy assert(boss == null and normal != null) # Compare boss stats separately: the actual encounter remains pending. for data in game.system_data["enemies"]: if data["tier"] == 2: boss = game._spawn_enemy(data, Vector2(1500, 0)) break assert(boss != null) boss.set_physics_process(false) for key in ["max_hull", "weapon_damage"]: assert(is_equal_approx(float(boss.get(key)), float(normal.get(key)) * 6.4)) for key in ["approach_speed", "approach_acceleration", "turn_speed", "activation_range", "weapon_range"]: assert(is_equal_approx(float(boss.get(key)), float(normal.get(key)) * 2.0)) assert(is_equal_approx(boss.weapon_cooldown, normal.weapon_cooldown * 0.5)) assert(boss.get_node("Sprite2D").scale == normal.get_node("Sprite2D").scale * 2.0) assert(boss.get_node("CollisionShape2D").scale == Vector2(2, 2)) var bar: Node2D = boss.get_node("HealthBar") assert(is_equal_approx(bar.get_health_ratio(), 1.0)) boss.take_damage(boss.max_hull * 0.5) assert(is_equal_approx(bar.get_health_ratio(), 0.5)) boss.rotation = 1.2 bar._process(0.0) assert(is_zero_approx(bar.global_rotation)) assert(bar.global_position == boss.global_position + Vector2(0, -68)) boss.free() func _clear_enemies(game: Node2D) -> void: for phase in 2: for enemy in get_tree().get_nodes_in_group("enemies"): if game.is_ancestor_of(enemy): enemy.call("take_damage", 100000.0) game.call("_physics_process", 0.0) func _assert_full_resources(player: CharacterBody2D) -> void: for resource in ["hull", "shields", "energy"]: assert(is_equal_approx(float(player.get(resource)), float(player.get("max_" + resource))))