Transporter vessels, an explicit store button, and bottom-anchored menus
Forgejo #19, part 6 of #12. Transporters are built at the ship crafter,
fly themselves to the nearest hub and wait there. When a building is
short of what its queue needs, the nearest idle transporter runs
hub -> mothership -> building -> hub. Ore leaves the bank when it is
loaded and lands in the building's stock on arrival, so what is drawn
and what happens are the same event - the extractor hauler's rule.
Production orders are now TYPED (interceptor / transporter) rather than
a bare count, since the crafter builds two different things. One at a
time is dispatched per building: without that, every idle transporter
chases the same shortfall and they all arrive carrying ore nobody needs.
Three fixes from play-testing feedback:
- Storing ore into a building is now a deliberate button press, not a
side effect of opening the menu.
- The mothership's load-ore controls were positioned from the TOP of the
screen, so on any viewport shorter than ~1300px the label fell off the
bottom. They are anchored to the bottom edge now, and the label had no
explicit font size so it inherited the theme's 78px and wrapped off
screen. Checked at 720x960 and 720x1280.
- The craft button looked live and did nothing. It was not the transport
work: BASE_FLEET_SIZE is 5 and a new game starts with exactly 5 ships,
so the fleet is at its cap from the first frame and every interceptor
order was refused. The button is now visibly disabled and says why.
The underlying balance (crafter useless until Wing Doctrine) is left
alone - that is a design call, not a bug to quietly change.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-11 19:14:27 +02:00
|
|
|
extends SceneTree
|
|
|
|
|
|
2026-08-15 00:09:10 +02:00
|
|
|
# Hub-owned transporters supply an unfunded combat-vessel order without ever
|
|
|
|
|
# being crafted, stored at the mothership, or added to the player fleet.
|
Transporter vessels, an explicit store button, and bottom-anchored menus
Forgejo #19, part 6 of #12. Transporters are built at the ship crafter,
fly themselves to the nearest hub and wait there. When a building is
short of what its queue needs, the nearest idle transporter runs
hub -> mothership -> building -> hub. Ore leaves the bank when it is
loaded and lands in the building's stock on arrival, so what is drawn
and what happens are the same event - the extractor hauler's rule.
Production orders are now TYPED (interceptor / transporter) rather than
a bare count, since the crafter builds two different things. One at a
time is dispatched per building: without that, every idle transporter
chases the same shortfall and they all arrive carrying ore nobody needs.
Three fixes from play-testing feedback:
- Storing ore into a building is now a deliberate button press, not a
side effect of opening the menu.
- The mothership's load-ore controls were positioned from the TOP of the
screen, so on any viewport shorter than ~1300px the label fell off the
bottom. They are anchored to the bottom edge now, and the label had no
explicit font size so it inherited the theme's 78px and wrapped off
screen. Checked at 720x960 and 720x1280.
- The craft button looked live and did nothing. It was not the transport
work: BASE_FLEET_SIZE is 5 and a new game starts with exactly 5 ships,
so the fleet is at its cap from the first frame and every interceptor
order was refused. The button is now visibly disabled and says why.
The underlying balance (crafter useless until Wing Doctrine) is left
alone - that is a design call, not a bug to quietly change.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-11 19:14:27 +02:00
|
|
|
|
2026-08-15 00:09:10 +02:00
|
|
|
var state: Node
|
|
|
|
|
var crafter_id: int
|
|
|
|
|
var initial_transporters: int
|
|
|
|
|
var total_at_start: int
|
|
|
|
|
var consumed: int = 0
|
Transporter vessels, an explicit store button, and bottom-anchored menus
Forgejo #19, part 6 of #12. Transporters are built at the ship crafter,
fly themselves to the nearest hub and wait there. When a building is
short of what its queue needs, the nearest idle transporter runs
hub -> mothership -> building -> hub. Ore leaves the bank when it is
loaded and lands in the building's stock on arrival, so what is drawn
and what happens are the same event - the extractor hauler's rule.
Production orders are now TYPED (interceptor / transporter) rather than
a bare count, since the crafter builds two different things. One at a
time is dispatched per building: without that, every idle transporter
chases the same shortfall and they all arrive carrying ore nobody needs.
Three fixes from play-testing feedback:
- Storing ore into a building is now a deliberate button press, not a
side effect of opening the menu.
- The mothership's load-ore controls were positioned from the TOP of the
screen, so on any viewport shorter than ~1300px the label fell off the
bottom. They are anchored to the bottom edge now, and the label had no
explicit font size so it inherited the theme's 78px and wrapped off
screen. Checked at 720x960 and 720x1280.
- The craft button looked live and did nothing. It was not the transport
work: BASE_FLEET_SIZE is 5 and a new game starts with exactly 5 ships,
so the fleet is at its cap from the first frame and every interceptor
order was refused. The button is now visibly disabled and says why.
The underlying balance (crafter useless until Wing Doctrine) is left
alone - that is a design call, not a bug to quietly change.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-11 19:14:27 +02:00
|
|
|
var elapsed: float = 0.0
|
|
|
|
|
var conservation_broken: bool = false
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
func _initialize() -> void:
|
2026-08-15 00:09:10 +02:00
|
|
|
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 = 200
|
|
|
|
|
state.build_time_scale = 0.02
|
|
|
|
|
state.unlocked = ["shipyards", "logistics", "freight"]
|
|
|
|
|
state.add_building(state.BUILDING_MOTHERSHIP, Vector2.ZERO)
|
|
|
|
|
crafter_id = state.add_building(state.BUILDING_SHIP_CRAFTER, Vector2(900, -300))
|
|
|
|
|
|
|
|
|
|
if state.queue_order(crafter_id, state.VESSEL_TRANSPORTER):
|
|
|
|
|
return _fail("the crafter accepted a logistics transporter order")
|
|
|
|
|
var hub_id: int = state.add_building(state.BUILDING_TRANSPORT_HUB, Vector2(600, 200))
|
|
|
|
|
initial_transporters = state.hub_capacity()
|
|
|
|
|
if state.transporters.size() != initial_transporters:
|
|
|
|
|
return _fail("hub provisioned %d transporters, expected %d" % [
|
|
|
|
|
state.transporters.size(), initial_transporters])
|
|
|
|
|
for transporter in state.transporters:
|
|
|
|
|
if int(transporter.hub_id) != hub_id or transporter.state != state.TRANSPORTER_IDLE:
|
|
|
|
|
return _fail("a provisioned transporter was not idle at its hub")
|
|
|
|
|
|
|
|
|
|
var bank_before: int = state.rocks
|
|
|
|
|
if not state.queue_order(crafter_id, state.PRODUCT_SHIP):
|
|
|
|
|
return _fail("crafter refused the combat-vessel order")
|
|
|
|
|
if state.rocks != bank_before:
|
|
|
|
|
return _fail("placing the order changed the bank before a transporter loaded")
|
|
|
|
|
state.order_completed.connect(_on_order_completed)
|
|
|
|
|
total_at_start = _total()
|
Transporter vessels, an explicit store button, and bottom-anchored menus
Forgejo #19, part 6 of #12. Transporters are built at the ship crafter,
fly themselves to the nearest hub and wait there. When a building is
short of what its queue needs, the nearest idle transporter runs
hub -> mothership -> building -> hub. Ore leaves the bank when it is
loaded and lands in the building's stock on arrival, so what is drawn
and what happens are the same event - the extractor hauler's rule.
Production orders are now TYPED (interceptor / transporter) rather than
a bare count, since the crafter builds two different things. One at a
time is dispatched per building: without that, every idle transporter
chases the same shortfall and they all arrive carrying ore nobody needs.
Three fixes from play-testing feedback:
- Storing ore into a building is now a deliberate button press, not a
side effect of opening the menu.
- The mothership's load-ore controls were positioned from the TOP of the
screen, so on any viewport shorter than ~1300px the label fell off the
bottom. They are anchored to the bottom edge now, and the label had no
explicit font size so it inherited the theme's 78px and wrapped off
screen. Checked at 720x960 and 720x1280.
- The craft button looked live and did nothing. It was not the transport
work: BASE_FLEET_SIZE is 5 and a new game starts with exactly 5 ships,
so the fleet is at its cap from the first frame and every interceptor
order was refused. The button is now visibly disabled and says why.
The underlying balance (crafter useless until Wing Doctrine) is left
alone - that is a design call, not a bug to quietly change.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-11 19:14:27 +02:00
|
|
|
|
|
|
|
|
|
|
|
|
|
func _process(delta: float) -> bool:
|
|
|
|
|
elapsed += delta
|
2026-08-15 00:09:10 +02:00
|
|
|
if _total() + consumed != total_at_start:
|
Transporter vessels, an explicit store button, and bottom-anchored menus
Forgejo #19, part 6 of #12. Transporters are built at the ship crafter,
fly themselves to the nearest hub and wait there. When a building is
short of what its queue needs, the nearest idle transporter runs
hub -> mothership -> building -> hub. Ore leaves the bank when it is
loaded and lands in the building's stock on arrival, so what is drawn
and what happens are the same event - the extractor hauler's rule.
Production orders are now TYPED (interceptor / transporter) rather than
a bare count, since the crafter builds two different things. One at a
time is dispatched per building: without that, every idle transporter
chases the same shortfall and they all arrive carrying ore nobody needs.
Three fixes from play-testing feedback:
- Storing ore into a building is now a deliberate button press, not a
side effect of opening the menu.
- The mothership's load-ore controls were positioned from the TOP of the
screen, so on any viewport shorter than ~1300px the label fell off the
bottom. They are anchored to the bottom edge now, and the label had no
explicit font size so it inherited the theme's 78px and wrapped off
screen. Checked at 720x960 and 720x1280.
- The craft button looked live and did nothing. It was not the transport
work: BASE_FLEET_SIZE is 5 and a new game starts with exactly 5 ships,
so the fleet is at its cap from the first frame and every interceptor
order was refused. The button is now visibly disabled and says why.
The underlying balance (crafter useless until Wing Doctrine) is left
alone - that is a design call, not a bug to quietly change.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-11 19:14:27 +02:00
|
|
|
conservation_broken = true
|
2026-08-15 00:09:10 +02:00
|
|
|
if state.pending_orders(crafter_id) > 0:
|
|
|
|
|
if elapsed > 25.0:
|
|
|
|
|
return _fail("hub transporters never supplied the queued order")
|
|
|
|
|
return false
|
|
|
|
|
if conservation_broken:
|
|
|
|
|
return _fail("ore was created or destroyed on the automatic route")
|
|
|
|
|
if state.transporters.size() != initial_transporters:
|
|
|
|
|
return _fail("transporters accumulated during delivery")
|
|
|
|
|
if state.stored_vessels.has(state.VESSEL_TRANSPORTER):
|
|
|
|
|
return _fail("a transporter appeared in the mothership hangar")
|
|
|
|
|
print("%d hub-owned transporters supplied the crafter automatically" % initial_transporters)
|
|
|
|
|
print("TEST_TRANSPORTER_SUPPLY: PASS")
|
|
|
|
|
quit(0)
|
|
|
|
|
return true
|
Transporter vessels, an explicit store button, and bottom-anchored menus
Forgejo #19, part 6 of #12. Transporters are built at the ship crafter,
fly themselves to the nearest hub and wait there. When a building is
short of what its queue needs, the nearest idle transporter runs
hub -> mothership -> building -> hub. Ore leaves the bank when it is
loaded and lands in the building's stock on arrival, so what is drawn
and what happens are the same event - the extractor hauler's rule.
Production orders are now TYPED (interceptor / transporter) rather than
a bare count, since the crafter builds two different things. One at a
time is dispatched per building: without that, every idle transporter
chases the same shortfall and they all arrive carrying ore nobody needs.
Three fixes from play-testing feedback:
- Storing ore into a building is now a deliberate button press, not a
side effect of opening the menu.
- The mothership's load-ore controls were positioned from the TOP of the
screen, so on any viewport shorter than ~1300px the label fell off the
bottom. They are anchored to the bottom edge now, and the label had no
explicit font size so it inherited the theme's 78px and wrapped off
screen. Checked at 720x960 and 720x1280.
- The craft button looked live and did nothing. It was not the transport
work: BASE_FLEET_SIZE is 5 and a new game starts with exactly 5 ships,
so the fleet is at its cap from the first frame and every interceptor
order was refused. The button is now visibly disabled and says why.
The underlying balance (crafter useless until Wing Doctrine) is left
alone - that is a design call, not a bug to quietly change.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-11 19:14:27 +02:00
|
|
|
|
|
|
|
|
|
2026-08-15 00:09:10 +02:00
|
|
|
func _on_order_completed(_building_id: int, product: String) -> void:
|
|
|
|
|
consumed += state.product_cost(product)
|
Transporter vessels, an explicit store button, and bottom-anchored menus
Forgejo #19, part 6 of #12. Transporters are built at the ship crafter,
fly themselves to the nearest hub and wait there. When a building is
short of what its queue needs, the nearest idle transporter runs
hub -> mothership -> building -> hub. Ore leaves the bank when it is
loaded and lands in the building's stock on arrival, so what is drawn
and what happens are the same event - the extractor hauler's rule.
Production orders are now TYPED (interceptor / transporter) rather than
a bare count, since the crafter builds two different things. One at a
time is dispatched per building: without that, every idle transporter
chases the same shortfall and they all arrive carrying ore nobody needs.
Three fixes from play-testing feedback:
- Storing ore into a building is now a deliberate button press, not a
side effect of opening the menu.
- The mothership's load-ore controls were positioned from the TOP of the
screen, so on any viewport shorter than ~1300px the label fell off the
bottom. They are anchored to the bottom edge now, and the label had no
explicit font size so it inherited the theme's 78px and wrapped off
screen. Checked at 720x960 and 720x1280.
- The craft button looked live and did nothing. It was not the transport
work: BASE_FLEET_SIZE is 5 and a new game starts with exactly 5 ships,
so the fleet is at its cap from the first frame and every interceptor
order was refused. The button is now visibly disabled and says why.
The underlying balance (crafter useless until Wing Doctrine) is left
alone - that is a design call, not a bug to quietly change.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-11 19:14:27 +02:00
|
|
|
|
|
|
|
|
|
2026-08-15 00:09:10 +02:00
|
|
|
func _total() -> int:
|
|
|
|
|
var sum: int = state.rocks + state.fleet_cargo
|
|
|
|
|
for building in state.buildings:
|
|
|
|
|
if building.type != state.BUILDING_MOTHERSHIP:
|
|
|
|
|
sum += state.building_resource(int(building.id), state.RESOURCE_ORE)
|
|
|
|
|
for order in building.get("orders", []):
|
|
|
|
|
if bool(order.started):
|
|
|
|
|
sum += state.product_cost(String(order.product))
|
|
|
|
|
for transporter in state.transporters:
|
|
|
|
|
sum += int(transporter.get("carrying", 0))
|
|
|
|
|
return sum
|
Transporter vessels, an explicit store button, and bottom-anchored menus
Forgejo #19, part 6 of #12. Transporters are built at the ship crafter,
fly themselves to the nearest hub and wait there. When a building is
short of what its queue needs, the nearest idle transporter runs
hub -> mothership -> building -> hub. Ore leaves the bank when it is
loaded and lands in the building's stock on arrival, so what is drawn
and what happens are the same event - the extractor hauler's rule.
Production orders are now TYPED (interceptor / transporter) rather than
a bare count, since the crafter builds two different things. One at a
time is dispatched per building: without that, every idle transporter
chases the same shortfall and they all arrive carrying ore nobody needs.
Three fixes from play-testing feedback:
- Storing ore into a building is now a deliberate button press, not a
side effect of opening the menu.
- The mothership's load-ore controls were positioned from the TOP of the
screen, so on any viewport shorter than ~1300px the label fell off the
bottom. They are anchored to the bottom edge now, and the label had no
explicit font size so it inherited the theme's 78px and wrapped off
screen. Checked at 720x960 and 720x1280.
- The craft button looked live and did nothing. It was not the transport
work: BASE_FLEET_SIZE is 5 and a new game starts with exactly 5 ships,
so the fleet is at its cap from the first frame and every interceptor
order was refused. The button is now visibly disabled and says why.
The underlying balance (crafter useless until Wing Doctrine) is left
alone - that is a design call, not a bug to quietly change.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-11 19:14:27 +02:00
|
|
|
|
|
|
|
|
|
2026-08-15 00:09:10 +02:00
|
|
|
func _fail(message: String) -> bool:
|
|
|
|
|
print("TEST_TRANSPORTER_SUPPLY: FAIL (%s)" % message)
|
|
|
|
|
quit(1)
|
|
|
|
|
return true
|