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 < 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