spaceship/tests/test_station_condition_readout.gd
Loïc Wisniewski 296b49c8b8 Offer only orderable vessels, and read out crew condition
A ship crafter shows what can actually be ordered there: a hull whose
research is done, and - for the support craft - one with somewhere to be
assigned. A transporter with no hub and a drone with no workshop have
nowhere to go and would sit in the hangar as spent resources, so the
structure that uses one is part of its availability. Hidden rather than
greyed, as the build menu already treats an unresearched structure, and
gated in queue_order() too so the model refuses what the menu declines to
show.

The craft buttons bound their handlers to a definition captured at startup.
With a list that changes length that is a live bug - a slot would order
whatever hull was there when the menu was built - so they bind to the slot
and resolve through the current offer.

The hub and workshop crew menus now NAME what is left in each vessel:
"TRANSPORTER 2  9 / 20 RUNS", worst first, with one wide bar for the vessel
closest to spent. The per-vessel bars they replaced drew about seven pixels
tall on a phone and carried no figure, so the number the player is deciding
on could not be read.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019AJMdB7iuHuLFZM1aBu3GD
2026-09-06 11:58:15 +02:00

95 lines
3.4 KiB
GDScript

extends SceneTree
# The hub and workshop menus name what is left in each vessel they hold.
#
# #216 gave them crews that wear out, and the whole point of that is a
# decision - "build another before this one is spent" - which the player can
# only make if they can read the figure. A bar alone said "getting low"; the
# number says how low.
#
# Covers:
# A. a hub lists every transporter it holds, worst first, with runs left
# B. a workshop says REPAIRS rather than RUNS, in its own capacity
# C. an empty structure says nothing rather than "0 / 0"
var state: Node
var scene: Node
var menu: Control
var hub_id: int
var workshop_id: int
var stage: int = 0
var elapsed: float = 0.0
func _initialize() -> void:
state = root.get_node("GameState")
state.buildings.clear()
state.extractors.clear()
state.transporters.clear()
state.repair_drones.clear()
state.reset_progression()
state.reset_new_game()
state.intro_active = false
state.reset_quests()
state.unlocked = ["shipyards", "logistics", "freight"]
hub_id = state.add_building(state.BUILDING_TRANSPORT_HUB, Vector2(900.0, 0.0))
workshop_id = state.add_building(GameState.BUILDING_WORKSHOP, Vector2(-900.0, 0.0))
scene = load("res://world/Main.tscn").instantiate()
root.add_child(scene)
current_scene = scene
menu = scene.get_node("UI/StationMenu")
func _process(delta: float) -> bool:
elapsed += delta
if elapsed < 0.3:
return false
match stage:
0:
# --- C. nothing held, nothing claimed --------------------
menu.open_for(hub_id)
if menu.condition_list.text.strip_edges() != "":
return _fail("an empty hub lists a crew: '%s'" % menu.condition_list.text)
print("an empty hub lists nothing")
# --- A. worst first, with the figure ---------------------
var staff: Script = load("res://tests/_staff.gd")
staff.staff(state, hub_id, 2)
state.transporters[0].trips_left = 4
state.transporters[1].trips_left = GameState.TRANSPORTER_TRIPS
menu.refresh()
var listed: String = menu.condition_list.text
if not listed.contains("4 / %d RUNS" % GameState.TRANSPORTER_TRIPS):
return _fail("a hub holding a worn transporter does not say so: '%s'" % listed)
if not listed.contains("%d / %d RUNS" % [GameState.TRANSPORTER_TRIPS,
GameState.TRANSPORTER_TRIPS]):
return _fail("the fresh transporter is missing from '%s'" % listed)
# Worst first: the nearly-spent one is the decision.
if listed.find("4 / ") > listed.find("%d / " % GameState.TRANSPORTER_TRIPS):
return _fail("the worn transporter is listed after the fresh one")
print("hub lists: %s" % listed.replace("\n", " | "))
elapsed = 0.0
stage = 1
return false
1:
# --- B. a workshop counts repairs, in its own capacity ----
load("res://tests/_staff.gd").staff(state, workshop_id, 1)
state.repair_drones[0].repairs_left = 3
menu.open_for(workshop_id)
var drone_text: String = menu.condition_list.text
if not drone_text.contains("3 / %d REPAIRS" % GameState.DRONE_REPAIRS):
return _fail("a workshop does not report repairs left: '%s'" % drone_text)
if drone_text.contains("RUNS"):
return _fail("a workshop reports its drones in RUNS: '%s'" % drone_text)
print("workshop lists: %s" % drone_text.replace("\n", " | "))
print("TEST_STATION_CONDITION_READOUT: PASS")
quit(0)
return true
return false
func _fail(message: String) -> bool:
print("TEST_STATION_CONDITION_READOUT: FAIL (%s)" % message)
quit(1)
return true