extends SceneTree # Headless gameplay test: run with # godot --headless -s res://tests/test_planet_landing_proximity.gd # Verifies flying the fleet onto a planet's landing radius makes # PlanetField.get_planet_fleet_is_on() return it, and that flying back # away clears it - without the planet destroying the ships (planets are # landable, not hazards). var main_scene: Node var fleet: Node var planet_field: Node var target_chunk: Vector2i var elapsed: float = 0.0 var stage: int = 0 func _initialize() -> void: var found: bool = false for x in range(-15, 15): for y in range(-15, 15): var chunk: Vector2i = Vector2i(x, y) # Not a black hole: it destroys ships on contact, and this # scan takes the FIRST planet it finds. That used to be the gas # giant guaranteed in the origin chunk; with that guarantee gone # the scan can land the fleet on something that kills it, which # is not what either of these tests is about. if WorldGen.has_planet_at_chunk(chunk) \ and String(WorldGen.planet_data_at_chunk(chunk).get("definition_id", "")) != "black_hole": target_chunk = chunk found = true break if found: break if not found: print("FAIL: could not find any chunk with a planet to test with") quit(1) return var packed: PackedScene = load("res://world/Main.tscn") main_scene = packed.instantiate() root.add_child(main_scene) fleet = main_scene.get_node("Fleet") planet_field = main_scene.get_node("PlanetField") func _process(delta: float) -> bool: elapsed += delta match stage: 0: # target_chunk is guaranteed ASTEROID_FIELD biome (a # prerequisite for having a planet), so regular drifting # asteroids/enemies could also spawn nearby and destroy a ship # mid-test - isolate it, same as other focused tests do. # # This has to happen on the first tick, not in _initialize(): # a node's set_process(false) call made before it has fully # finished entering the tree doesn't reliably stick - the # engine's own (deferred) tree-entry finalization, which runs # strictly after _ready(), can silently reset it back to # enabled. Here, at the point _ready() is already confirmed # complete (fleet.ships is reliably populated by now), it's safe. main_scene.get_node("AsteroidField").set_process(false) main_scene.get_node("EnemySpawner").set_process(false) # Crew the fleet HERE rather than in _initialize(): work done # there can be undone by the engine's deferred tree-entry # finalization, the same reason the set_process(false) calls # above live at this point. A new game flies one vessel now. root.get_node("GameState").unlocked.append_array(["wing", "squadron", "armada"]) fleet.spawn_ships(5, Vector2.ZERO) # Silencing the field does not remove what it already placed, and # those keep drifting - a rock taking the fleet out mid-test reads # here as a landing failure. for rock in get_nodes_in_group("asteroids"): if is_instance_valid(rock): rock.queue_free() # PlanetField only scans chunks near the fleet's CURRENT # position, so it never even looks at target_chunk unless the # fleet is already nearby - move it there first. var near_pos: Vector2 = WorldGen.chunk_origin(target_chunk) + Vector2.ONE * WorldGen.CHUNK_SIZE * 0.5 for ship in fleet.ships: ship.position = near_pos fleet.move_to(near_pos) elapsed = 0.0 stage = 1 return false 1: # Wait for PlanetField to spawn the target planet. if elapsed < planet_field.check_interval + 0.1: return false if not planet_field.populated_chunks.has(target_chunk): print("TEST_PLANET_LANDING_PROXIMITY: FAIL (planet never spawned)") quit(1) return true elapsed = 0.0 stage = 2 return false 2: # Fly the fleet exactly onto the planet. var planet: Node2D = planet_field.populated_chunks[target_chunk][0] for ship in fleet.ships: ship.position = planet.position fleet.move_to(planet.position) elapsed = 0.0 stage = 3 return false 3: if elapsed < 0.1: return false var planet: Node2D = planet_field.populated_chunks[target_chunk][0] var query_ok: bool = planet_field.get_planet_fleet_is_on() == planet var ships_alive: bool = fleet.ships.size() == 5 print("query_ok=%s ships_alive=%s" % [query_ok, ships_alive]) if not (query_ok and ships_alive): print("TEST_PLANET_LANDING_PROXIMITY: FAIL (landing detection)") quit(1) return true var far_pos: Vector2 = planet.position + Vector2(5000, 5000) for ship in fleet.ships: ship.position = far_pos fleet.move_to(far_pos) elapsed = 0.0 stage = 4 return false 4: if elapsed < 0.1: return false var query_cleared_ok: bool = planet_field.get_planet_fleet_is_on() == null print("query_cleared_ok=%s" % query_cleared_ok) if query_cleared_ok: print("TEST_PLANET_LANDING_PROXIMITY: PASS") quit(0) else: print("TEST_PLANET_LANDING_PROXIMITY: FAIL (leaving detection)") quit(1) return true return false