Resolve pending gameplay tickets

This commit is contained in:
Loïc Wisniewski 2026-09-02 13:43:56 +02:00
commit c2ebbfaa2d
28 changed files with 618 additions and 188 deletions

View file

@ -0,0 +1,137 @@
extends SceneTree
# Forgejo #179: an Energy Propulser in the fleet grants a hold-aim-release
# dash. Covers visibility, aimed movement, energy cost, formation integrity,
# and one cooldown per Propulser.
const DASH_COST: int = 15
const DASH_DISTANCE: float = 520.0
var state: Node
var main: Node
var fleet: Node
var dash: Node
var stage: int = 0
var elapsed: float = 0.0
var first_origin: Vector2
var second_origin: Vector2
var offsets_before: Array = []
var first_component: Node
func _initialize() -> void:
state = root.get_node("GameState")
state.reset_new_game()
state.intro_active = false
state.reset_quests()
state.vessel_levels["unlock_distorder"] = 1
state.fleet_inventory.total_capacity = -1
state.deposit_fleet_resource(GameState.RESOURCE_ENERGY, DASH_COST * 3)
main = load("res://world/Main.tscn").instantiate()
root.add_child(main)
current_scene = main
fleet = main.get_node("Fleet")
dash = main.get_node("DashController")
func _process(delta: float) -> bool:
elapsed += delta
match stage:
0:
if elapsed < 0.3:
return false
main.get_node("EnemySpawner").set_process(false)
main.get_node("AsteroidField").set_process(false)
if main.get_node("UI/DashButton").visible:
return _fail("dash button appeared without an Energy Propulser")
# The carrier keeps enough hold capacity for both dashes. Two
# Propulsers prove that cooldown belongs to a vessel, not the fleet.
fleet.spawn_ships(3, Vector2.ZERO, PackedStringArray([
GameState.VESSEL_CARRIER, GameState.VESSEL_DISTORDER,
GameState.VESSEL_DISTORDER,
]))
dash._process(0.0)
if not main.get_node("UI/DashButton").visible:
return _fail("an Energy Propulser did not reveal the dash button")
first_component = dash._next_ready_ship().get_component("distorder")
first_origin = fleet.get_centroid()
for ship in fleet.ships:
offsets_before.append(ship.position - first_origin)
_aim_and_release(Vector2.RIGHT, 11)
if not fleet.is_dashing():
return _fail("releasing a rightward aim did not begin a dash")
if state.fleet_resource(GameState.RESOURCE_ENERGY) != DASH_COST * 2:
return _fail("first dash did not consume %d energy" % DASH_COST)
if first_component.is_ready():
return _fail("the Propulser that dashed did not enter cooldown")
dash._process(0.0)
if not main.get_node("UI/DashButton").enabled:
return _fail("one cooling Propulser disabled a second ready one")
stage = 1
elapsed = 0.0
return false
1:
if elapsed < 0.7:
return false
var moved: Vector2 = fleet.get_centroid() - first_origin
if absf(moved.x - DASH_DISTANCE) > 8.0 or absf(moved.y) > 8.0:
return _fail("rightward aim moved the fleet by %s" % moved)
for i in range(fleet.ships.size()):
var offset: Vector2 = fleet.ships[i].position - fleet.get_centroid()
if offset.distance_to(offsets_before[i]) > 1.0:
return _fail("dash distorted formation slot %d by %.2f" \
% [i, offset.distance_to(offsets_before[i])])
second_origin = fleet.get_centroid()
_aim_and_release(Vector2.UP, 12)
if state.fleet_resource(GameState.RESOURCE_ENERGY) != DASH_COST:
return _fail("second Propulser did not pay for its own dash")
dash._process(0.0)
if main.get_node("UI/DashButton").enabled:
return _fail("dash remained enabled after both Propulsers fired")
stage = 2
elapsed = 0.0
return false
2:
if elapsed < 0.7:
return false
var moved: Vector2 = fleet.get_centroid() - second_origin
if absf(moved.y + DASH_DISTANCE) > 8.0 or absf(moved.x) > 8.0:
return _fail("upward aim moved the fleet by %s" % moved)
first_component.tick(first_component.DASH_COOLDOWN)
dash._process(0.0)
if not main.get_node("UI/DashButton").enabled:
return _fail("button did not re-enable when one Propulser recharged")
var surface: Node = load("res://surface/PlanetSurface.tscn").instantiate()
if not surface.has_node("DashController") or not surface.has_node("UI/DashButton"):
return _fail("planet surface does not carry the dash ability")
surface.free()
print("two aimed dashes moved %.0f units, preserved formation, and cooled down per Propulser" \
% DASH_DISTANCE)
print("TEST_ENERGY_PROPULSER_DASH: PASS")
quit(0)
return true
return false
func _aim_and_release(direction: Vector2, touch_index: int) -> void:
var button: Control = main.get_node("UI/DashButton")
var press := InputEventScreenTouch.new()
press.index = touch_index
press.pressed = true
press.position = button.global_position + button.size * 0.5
main._handle_touch(press)
var drag := InputEventScreenDrag.new()
drag.index = touch_index
drag.position = press.position + direction * 240.0
main._handle_drag(drag)
var release := InputEventScreenTouch.new()
release.index = touch_index
release.pressed = false
release.position = drag.position
main._handle_touch(release)
func _fail(message: String) -> bool:
print("TEST_ENERGY_PROPULSER_DASH: FAIL (%s)" % message)
quit(1)
return true