Randoloot/tests/levels/system_lifecycle_test.gd
2026-10-12 22:16:09 +02:00

231 lines
11 KiB
GDScript

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))))