Forgejo #13: releasing the stick paused, then moved again before settling. stop() aims each ship at a braking point ahead of it, but the ship's own velocity was ~0 - the anchor had been carrying it - so it started from REST, accelerated into its own stopping distance, and halted a second time. Measured: 0 -> 45 -> 90 -> 135 -> 180 -> brake. stop() now hands the fleet's motion to the ship, so the release is one continuous decelerating coast (222 -> 0) to the identical endpoint. test_joystick_control now asserts the speed one frame after release is a real fraction of cruise, and never rises afterwards. Forgejo #21: unresearched structures are no longer listed greyed out. They are hidden, and the menu repacks around what is left - a fixed grid with entries hidden would otherwise leave holes where they used to be. An entry alone on its row is centred rather than hanging in the left column. Researched-but-not-usable is still shown greyed: an extractor with no planet under the fleet is "not now", not "not yet". This reverses a documented decision (the old comment argued that always listing everything stops the player wondering whether the game has it at all), so test_skill_tree's matching assertion was updated from greyed-but-listed to hidden. The gate itself is unchanged and still refuses a build forced past the menu. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
135 lines
4.7 KiB
GDScript
135 lines
4.7 KiB
GDScript
extends SceneTree
|
|
|
|
# Headless gameplay test: run with
|
|
# godot --headless -s res://tests/test_build_menu_hides_locked.gd
|
|
# Forgejo #21: a structure the player has not researched should not be in the
|
|
# build menu at all, rather than sitting there greyed out.
|
|
#
|
|
# The menu is a fixed grid in Main.tscn, so simply hiding entries would leave
|
|
# holes where they used to be - it is repacked from whatever is researched.
|
|
#
|
|
# Verifies:
|
|
# 1. with nothing researched only the mothership is offered (it is
|
|
# deliberately never gated - it is where research happens)
|
|
# 2. researching a structure adds it, and it is placed, not left at
|
|
# whatever offsets it happened to have in the scene file
|
|
# 3. no gaps: what is shown occupies consecutive grid slots
|
|
# 4. an entry alone on its row is centred, not hanging in the left column
|
|
# 5. researched-but-not-usable is still shown greyed (an extractor with no
|
|
# planet under the fleet is "not now", not "not yet")
|
|
|
|
var game_state: Node
|
|
var scene: Node
|
|
var controller: Node
|
|
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.reset_progression()
|
|
game_state.rocks = 500
|
|
scene = load("res://Main.tscn").instantiate()
|
|
root.add_child(scene)
|
|
controller = scene.get_node("BuildController")
|
|
|
|
|
|
func _shown() -> Array:
|
|
var out: Array = []
|
|
for entry in controller.build_menu_entries:
|
|
if entry[1].visible:
|
|
out.append(entry)
|
|
return out
|
|
|
|
|
|
func _slots() -> Array:
|
|
# (row, x) of every visible button, in menu order.
|
|
var out: Array = []
|
|
for entry in _shown():
|
|
var b: Control = entry[1]
|
|
out.append([b.offset_top, b.offset_left + (b.offset_right - b.offset_left) / 2.0])
|
|
return out
|
|
|
|
|
|
func _process(delta: float) -> bool:
|
|
elapsed += delta
|
|
match stage:
|
|
0:
|
|
if elapsed < 0.2:
|
|
return false
|
|
scene.get_node("AsteroidField").set_process(false)
|
|
scene.get_node("EnemySpawner").set_process(false)
|
|
|
|
# --- 1. nothing researched ----------------------------------
|
|
controller._refresh_build_status()
|
|
var shown: Array = _shown()
|
|
if shown.size() != 1 or shown[0][0] != GameState.BUILDING_MOTHERSHIP:
|
|
var names: Array = []
|
|
for e in shown:
|
|
names.append(e[0])
|
|
print("TEST_BUILD_MENU_HIDES_LOCKED: FAIL (unresearched structures on offer: %s)" % [names])
|
|
quit(1)
|
|
return true
|
|
# --- 4. and it is centred, being alone on its row -----------
|
|
var only: Array = _slots()[0]
|
|
if absf(only[1]) > 0.01:
|
|
print("TEST_BUILD_MENU_HIDES_LOCKED: FAIL (the only entry sits at x=%.1f instead of centred)" % only[1])
|
|
quit(1)
|
|
return true
|
|
print("nothing researched -> only the mothership, centred")
|
|
|
|
# --- 2. research three more ---------------------------------
|
|
game_state.unlocked = ["shipyards", "logistics", "coordination"]
|
|
controller._refresh_build_status()
|
|
stage = 1
|
|
return false
|
|
1:
|
|
var shown2: Array = _shown()
|
|
if shown2.size() != 4:
|
|
print("TEST_BUILD_MENU_HIDES_LOCKED: FAIL (researched 3, expected 4 entries, got %d)" % shown2.size())
|
|
quit(1)
|
|
return true
|
|
for e in shown2:
|
|
if e[0] == GameState.BUILDING_TRANSPORT_HUB:
|
|
print("TEST_BUILD_MENU_HIDES_LOCKED: FAIL (the unresearched transport hub is still listed)")
|
|
quit(1)
|
|
return true
|
|
|
|
# --- 3. consecutive slots, no holes -------------------------
|
|
var slots: Array = _slots()
|
|
var rows: Array = controller.MENU_ROW_TOPS
|
|
for i in range(slots.size()):
|
|
var want_row: float = rows[i / 2]
|
|
if absf(slots[i][0] - want_row) > 0.01:
|
|
print("slot %d at y=%.1f, expected row %d at y=%.1f" % [i, slots[i][0], i / 2, want_row])
|
|
print("TEST_BUILD_MENU_HIDES_LOCKED: FAIL (a gap was left where a hidden entry used to be)")
|
|
quit(1)
|
|
return true
|
|
var want_x: float = -controller.MENU_COL_X if i % 2 == 0 else controller.MENU_COL_X
|
|
if absf(slots[i][1] - want_x) > 0.01:
|
|
print("TEST_BUILD_MENU_HIDES_LOCKED: FAIL (entry %d at x=%.1f, expected %.1f)" % [i, slots[i][1], want_x])
|
|
quit(1)
|
|
return true
|
|
print("4 entries packed into consecutive slots, no gaps")
|
|
|
|
# --- 5. researched but not usable is shown, greyed ----------
|
|
var extractor_shown: bool = false
|
|
for e in shown2:
|
|
if e[0] == GameState.BUILDING_EXTRACTOR:
|
|
extractor_shown = true
|
|
if e[1].enabled:
|
|
print("TEST_BUILD_MENU_HIDES_LOCKED: FAIL (extractor offered as usable with no planet under the fleet)")
|
|
quit(1)
|
|
return true
|
|
if not extractor_shown:
|
|
print("TEST_BUILD_MENU_HIDES_LOCKED: FAIL (researched extractor hidden - 'not now' is not 'not yet')")
|
|
quit(1)
|
|
return true
|
|
print("researched extractor shown but greyed, with no planet in reach")
|
|
print("TEST_BUILD_MENU_HIDES_LOCKED: PASS")
|
|
quit(0)
|
|
return true
|
|
return false
|