159 lines
5.8 KiB
GDScript3
159 lines
5.8 KiB
GDScript3
|
|
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://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://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 < 1.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 < 1.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
|