124 lines
4.8 KiB
GDScript3
124 lines
4.8 KiB
GDScript3
|
|
extends SceneTree
|
||
|
|
|
||
|
|
# Headless gameplay test: run with
|
||
|
|
# godot --headless -s res://tests/test_resource_readout.gd
|
||
|
|
# Verifies ResourceReadout.gd (#49) generalizes ResourceCounter/GasCounter/
|
||
|
|
# CargoCounter/GasCargoCounter into one row per GameState.resource_types()
|
||
|
|
# entry, in both Main.tscn and PlanetSurface.tscn, with no per-resource
|
||
|
|
# code:
|
||
|
|
# 1. exactly one banked + one fleet NeonNumber per current resource type,
|
||
|
|
# each correctly reading its own resource's amount
|
||
|
|
# 2. fleet rows hide at zero and show once carried, banked rows always show
|
||
|
|
# 3. banked and fleet rows are visually distinct (colour, position)
|
||
|
|
# 4. the script itself contains no hardcoded resource id - the row count
|
||
|
|
# and mapping come entirely from GameState.resource_types()
|
||
|
|
# 5. PlanetSurface.tscn's instance renders too, with its own bright-
|
||
|
|
# background contrast
|
||
|
|
#
|
||
|
|
# A -s entry-point script can only reach the GameState autoload's CONSTANTS
|
||
|
|
# through the bare "GameState" identifier (GameState.RESOURCE_ORE etc.) -
|
||
|
|
# calling any of its METHODS that way fails to compile with "Identifier not
|
||
|
|
# found: GameState", even from _initialize(). Every other test in this suite
|
||
|
|
# already routes method calls through the actual instance
|
||
|
|
# (root.get_node("GameState")) instead, and this file follows the same rule.
|
||
|
|
|
||
|
|
var game_state: Node
|
||
|
|
var main: Node
|
||
|
|
var readout: Node
|
||
|
|
var stage: int = 0
|
||
|
|
var elapsed: float = 0.0
|
||
|
|
|
||
|
|
|
||
|
|
func _initialize() -> void:
|
||
|
|
game_state = root.get_node("GameState")
|
||
|
|
game_state.bank_inventory.set_amount(GameState.RESOURCE_ORE, 11)
|
||
|
|
game_state.bank_inventory.set_amount(GameState.RESOURCE_GAS, 4)
|
||
|
|
game_state.fleet_inventory.set_amount(GameState.RESOURCE_ORE, 6)
|
||
|
|
# Gas left at 0 in the fleet hold deliberately, to check the hide-at-zero
|
||
|
|
# rule holds per-resource, not just per-readout.
|
||
|
|
|
||
|
|
# --- 4. no hardcoded resource id in the generalized script ---
|
||
|
|
var source: String = FileAccess.get_file_as_string("res://ResourceReadout.gd")
|
||
|
|
for literal in ['"ore"', '"gas"', 'RESOURCE_ORE', 'RESOURCE_GAS']:
|
||
|
|
if literal in source:
|
||
|
|
return _fail("ResourceReadout.gd hardcodes %s - it must read GameState.resource_types() only" % literal)
|
||
|
|
|
||
|
|
main = load("res://Main.tscn").instantiate()
|
||
|
|
root.add_child(main)
|
||
|
|
readout = main.get_node("UI/ResourceReadout")
|
||
|
|
|
||
|
|
|
||
|
|
func _process(delta: float) -> bool:
|
||
|
|
elapsed += delta
|
||
|
|
match stage:
|
||
|
|
0:
|
||
|
|
if elapsed < 0.2:
|
||
|
|
return false
|
||
|
|
|
||
|
|
# --- 1. one row per resource type, correctly mapped ---
|
||
|
|
var types: PackedStringArray = game_state.resource_types()
|
||
|
|
for resource_type in types:
|
||
|
|
var banked: Node = readout.banked_number(resource_type)
|
||
|
|
var fleet: Node = readout.fleet_number(resource_type)
|
||
|
|
if banked == null or fleet == null:
|
||
|
|
return _fail("no readout row for resource '%s'" % resource_type)
|
||
|
|
if banked.amount != game_state.banked_resource(resource_type):
|
||
|
|
return _fail("banked row for '%s' shows %d, bank has %d" % [
|
||
|
|
resource_type, banked.amount, game_state.banked_resource(resource_type)
|
||
|
|
])
|
||
|
|
|
||
|
|
# --- 2. hide-at-zero is per resource ---
|
||
|
|
var ore_fleet: Node = readout.fleet_number(GameState.RESOURCE_ORE)
|
||
|
|
var gas_fleet: Node = readout.fleet_number(GameState.RESOURCE_GAS)
|
||
|
|
if not ore_fleet.visible:
|
||
|
|
return _fail("fleet ore is 6 but its row is hidden")
|
||
|
|
if gas_fleet.visible:
|
||
|
|
return _fail("fleet gas is 0 but its row is showing")
|
||
|
|
if ore_fleet.amount != 6:
|
||
|
|
return _fail("fleet ore row shows %d, hold has 6" % ore_fleet.amount)
|
||
|
|
|
||
|
|
# --- 3. banked and fleet are visually distinct ---
|
||
|
|
var ore_banked: Node = readout.banked_number(GameState.RESOURCE_ORE)
|
||
|
|
if ore_banked.glow_color == ore_fleet.glow_color:
|
||
|
|
return _fail("banked and fleet rows share a colour")
|
||
|
|
if ore_banked.position == ore_fleet.position:
|
||
|
|
return _fail("banked and fleet rows share a position")
|
||
|
|
|
||
|
|
# Depositing gas into the fleet hold should reveal its row live.
|
||
|
|
game_state.fleet_inventory.deposit(GameState.RESOURCE_GAS, 3)
|
||
|
|
elapsed = 0.0
|
||
|
|
stage = 1
|
||
|
|
return false
|
||
|
|
1:
|
||
|
|
if elapsed < 0.2:
|
||
|
|
return false
|
||
|
|
var gas_fleet: Node = readout.fleet_number(GameState.RESOURCE_GAS)
|
||
|
|
if not gas_fleet.visible or gas_fleet.amount != 3:
|
||
|
|
return _fail("fleet gas row did not update live after a deposit (visible=%s amount=%d)" % [
|
||
|
|
gas_fleet.visible, gas_fleet.amount
|
||
|
|
])
|
||
|
|
|
||
|
|
# --- 5. the surface scene's instance also works, bright-background ---
|
||
|
|
main.free()
|
||
|
|
var surface: Node = load("res://PlanetSurface.tscn").instantiate()
|
||
|
|
root.add_child(surface)
|
||
|
|
var surface_readout: Node = surface.get_node("UI/ResourceReadout")
|
||
|
|
if not surface_readout.bright_background:
|
||
|
|
surface.free()
|
||
|
|
return _fail("PlanetSurface's ResourceReadout instance is not set to bright_background")
|
||
|
|
elapsed = 0.0
|
||
|
|
stage = 2
|
||
|
|
return false
|
||
|
|
2:
|
||
|
|
if elapsed < 0.2:
|
||
|
|
return false
|
||
|
|
print("TEST_RESOURCE_READOUT: PASS")
|
||
|
|
quit(0)
|
||
|
|
return true
|
||
|
|
return false
|
||
|
|
|
||
|
|
|
||
|
|
func _fail(message: String) -> bool:
|
||
|
|
print("TEST_RESOURCE_READOUT: FAIL (%s)" % message)
|
||
|
|
quit(1)
|
||
|
|
return true
|