163 lines
7.1 KiB
GDScript3
163 lines
7.1 KiB
GDScript3
|
|
extends SceneTree
|
||
|
|
|
||
|
|
# Headless gameplay test: run with
|
||
|
|
# godot --headless -s res://tests/test_gas_burner.gd
|
||
|
|
# Forgejo #54: gas burner building + the energy resource, stored/moved
|
||
|
|
# exactly like ore and gas.
|
||
|
|
#
|
||
|
|
# Modeled on tests/test_extractor_income.gd's shape: pure GameState state,
|
||
|
|
# no scene loaded, poking buildings/inventories directly and waiting out
|
||
|
|
# real production/transporter timing with generous margins rather than
|
||
|
|
# fixed frame counts (SceneTree physics can run ahead of _process(), trap 5
|
||
|
|
# in the repo notes).
|
||
|
|
#
|
||
|
|
# Covers:
|
||
|
|
# A. energy is fully generic - in resource_types(), has its own
|
||
|
|
# ResourceDefinition/glyph/colour - with no per-resource code anywhere
|
||
|
|
# (ResourceBar/ResourceTransferList already iterate resource_types())
|
||
|
|
# B. a burner with local gas converts it to energy, into its OWN
|
||
|
|
# inventory, at the configured rate; with no gas it stalls and never
|
||
|
|
# touches the bank
|
||
|
|
# C. the building is gated behind its own research node
|
||
|
|
# D. a hub transporter both delivers gas to a burner and collects its
|
||
|
|
# energy, following the existing supply/pickup dispatch paths
|
||
|
|
|
||
|
|
var game_state: Node
|
||
|
|
var stage: int = 0
|
||
|
|
var elapsed: float = 0.0
|
||
|
|
var mothership_id: int = 0
|
||
|
|
var hub_id: int = 0
|
||
|
|
var burner_id: int = 0
|
||
|
|
var load_limit: int = 0
|
||
|
|
var energy_before_stall: int = 0
|
||
|
|
|
||
|
|
const MOTHERSHIP_AT := Vector2.ZERO
|
||
|
|
const HUB_AT := Vector2(150.0, 0.0)
|
||
|
|
const BURNER_AT := Vector2(400.0, 0.0)
|
||
|
|
|
||
|
|
|
||
|
|
func _initialize() -> void:
|
||
|
|
game_state = root.get_node("GameState")
|
||
|
|
game_state.rocks = 0
|
||
|
|
game_state.gas = 0
|
||
|
|
game_state.buildings.clear()
|
||
|
|
game_state.extractors.clear()
|
||
|
|
game_state.transporters.clear()
|
||
|
|
game_state.reset_progression()
|
||
|
|
|
||
|
|
mothership_id = game_state.add_building(GameState.BUILDING_MOTHERSHIP, MOTHERSHIP_AT)
|
||
|
|
burner_id = game_state.add_building(GameState.BUILDING_GAS_BURNER, BURNER_AT)
|
||
|
|
game_state.deposit_resource_to_building(burner_id, GameState.RESOURCE_GAS, 20)
|
||
|
|
|
||
|
|
|
||
|
|
func _process(delta: float) -> bool:
|
||
|
|
elapsed += delta
|
||
|
|
match stage:
|
||
|
|
0:
|
||
|
|
# --- A. energy is fully generic -------------------------------
|
||
|
|
if not game_state.resource_types().has(GameState.RESOURCE_ENERGY):
|
||
|
|
return _fail("energy is not in resource_types() - the HUD/transfer list would never show it")
|
||
|
|
var definition: Resource = game_state.resource_definition(GameState.RESOURCE_ENERGY)
|
||
|
|
if definition == null or definition.glyph_scene == null:
|
||
|
|
return _fail("energy has no ResourceDefinition or glyph_scene")
|
||
|
|
var energy_color: Color = game_state.resource_color(GameState.RESOURCE_ENERGY)
|
||
|
|
if energy_color == game_state.resource_color(GameState.RESOURCE_ORE) \
|
||
|
|
or energy_color == game_state.resource_color(GameState.RESOURCE_GAS):
|
||
|
|
return _fail("energy shares a colour with ore or gas")
|
||
|
|
print("energy is generic: in resource_types(), own definition, own colour %s" % energy_color)
|
||
|
|
|
||
|
|
# --- B. produces energy from local gas at the configured rate -
|
||
|
|
if elapsed < 2.5:
|
||
|
|
return false
|
||
|
|
var gas_left: int = game_state.building_resource(burner_id, GameState.RESOURCE_GAS)
|
||
|
|
var energy_made: int = game_state.building_resource(burner_id, GameState.RESOURCE_ENERGY)
|
||
|
|
var gas_burned: int = 20 - gas_left
|
||
|
|
if gas_burned < 2:
|
||
|
|
return _fail("burner only burned %d gas in 2.5s at rate %.1f/s" % [gas_burned, GameState.GAS_BURN_RATE])
|
||
|
|
if energy_made != gas_burned * GameState.ENERGY_PER_GAS:
|
||
|
|
return _fail("burner made %d energy for %d gas burned, expected %dx" % [
|
||
|
|
energy_made, gas_burned, GameState.ENERGY_PER_GAS
|
||
|
|
])
|
||
|
|
if game_state.rocks != 0 or game_state.gas != 0:
|
||
|
|
return _fail("conversion touched the bank (rocks=%d gas=%d) - it must only use local stock" % [
|
||
|
|
game_state.rocks, game_state.gas
|
||
|
|
])
|
||
|
|
print("burner converted %d gas -> %d energy locally, bank untouched" % [gas_burned, energy_made])
|
||
|
|
|
||
|
|
# --- stall with no gas -----------------------------------------
|
||
|
|
var burner_inventory: RefCounted = game_state.building_inventory(burner_id)
|
||
|
|
burner_inventory.withdraw(GameState.RESOURCE_GAS, burner_inventory.amount(GameState.RESOURCE_GAS))
|
||
|
|
energy_before_stall = game_state.building_resource(burner_id, GameState.RESOURCE_ENERGY)
|
||
|
|
elapsed = 0.0
|
||
|
|
stage = 1
|
||
|
|
return false
|
||
|
|
1:
|
||
|
|
if elapsed < 1.5:
|
||
|
|
return false
|
||
|
|
var energy_now: int = game_state.building_resource(burner_id, GameState.RESOURCE_ENERGY)
|
||
|
|
if energy_now != energy_before_stall:
|
||
|
|
return _fail("burner made energy with no local gas (energy %d -> %d) - it must stall" % [
|
||
|
|
energy_before_stall, energy_now
|
||
|
|
])
|
||
|
|
print("stalled with no gas: energy held at %d" % energy_now)
|
||
|
|
|
||
|
|
# --- C. gated behind research -----------------------------------
|
||
|
|
if game_state.is_building_unlocked(GameState.BUILDING_GAS_BURNER):
|
||
|
|
return _fail("gas_burner is buildable with no research at all")
|
||
|
|
var gate: String = game_state.research_for_building(GameState.BUILDING_GAS_BURNER)
|
||
|
|
if gate == "":
|
||
|
|
return _fail("no research node gates gas_burner")
|
||
|
|
game_state.unlocked = ["shipyards", "logistics", "freight", "power_systems"]
|
||
|
|
if not game_state.is_building_unlocked(GameState.BUILDING_GAS_BURNER):
|
||
|
|
return _fail("still locked after researching '%s'" % gate)
|
||
|
|
print("locked behind research '%s', unlockable" % gate)
|
||
|
|
|
||
|
|
# --- D. logistics: reset for a fresh delivery/pickup test -----
|
||
|
|
game_state.buildings.clear()
|
||
|
|
game_state.transporters.clear()
|
||
|
|
game_state.gas = 200
|
||
|
|
mothership_id = game_state.add_building(GameState.BUILDING_MOTHERSHIP, MOTHERSHIP_AT)
|
||
|
|
hub_id = game_state.add_building(GameState.BUILDING_TRANSPORT_HUB, HUB_AT)
|
||
|
|
burner_id = game_state.add_building(GameState.BUILDING_GAS_BURNER, BURNER_AT)
|
||
|
|
if game_state.transporters.size() != game_state.hub_capacity():
|
||
|
|
return _fail("hub did not provision its transporters")
|
||
|
|
load_limit = game_state.transporter_load_limit()
|
||
|
|
elapsed = 0.0
|
||
|
|
stage = 2
|
||
|
|
return false
|
||
|
|
2:
|
||
|
|
# --- a transporter delivers gas to the burner ------------------
|
||
|
|
if game_state.building_resource(burner_id, GameState.RESOURCE_GAS) > 0:
|
||
|
|
print("transporter delivered gas to the burner: %d" % [
|
||
|
|
game_state.building_resource(burner_id, GameState.RESOURCE_GAS)
|
||
|
|
])
|
||
|
|
# Force the burner's local energy up to a full load so pickup
|
||
|
|
# dispatch fires immediately, rather than waiting out the
|
||
|
|
# genuinely slow conversion rate for a second, separate check.
|
||
|
|
game_state.building_inventory(burner_id).set_amount(GameState.RESOURCE_ENERGY, load_limit)
|
||
|
|
elapsed = 0.0
|
||
|
|
stage = 3
|
||
|
|
return false
|
||
|
|
if elapsed > 10.0:
|
||
|
|
return _fail("no gas was ever delivered to the burner")
|
||
|
|
return false
|
||
|
|
3:
|
||
|
|
# --- a transporter collects the burner's energy to the bank ---
|
||
|
|
if game_state.banked_resource(GameState.RESOURCE_ENERGY) >= load_limit:
|
||
|
|
print("transporter collected %d energy to the bank" % game_state.banked_resource(GameState.RESOURCE_ENERGY))
|
||
|
|
print("TEST_GAS_BURNER: PASS")
|
||
|
|
quit(0)
|
||
|
|
return true
|
||
|
|
if elapsed > 10.0:
|
||
|
|
return _fail("burner's energy was never collected (bank=%d burner=%d)" % [
|
||
|
|
game_state.banked_resource(GameState.RESOURCE_ENERGY),
|
||
|
|
game_state.building_resource(burner_id, GameState.RESOURCE_ENERGY),
|
||
|
|
])
|
||
|
|
return false
|
||
|
|
return false
|
||
|
|
|
||
|
|
|
||
|
|
func _fail(message: String) -> bool:
|
||
|
|
print("TEST_GAS_BURNER: FAIL (%s)" % message)
|
||
|
|
quit(1)
|
||
|
|
return true
|