#211 conquest is the fight now: a planet registers the garrison its setup authors, each defender's own death counts against it, and the last one takes the world. The capture points - stand in a ring, wait out a timer, once per ring - are gone, along with the editor palette that placed them. #212 conquest opens a dialog on the surface naming the research points recovered; the award travels with the signal, after it is banked. #209 the prologue's charted sectors go with the breach, so the map the survivors keep is of where they now are - and "chart 30 sectors" is no longer complete before they have flown anywhere. #218 enemy variety is gated on the FLEET, not on wave strength: a starting fleet meets chasers only at any wave number, and each vessel past three opens one more kind. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019AJMdB7iuHuLFZM1aBu3GD
143 lines
5.5 KiB
GDScript
143 lines
5.5 KiB
GDScript
extends SceneTree
|
|
|
|
# Headless gameplay test: run with
|
|
# godot --headless -s res://tests/test_planet_garrison.gd
|
|
# Forgejo #211: taking a planet is killing what defends it. The capture
|
|
# points this replaced - stand in a ring, wait out a timer, once per ring -
|
|
# are gone, so what has to be proven is that the FIGHT reaches the conquest
|
|
# state, through the enemies' own deaths rather than through a bookkeeping
|
|
# call a test makes on their behalf.
|
|
#
|
|
# test_conquered_planet_clear.gd covers the counting rules around landing and
|
|
# re-landing. This one covers the wiring: a real Enemy, destroyed the way
|
|
# anything destroys one, moves the planet toward being held.
|
|
#
|
|
# Covers:
|
|
# A. an authored garrison registers itself when the surface is composed
|
|
# B. killing one defender is progress, not conquest
|
|
# C. killing the last one conquers the planet, exactly once, and the
|
|
# research award rides along with the signal
|
|
# D. an enemy that dies after the planet has already fallen changes nothing
|
|
|
|
# Resolved via load() inside _initialize(), NOT a top-level `const ...
|
|
# preload(...)`. A top-level preload in a script-mode ENTRY point (-s
|
|
# this_file.gd) evaluates during this file's own early compilation, which can
|
|
# happen before autoloads are registered - and these scripts reference
|
|
# GameState in function bodies, which GDScript resolves at compile time.
|
|
var PLANET_SETUP_SCRIPT: Script
|
|
var SPAWN_SCRIPT: Script
|
|
|
|
var game_state: Node
|
|
var host: Node
|
|
var planet_id: String = "test_garrison_planet"
|
|
var conquered_count: int = 0
|
|
var conquered_points: int = -1
|
|
var stage: int = 0
|
|
var elapsed: float = 0.0
|
|
|
|
|
|
func _initialize() -> void:
|
|
PLANET_SETUP_SCRIPT = load("res://surface/PlanetSetup.gd")
|
|
SPAWN_SCRIPT = load("res://surface/PlanetSetupSpawn.gd")
|
|
game_state = root.get_node("GameState")
|
|
game_state.planet_capture.clear()
|
|
game_state.planet_id = planet_id
|
|
game_state.planet_definition_id = "rocky"
|
|
game_state.planet_conquered.connect(func(_id, points):
|
|
conquered_count += 1
|
|
conquered_points = points)
|
|
|
|
var setup: Resource = PLANET_SETUP_SCRIPT.new()
|
|
setup.setup_id = "test_garrison"
|
|
setup.surface_profile_id = "rocky"
|
|
# Worth something, so the award travelling with the signal is checked on a
|
|
# planet that actually pays.
|
|
setup.research_point_reward = 3
|
|
for i in range(3):
|
|
var spawn: Resource = SPAWN_SCRIPT.new()
|
|
spawn.enemy_id = "chaser"
|
|
spawn.position = Vector2(0.0, 300.0 * float(i + 1))
|
|
setup.enemy_spawns.append(spawn)
|
|
|
|
host = load("res://surface/PlanetSetupHost.tscn").instantiate()
|
|
root.add_child(host)
|
|
host.apply_setup(setup)
|
|
|
|
|
|
func _defenders() -> Array:
|
|
var out: Array = []
|
|
for child in host.get_children():
|
|
if is_instance_valid(child) and child.is_in_group("enemies") \
|
|
and not child.is_queued_for_deletion():
|
|
out.append(child)
|
|
return out
|
|
|
|
|
|
func _process(delta: float) -> bool:
|
|
elapsed += delta
|
|
if elapsed < 0.2:
|
|
return false
|
|
match stage:
|
|
0:
|
|
# --- A. the garrison registered itself -----------------------
|
|
var defenders: Array = _defenders()
|
|
if defenders.size() != 3:
|
|
return _fail("the surface placed %d defenders for 3 authored" % defenders.size())
|
|
if game_state.garrison_total(planet_id) != 3 \
|
|
or game_state.garrison_remaining(planet_id) != 3:
|
|
return _fail("a 3-strong garrison registered as %d of %d" % [
|
|
game_state.garrison_remaining(planet_id),
|
|
game_state.garrison_total(planet_id)])
|
|
print("3 defenders placed, and the planet knows it")
|
|
|
|
# --- B. one down is not conquest -----------------------------
|
|
var points_before: int = game_state.research_points
|
|
defenders[0].take_damage(defenders[0].hp)
|
|
if game_state.garrison_remaining(planet_id) != 2:
|
|
return _fail("one kill left %d of the garrison standing, expected 2" \
|
|
% game_state.garrison_remaining(planet_id))
|
|
if game_state.is_planet_conquered(planet_id):
|
|
return _fail("the planet fell to the first kill")
|
|
if game_state.research_points != points_before:
|
|
return _fail("an unfinished conquest paid out")
|
|
print("one defender down: 2 left, planet still theirs")
|
|
|
|
# --- C. the last one takes it --------------------------------
|
|
defenders[1].take_damage(defenders[1].hp)
|
|
defenders[2].take_damage(defenders[2].hp)
|
|
if not game_state.is_planet_conquered(planet_id):
|
|
return _fail("the whole garrison is dead and the planet is not ours")
|
|
if conquered_count != 1:
|
|
return _fail("planet_conquered fired %d times, expected once" % conquered_count)
|
|
if conquered_points != 3:
|
|
return _fail("the conquest reported %d research points, expected the authored 3" \
|
|
% conquered_points)
|
|
if game_state.research_points != points_before + 3:
|
|
return _fail("the reported award was not the one banked")
|
|
print("last defender down: planet taken, 3 research points paid once")
|
|
|
|
elapsed = 0.0
|
|
stage = 1
|
|
return false
|
|
1:
|
|
# --- D. a straggler after the fact changes nothing -----------
|
|
# A shot already in flight, or a bomb still blooming, can kill
|
|
# something a frame after the planet has fallen.
|
|
var points_after: int = game_state.research_points
|
|
game_state.mark_garrison_enemy_destroyed(planet_id)
|
|
if conquered_count != 1:
|
|
return _fail("a kill after conquest fired planet_conquered again")
|
|
if game_state.research_points != points_after:
|
|
return _fail("a kill after conquest paid the reward a second time")
|
|
print("a late kill is absorbed: no second conquest, no second payment")
|
|
|
|
print("TEST_PLANET_GARRISON: PASS")
|
|
quit(0)
|
|
return true
|
|
return false
|
|
|
|
|
|
func _fail(message: String) -> bool:
|
|
print("TEST_PLANET_GARRISON: FAIL (%s)" % message)
|
|
quit(1)
|
|
return true
|