spaceship/tests/test_ship_lab.gd

177 lines
6.4 KiB
GDScript3
Raw Normal View History

extends SceneTree
# Headless gameplay test: run with
# godot --headless -s res://tests/test_ship_lab.gd
# Forgejo #5: the ship lab researches upgrades per vessel type and unlocks
# new vessel types. The shield vessel is the first of those.
#
# Verifies:
# 1. the lab is gated behind its own research node, like every structure
# 2. upgrades cannot be bought without a lab built - it is a place you go,
# not a menu that exists once researched
# 3. buying raises the level, charges the escalating price, and stops at
# max
# 4. an upgrade improves the ships ALREADY FLYING, not just the next one
# built
# 5. the shield vessel is unlocked at the lab, and only then can the
# crafter build one
# 6. a shield vessel is what comes back from production - a typed order
# must not decay into an interceptor
# 7. upgrades are per vessel type: an interceptor upgrade does not tune
# the transporter
var game_state: Node
var scene: Node
var fleet: Node
var field: Node
var controller: Node
var crafter_id: int = 0
var stage: int = 0
var elapsed: float = 0.0
func _initialize() -> void:
game_state = root.get_node("GameState")
game_state.buildings.clear()
game_state.extractors.clear()
game_state.transporters.clear()
game_state.vessels_owed.clear()
game_state.reset_progression()
game_state.rocks = 1200
game_state.fleet_cargo = 0
scene = load("res://Main.tscn").instantiate()
root.add_child(scene)
fleet = scene.get_node("Fleet")
field = scene.get_node("BuildingField")
controller = scene.get_node("BuildController")
func _process(delta: float) -> bool:
elapsed += delta
match stage:
0:
scene.get_node("AsteroidField").set_process(false)
scene.get_node("EnemySpawner").set_process(false)
for a in get_nodes_in_group("asteroids"):
if is_instance_valid(a):
a.queue_free()
# --- 1. gated behind research -------------------------------
if game_state.is_building_unlocked(GameState.BUILDING_SHIP_LAB):
print("TEST_SHIP_LAB: FAIL (lab buildable with no research)")
quit(1)
return true
var gate: String = game_state.research_for_building(GameState.BUILDING_SHIP_LAB)
if gate == "":
print("TEST_SHIP_LAB: FAIL (no research node gates the lab)")
quit(1)
return true
print("lab gated behind '%s'" % gate)
# --- 2. no lab, no upgrades ---------------------------------
if game_state.can_buy_upgrade("int_damage"):
print("TEST_SHIP_LAB: FAIL (upgrades purchasable with no lab built)")
quit(1)
return true
if game_state.buy_upgrade("int_damage"):
print("TEST_SHIP_LAB: FAIL (bought an upgrade with no lab built)")
quit(1)
return true
print("no lab -> no upgrades")
game_state.unlocked = ["shipyards", "vessel_science", "coordination", "wing", "squadron"]
field.place(GameState.BUILDING_SHIP_LAB, Vector2(-700.0, 0.0))
field.place(GameState.BUILDING_SHIP_CRAFTER, Vector2(700.0, 0.0))
crafter_id = int(game_state.buildings[-1].id)
elapsed = 0.0
stage = 1
return false
1:
if elapsed < 0.3:
return false
# --- 3. buying raises the level and charges ------------------
var before_rocks: int = game_state.rocks
var first_cost: int = game_state.upgrade_cost("int_damage")
if not game_state.buy_upgrade("int_damage"):
print("TEST_SHIP_LAB: FAIL (could not buy an upgrade with a lab built)")
quit(1)
return true
if game_state.upgrade_level("int_damage") != 1:
print("TEST_SHIP_LAB: FAIL (level did not rise)")
quit(1)
return true
if game_state.rocks != before_rocks - first_cost:
print("TEST_SHIP_LAB: FAIL (wrong price charged)")
quit(1)
return true
var second_cost: int = game_state.upgrade_cost("int_damage")
if second_cost <= first_cost:
print("TEST_SHIP_LAB: FAIL (level 2 costs %d, no more than level 1 at %d)" % [second_cost, first_cost])
quit(1)
return true
print("bought level 1 for %d, level 2 now costs %d" % [first_cost, second_cost])
# --- 4. it reaches ships already flying ----------------------
var flying: Node = fleet.ships[0]
if flying.projectile_damage != GameState.SHIP_BASE_DAMAGE + 1:
print("TEST_SHIP_LAB: FAIL (a ship already flying still does %d damage)" % flying.projectile_damage)
quit(1)
return true
print("ship already flying now does %d damage" % flying.projectile_damage)
# --- 7. per vessel type --------------------------------------
var trn_speed_before: float = game_state.transporter_speed()
game_state.buy_upgrade("int_speed")
if game_state.transporter_speed() != trn_speed_before:
print("TEST_SHIP_LAB: FAIL (an interceptor upgrade changed the transporter)")
quit(1)
return true
print("interceptor upgrades leave the transporter alone")
# --- 5. the shield vessel is unlocked at the lab -------------
if game_state.shield_vessel_unlocked():
print("TEST_SHIP_LAB: FAIL (shield vessel available before it was unlocked)")
quit(1)
return true
if game_state.queue_order(crafter_id, GameState.VESSEL_SHIELD):
print("TEST_SHIP_LAB: FAIL (crafter took a shield order before the type was unlocked)")
quit(1)
return true
if not game_state.unlock_shield_vessel():
print("TEST_SHIP_LAB: FAIL (could not unlock the shield vessel at the lab)")
quit(1)
return true
print("shield vessel unlocked at the lab")
# --- 6. a typed order comes back as that type ----------------
fleet.spawn_ships(1, Vector2.ZERO)
if not game_state.queue_order(crafter_id, GameState.VESSEL_SHIELD):
print("TEST_SHIP_LAB: FAIL (crafter refused a shield order after unlocking)")
quit(1)
return true
game_state.deposit_to_building(crafter_id, GameState.SHIELD_COST)
elapsed = 0.0
stage = 2
return false
2:
if elapsed < 0.6:
return false
var shield_ship: Node = null
for ship in fleet.ships:
if is_instance_valid(ship) and ship.vessel_type == GameState.VESSEL_SHIELD:
shield_ship = ship
if shield_ship == null:
print("TEST_SHIP_LAB: FAIL (the shield order produced no shield vessel: %d ships, owed %s)" % [
fleet.ships.size(), game_state.vessels_owed
])
quit(1)
return true
if not shield_ship.has_shield():
print("TEST_SHIP_LAB: FAIL (the shield vessel arrived with no shield up)")
quit(1)
return true
print("shield vessel built, shield up with %d charge(s)" % shield_ship.shield_charges)
print("TEST_SHIP_LAB: PASS")
quit(0)
return true
return false