spaceship/tests/test_propulser_upgrades.gd
Loïc Wisniewski 78836882af Sharpen upgrades, mark the convoy's destination, and give the world sound
#204 the Beam Collimator widens the beam instead of adding range to one that
already crosses the screen; beam width becomes a per-shot vessel stat.
#205 the Energy Propulser gains three upgrades - dash recharge, dash reach,
and boosted-cruise drain - which turns three constants into vessel stats.
#206 three further doctrines carry the fleet from ten to twenty.
#207 the prologue's World Ship gets a marker, through the scanner's own
guidance arrow rather than a second one.
#208 #210 #213 #214 four new synthesised sounds: the breach opening, cargo
reaching the hold, a rock breaking, and a gas bomb blooming.
#215 building health bars are larger, plated and framed.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019AJMdB7iuHuLFZM1aBu3GD
2026-09-05 12:16:17 +02:00

133 lines
5.5 KiB
GDScript

extends SceneTree
# Forgejo #205: the Energy Propulser had no upgrades at all - it was the one
# fleet hull whose ship lab offered nothing. It now carries three, and this
# checks each of them reaches the thing it is supposed to change rather than
# only reading well in the menu.
#
# Covers:
# A. Warp Coils lengthen the dash, and the controller aims that far
# B. Surge Capacitor shortens the recharge, floored by minimum_stats
# C. Flux Regulator makes boosted cruise cheaper to sustain
# D. an unupgraded Propulser is exactly what it was before
const BASE_DASH_DISTANCE: float = 520.0
const BASE_DASH_COOLDOWN: float = 5.0
const BASE_BOOST_DRAIN: float = 2.0
const COOLDOWN_FLOOR: float = 2.0
# Where three Surge Capacitors actually land. Above the floor, deliberately:
# the floor is a guard on the definition, not a target the branch reaches.
const UPGRADED_COOLDOWN: float = 2.3
var state: Node
var main: Node
var fleet: Node
var dash: Node
var stage: int = 0
var elapsed: float = 0.0
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
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 _stat(name: String) -> float:
return state.vessel_stat(GameState.VESSEL_DISTORDER, name)
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)
# --- D. nothing researched, nothing changed -------------------
if not is_equal_approx(_stat("dash_distance"), BASE_DASH_DISTANCE) \
or not is_equal_approx(_stat("dash_cooldown"), BASE_DASH_COOLDOWN) \
or not is_equal_approx(_stat("boost_drain"), BASE_BOOST_DRAIN):
return _fail("an unresearched Propulser does not match its own definition")
print("unupgraded Propulser: %.0f dash, %.1fs recharge, %.1f energy/s" \
% [_stat("dash_distance"), _stat("dash_cooldown"), _stat("boost_drain")])
# --- A. Warp Coils --------------------------------------------
state.vessel_levels["dst_dash_range"] = 3
if not is_equal_approx(_stat("dash_distance"), BASE_DASH_DISTANCE + 420.0):
return _fail("three Warp Coils gave %.0f dash distance, expected %.0f" \
% [_stat("dash_distance"), BASE_DASH_DISTANCE + 420.0])
# The controller must aim as far as the fleet can actually surge,
# or the guide promises reach the dash does not have.
if not is_equal_approx(dash._aim_max_range(), _stat("dash_distance")):
return _fail("the dash guide reaches %.0f while the dash carries %.0f" \
% [dash._aim_max_range(), _stat("dash_distance")])
print("Warp Coils: dash and its guide both reach %.0f" % _stat("dash_distance"))
# --- C. Flux Regulator ----------------------------------------
state.vessel_levels["dst_drain"] = 3
var expected_drain: float = BASE_BOOST_DRAIN * pow(0.75, 3)
if not is_equal_approx(_stat("boost_drain"), expected_drain):
return _fail("three Flux Regulators drain %.3f/s, expected %.3f" \
% [_stat("boost_drain"), expected_drain])
print("Flux Regulator: sustained boost costs %.2f energy/s" % _stat("boost_drain"))
# --- B. Surge Capacitor, and its floor ------------------------
state.vessel_levels["dst_dash_cooldown"] = 2
if not is_equal_approx(_stat("dash_cooldown"), BASE_DASH_COOLDOWN - 1.8):
return _fail("two Surge Capacitors left a %.2fs recharge, expected %.2f" \
% [_stat("dash_cooldown"), BASE_DASH_COOLDOWN - 1.8])
state.vessel_levels["dst_dash_cooldown"] = 3
if not is_equal_approx(_stat("dash_cooldown"), UPGRADED_COOLDOWN):
return _fail("three Surge Capacitors left a %.2fs recharge, expected %.2f" \
% [_stat("dash_cooldown"), UPGRADED_COOLDOWN])
# Past the branch's own maximum, to prove minimum_stats actually
# holds. Nothing in the game can buy this level; raising max_level
# later would walk straight into the floor, and this says where it
# is rather than leaving it to be discovered.
state.vessel_levels["dst_dash_cooldown"] = 6
if not is_equal_approx(_stat("dash_cooldown"), COOLDOWN_FLOOR):
return _fail("the recharge passed its %.1fs floor, reaching %.2f" \
% [COOLDOWN_FLOOR, _stat("dash_cooldown")])
state.vessel_levels["dst_dash_cooldown"] = 3
print("Surge Capacitor: %.1fs recharge at full research, floored at %.1f" \
% [UPGRADED_COOLDOWN, COOLDOWN_FLOOR])
# A hull built AFTER the research carries the researched recharge:
# apply_stats() is what puts a definition on a component, and a
# stat that never reaches the component upgrades nothing.
fleet.spawn_ships(1, Vector2.ZERO,
PackedStringArray([GameState.VESSEL_DISTORDER]))
elapsed = 0.0
stage = 1
return false
1:
if elapsed < 0.3:
return false
var component: Node = fleet.ships[0].get_component("distorder")
if component == null:
return _fail("the spawned Propulser has no distorder component")
if not is_equal_approx(component.cooldown_duration, UPGRADED_COOLDOWN):
return _fail("the hull recharges in %.2fs while its definition says %.2f" \
% [component.cooldown_duration, UPGRADED_COOLDOWN])
print("the researched recharge reaches the hull itself")
print("TEST_PROPULSER_UPGRADES: PASS")
quit(0)
return true
return false
func _fail(message: String) -> bool:
print("TEST_PROPULSER_UPGRADES: FAIL (%s)" % message)
quit(1)
return true