150 lines
5.6 KiB
GDScript
150 lines
5.6 KiB
GDScript
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
|
|
const DASH_SETTLE_TIME: float = 0.3
|
|
|
|
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")
|
|
# The burst should cover substantially more than a linear quarter of
|
|
# its distance at a quarter of its duration, then ease into its stop.
|
|
fleet.set_physics_process(false)
|
|
fleet._advance_dash(fleet.dash_duration * 0.25)
|
|
var early_distance: float = fleet.get_centroid().distance_to(first_origin)
|
|
if early_distance <= DASH_DISTANCE * 0.45 \
|
|
or early_distance >= DASH_DISTANCE * 0.7:
|
|
return _fail("dash has no useful ease-out curve (quarter-time distance %.1f)" \
|
|
% early_distance)
|
|
fleet.set_physics_process(true)
|
|
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 < DASH_SETTLE_TIME:
|
|
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 < DASH_SETTLE_TIME:
|
|
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")
|
|
if surface.has_node("UI/SpeedFader"):
|
|
return _fail("planet surface still carries the sustained speed multiplier")
|
|
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
|