spaceship/tests/test_gas_burner_pause.gd
2026-09-03 00:12:08 +02:00

159 lines
5.8 KiB
GDScript

extends SceneTree
# Headless gameplay test: run with
# godot --headless -s res://tests/test_gas_burner_pause.gd
# Forgejo #78: a gas burner converts gas the player may want for bombs into
# energy they may not need yet, and until now it did that relentlessly - the
# only way to stop it was to demolish it.
#
# Covers:
# A. the burner offers a "pause" action, and it is its PRIMARY one, so a
# single tap on the context button toggles it rather than opening a menu
# B. a running burner converts gas into energy
# C. a paused one converts nothing, and keeps its gas
# D. resuming converts again, and the fraction of a unit already worked
# through is not thrown away
# E. the button shows what it will DO - pause bars while running, a play
# triangle while stopped
var game_state: Node
var main: Node
var controller: Node
var burner_id: int = 0
var stage: int = 0
var elapsed: float = 0.0
var gas_at_pause: int = 0
var energy_at_pause: int = 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()
main = load("res://world/Main.tscn").instantiate()
root.add_child(main)
current_scene = main
controller = main.get_node("BuildController")
func _burner() -> Dictionary:
return game_state.find_building(burner_id)
func _stock(resource_type: String) -> int:
return game_state.building_resource(burner_id, resource_type)
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)
# Through the FIELD, not GameState directly: place() both records
# the building and spawns its node, and part E needs the node.
main.get_node("BuildingField").place(GameState.BUILDING_GAS_BURNER,
Vector2(600.0, 0.0))
burner_id = int(game_state.buildings[0].id)
game_state.building_inventory(burner_id).deposit(GameState.RESOURCE_GAS, 30)
if _stock(GameState.RESOURCE_GAS) <= 0:
return _fail("could not stock the burner with gas")
# --- A. it offers pause, as its primary action ----------------
var definition: Resource = load("res://buildings/BuildingDefinitions.gd") \
.get_definition(GameState.BUILDING_GAS_BURNER)
var visual: Node = definition.visual_scene.instantiate()
var provider: Node = visual.get_node_or_null("ActionProvider")
if provider == null:
visual.free()
return _fail("the gas burner visual has no ActionProvider")
var actions: PackedStringArray = provider.actions
visual.free()
if not Array(actions).has("pause"):
return _fail("the gas burner does not offer a pause action: %s" % str(actions))
if String(actions[0]) != "pause":
return _fail("pause is not the burner's primary action (%s comes first), so it would need a menu rather than one tap" % actions[0])
print("gas burner offers pause as its primary action")
stage = 1
elapsed = 0.0
return false
1:
# --- B. running, it converts ----------------------------------
if elapsed < 5.5:
return false
if _stock(GameState.RESOURCE_ENERGY) <= 0:
return _fail("a running burner made no energy in %.1fs" % elapsed)
print("running: %d gas left, %d energy made" \
% [_stock(GameState.RESOURCE_GAS), _stock(GameState.RESOURCE_ENERGY)])
if game_state.is_building_paused(burner_id):
return _fail("the burner started out paused")
if not game_state.toggle_building_paused(burner_id):
return _fail("toggling did not pause the burner")
gas_at_pause = _stock(GameState.RESOURCE_GAS)
energy_at_pause = _stock(GameState.RESOURCE_ENERGY)
stage = 2
elapsed = 0.0
return false
2:
# --- C. paused, it does nothing -------------------------------
if elapsed < 1.5:
return false
if _stock(GameState.RESOURCE_ENERGY) != energy_at_pause:
return _fail("a paused burner made %d more energy" \
% (_stock(GameState.RESOURCE_ENERGY) - energy_at_pause))
if _stock(GameState.RESOURCE_GAS) != gas_at_pause:
return _fail("a paused burner consumed %d gas" \
% (gas_at_pause - _stock(GameState.RESOURCE_GAS)))
print("paused for %.1fs: no gas burned, no energy made" % elapsed)
# --- D. resuming works again ----------------------------------
if game_state.toggle_building_paused(burner_id):
return _fail("toggling a paused burner did not resume it")
stage = 3
elapsed = 0.0
return false
3:
if elapsed < 5.5:
return false
if _stock(GameState.RESOURCE_ENERGY) <= energy_at_pause:
return _fail("a resumed burner made no further energy")
print("resumed: energy %d -> %d" \
% [energy_at_pause, _stock(GameState.RESOURCE_ENERGY)])
# --- E. the icon reports the action, not the state ------------
var building: Node = _find_building_node()
if building == null:
return _fail("no Building node was spawned for the burner")
var running_icon: int = controller._building_action_icon(building)
game_state.set_building_paused(burner_id, true)
var paused_icon: int = controller._building_action_icon(building)
game_state.set_building_paused(burner_id, false)
if running_icon != IconButton.Icon.PAUSE:
return _fail("a running burner's button does not show the pause glyph")
if paused_icon != IconButton.Icon.RESUME:
return _fail("a paused burner's button does not show the resume glyph")
print("button shows pause while running and resume while stopped")
print("TEST_GAS_BURNER_PAUSE: PASS")
quit(0)
return true
return false
func _find_building_node() -> Node:
for node in get_nodes_in_group("buildings"):
if is_instance_valid(node) and int(node.building_id) == burner_id:
return node
return null
func _fail(message: String) -> bool:
print("TEST_GAS_BURNER_PAUSE: FAIL (%s)" % message)
quit(1)
return true