spaceship/tests/test_transporter_burn.gd
Loïc Wisniewski 265e121cb0 Build the logistics crews, and let them burn energy
#216: transport hubs and spacial workshops no longer conjure their crews.
Transporters and repair drones are ordered at a ship crafter, assigned per
building through a new Station menu, flown out from the mothership hangar,
and spent by the work they do - 20 runs, 12 repairs, counted where the run
ENDS so nothing retires with cargo in the air or a building half repaired.
A spent vessel is gone, so the structure is short again and the player has
to build another. The menu shows what each one has left, worst first.

Craftability needed its own flag: "the crafter can make it" and "it can take
a berth in the fleet" stopped being the same question.

#217: transporters crawl at 120 rather than 150, and a Burn Drive lets them
carry energy and spend it to travel far faster. Fetching it is a leg of its
own, to the nearest store that has any - so a refuelling transporter cannot
be dispatched mid-errand - and the leg flown to COLLECT fuel is not charged
for it. Unresearched, nothing detours and nothing changes.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019AJMdB7iuHuLFZM1aBu3GD
2026-09-05 19:09:35 +02:00

127 lines
5.2 KiB
GDScript

extends SceneTree
# Forgejo #217: transporters crawl by default, and a Burn Drive lets them
# carry energy and spend it to go far faster. The energy is theirs to find -
# they fetch it from the nearest store that has any - and it runs out, so the
# speed is something the player's energy supply pays for continuously rather
# than a one-off purchase.
#
# Covers:
# A. unresearched, a transporter never detours for fuel however much energy
# is lying about, and makes the base speed
# B. researched and empty, an idle one goes for the NEAREST store with
# energy in it, and takes what is there
# C. a fuelled transporter is measurably faster than an unfuelled one
# D. a leg burns a unit, and an empty tank drops it back to the crawl
# E. the leg it flies to collect fuel is not itself charged
const HUB_AT: Vector2 = Vector2(0.0, 0.0)
const NEAR_ENERGY_AT: Vector2 = Vector2(400.0, 0.0)
const FAR_ENERGY_AT: Vector2 = Vector2(-3000.0, 0.0)
var state: Node
var hub_id: int
var near_id: int
var far_id: int
func _initialize() -> void:
state = root.get_node("GameState")
state.buildings.clear()
state.extractors.clear()
state.transporters.clear()
state.stored_vessels.clear()
state.vessel_deliveries.clear()
state.reset_progression()
state.rocks = 500
state.unlocked = ["shipyards", "logistics", "freight"]
state.add_building(state.BUILDING_MOTHERSHIP, Vector2(0.0, 4000.0))
hub_id = state.add_building(state.BUILDING_TRANSPORT_HUB, HUB_AT)
near_id = state.add_building(state.BUILDING_SHIP_CRAFTER, NEAR_ENERGY_AT)
far_id = state.add_building(state.BUILDING_SHIP_LAB, FAR_ENERGY_AT)
load("res://tests/_staff.gd").staff(state, hub_id, 1)
func _initialize_done() -> void:
pass
func _process(_delta: float) -> bool:
# The bank is deliberately empty of energy, so the only sources are the
# two structures below and "nearest" is a real choice.
state.bank_inventory.set_amount(GameState.RESOURCE_ENERGY, 0)
state.deposit_resource_to_building(near_id, GameState.RESOURCE_ENERGY, 4)
state.deposit_resource_to_building(far_id, GameState.RESOURCE_ENERGY, 50)
var t: Dictionary = state.transporters[0]
# --- A. unresearched: no tank, no detour, base speed ----------------
if state.transporter_burns_energy():
return _fail("an unresearched transporter already burns energy")
var crawl: float = state.transporter_leg_speed(t)
if not is_equal_approx(crawl, state.transporter_speed()):
return _fail("an unfuelled transporter makes %.1f, expected the base %.1f" \
% [crawl, state.transporter_speed()])
state._refuel_idle_transporters()
if String(t.state) != state.TRANSPORTER_IDLE:
return _fail("an unresearched transporter went looking for fuel")
print("unresearched: no detour, %.0f base speed" % crawl)
# --- B. researched and empty: to the NEAREST store ------------------
state.vessel_levels["trn_burn"] = 1
if not state.transporter_burns_energy():
return _fail("a researched Burn Drive did not enable energy burning")
state._refuel_idle_transporters()
if String(t.state) != state.TRANSPORTER_TO_FUEL:
return _fail("an empty transporter did not go for fuel (state %s)" % t.state)
if not Vector2(t.to).is_equal_approx(NEAR_ENERGY_AT):
return _fail("it flew to %s, not the nearer store at %s" % [t.to, NEAR_ENERGY_AT])
print("researched and empty: flies to the nearest store, not the fullest")
# --- E. and the trip to collect is not itself charged ---------------
var before_fuel: int = int(t.get("fuel", 0))
state._advance_transporters(600.0)
if int(t.get("fuel", 0)) <= before_fuel:
return _fail("the transporter came back from the fuel store with nothing")
# The near store held 4, which is under the tank, so it took all of it.
if int(t.fuel) != 4:
return _fail("it drew %d energy, expected the 4 that were there" % int(t.fuel))
if state.building_resource(near_id, GameState.RESOURCE_ENERGY) != 0:
return _fail("the store it drew from still holds energy")
print("collected 4 - all the near store had - and was not charged for the trip")
# --- C. fuelled is faster -------------------------------------------
var boosted: float = state.transporter_leg_speed(t)
if boosted <= crawl:
return _fail("a fuelled transporter makes %.1f, no better than the crawl %.1f" \
% [boosted, crawl])
if not is_equal_approx(boosted, crawl * state.transporter_fuel_boost()):
return _fail("a fuelled transporter makes %.1f, expected %.1f" \
% [boosted, crawl * state.transporter_fuel_boost()])
print("fuelled: %.0f against %.0f, a %.1fx difference" \
% [boosted, crawl, state.transporter_fuel_boost()])
# --- D. and it burns down to the crawl ------------------------------
var tank: int = int(t.fuel)
for leg in range(tank):
t.state = state.TRANSPORTER_RETURNING
t.progress = 0.0
t.from = HUB_AT
t.to = NEAR_ENERGY_AT
state._advance_transporters(600.0)
if int(t.get("fuel", 0)) != 0:
return _fail("%d legs left %d energy aboard, expected an empty tank" \
% [tank, int(t.fuel)])
if not is_equal_approx(state.transporter_leg_speed(t), crawl):
return _fail("an emptied transporter did not drop back to the crawl")
print("%d legs emptied the tank and it is back to %.0f" % [tank, crawl])
print("TEST_TRANSPORTER_BURN: PASS")
quit(0)
return true
func _fail(message: String) -> bool:
print("TEST_TRANSPORTER_BURN: FAIL (%s)" % message)
quit(1)
return true