Remove the one-way ore API superseded by the transfer menu
The loose end from #24. withdraw_to_fleet, unload_into_building and deliver_cargo were the old one-way moves behind "Load ore" and "Store ore here"; every one of them is a special case of transfer_to_building / transfer_to_fleet, and none had a caller left outside tests. The cargo_delivered signal had no listeners at all. Not just tidying: unload_into_building routed through deposit_to_building, which does NOT special-case the mothership - it writes b.stock, while building_holdings() returns `rocks` for a mothership and ignores stock entirely. So unload_into_building( mothership_id) would have parked ore in a field nothing reads, with no error. Nothing called it that way, but it is a plausibly-named function sitting there to be reached for later. transfer_to_building handles it. CARGO_LOAD_BATCH stays - the transfer menu's batch buttons use it; only its role as withdraw_to_fleet's default argument is gone. The #24 note expected folding these in to be costly for test_cargo_readout, which places no buildings. It is not: the transfer primitives work off GameState records rather than spawned nodes, so a single add_building() in setup is enough and it stays a display test. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
fe1c721d64
commit
b6427b080d
27 changed files with 1085 additions and 275 deletions
|
|
@ -74,12 +74,34 @@ var lab_choice: int = 0
|
|||
@onready var craft_menu: Control = get_node("../UI/CraftMenu")
|
||||
@onready var craft_interceptor_button: IconButton = get_node("../UI/CraftMenu/InterceptorButton")
|
||||
@onready var craft_transporter_button: IconButton = get_node("../UI/CraftMenu/TransporterButton")
|
||||
@onready var craft_store_button: IconButton = get_node("../UI/CraftMenu/StoreOreButton")
|
||||
@onready var craft_store_label: Label = get_node("../UI/CraftMenu/StoreOreLabel")
|
||||
@onready var craft_close_button: IconButton = get_node("../UI/CraftMenu/CloseButton")
|
||||
@onready var craft_status: Label = get_node("../UI/CraftMenu/StatusLabel")
|
||||
@onready var load_ore_button: IconButton = get_node("../UI/SkillMenu/LoadOreButton")
|
||||
@onready var load_ore_label: Label = get_node("../UI/SkillMenu/LoadOreLabel")
|
||||
|
||||
# --- the transfer panel (#24) ---------------------------------------------
|
||||
# Ore used to be moved from inside whichever panel happened to be open: "load
|
||||
# ore" lived in the research screen, "store ore here" in the ship crafter.
|
||||
# Both are now one top-level button that works at every building and in both
|
||||
# directions, so moving ore is never buried under an unrelated menu.
|
||||
@onready var transfer_button: IconButton = get_node("../UI/TransferButton")
|
||||
@onready var transfer_menu: Control = get_node("../UI/TransferMenu")
|
||||
@onready var transfer_status: Label = get_node("../UI/TransferMenu/StatusLabel")
|
||||
@onready var transfer_close_button: IconButton = get_node("../UI/TransferMenu/CloseButton")
|
||||
@onready var to_building_label: Label = get_node("../UI/TransferMenu/ToBuildingLabel")
|
||||
@onready var to_building_batch_button: IconButton = get_node("../UI/TransferMenu/ToBuildingBatchButton")
|
||||
@onready var to_building_batch_label: Label = get_node("../UI/TransferMenu/ToBuildingBatchLabel")
|
||||
@onready var to_building_all_button: IconButton = get_node("../UI/TransferMenu/ToBuildingAllButton")
|
||||
@onready var to_fleet_label: Label = get_node("../UI/TransferMenu/ToFleetLabel")
|
||||
@onready var to_fleet_batch_button: IconButton = get_node("../UI/TransferMenu/ToFleetBatchButton")
|
||||
@onready var to_fleet_batch_label: Label = get_node("../UI/TransferMenu/ToFleetBatchLabel")
|
||||
@onready var to_fleet_all_button: IconButton = get_node("../UI/TransferMenu/ToFleetAllButton")
|
||||
|
||||
# Every building menu carries the same header (#24). Held as a list because
|
||||
# the only thing any of them needs is to be told which building it is
|
||||
# reporting on when its panel opens.
|
||||
@onready var resource_bars: Array = [
|
||||
get_node("../UI/CraftMenu/Bar"), get_node("../UI/SkillMenu/Bar"),
|
||||
get_node("../UI/LabMenu/Bar"), get_node("../UI/TransferMenu/Bar"),
|
||||
]
|
||||
|
||||
@onready var skill_menu: Control = get_node("../UI/SkillMenu")
|
||||
@onready var skill_tree: Control = get_node("../UI/SkillMenu/Tree")
|
||||
|
|
@ -141,6 +163,12 @@ var craft_building_id: int = 0
|
|||
var craft_message: String = ""
|
||||
var craft_message_until: int = 0
|
||||
|
||||
# Which building the transfer panel is moving ore in and out of. Remembered
|
||||
# for the same reason craft_building_id is: _process() clears
|
||||
# current_building while any menu is open, so by the next frame the panel
|
||||
# would not know which building it belongs to.
|
||||
var transfer_building_id: int = 0
|
||||
|
||||
var current_building: Node2D = null
|
||||
var pending_building: Node2D = null
|
||||
var pending_time: float = 0.0
|
||||
|
|
@ -167,11 +195,16 @@ func _ready() -> void:
|
|||
action_button.pressed.connect(_on_action_pressed)
|
||||
|
||||
craft_interceptor_button.pressed.connect(_on_craft_interceptor)
|
||||
load_ore_button.pressed.connect(_on_load_ore)
|
||||
craft_transporter_button.pressed.connect(_on_craft_transporter)
|
||||
craft_store_button.pressed.connect(_on_store_ore)
|
||||
craft_close_button.pressed.connect(func(): craft_menu.visible = false)
|
||||
|
||||
transfer_button.pressed.connect(_on_transfer_pressed)
|
||||
transfer_close_button.pressed.connect(func(): transfer_menu.visible = false)
|
||||
to_building_batch_button.pressed.connect(_on_transfer.bind(true, GameState.CARGO_LOAD_BATCH))
|
||||
to_building_all_button.pressed.connect(_on_transfer.bind(true, ALL))
|
||||
to_fleet_batch_button.pressed.connect(_on_transfer.bind(false, GameState.CARGO_LOAD_BATCH))
|
||||
to_fleet_all_button.pressed.connect(_on_transfer.bind(false, ALL))
|
||||
|
||||
formation_close_button.pressed.connect(func(): formation_menu.visible = false)
|
||||
formation_reset_button.pressed.connect(_on_reset_formation)
|
||||
formation_editor.formation_changed.connect(_on_formation_changed)
|
||||
|
|
@ -186,14 +219,16 @@ func _ready() -> void:
|
|||
formation_menu.visible = false
|
||||
skill_menu.visible = false
|
||||
lab_menu.visible = false
|
||||
transfer_menu.visible = false
|
||||
action_button.visible = false
|
||||
transfer_button.visible = false
|
||||
|
||||
|
||||
# True while a building prompt or panel owns the shared action slot, so the
|
||||
# enter-atmosphere prompt knows to stay out of the way.
|
||||
func is_showing_building_prompt() -> bool:
|
||||
return current_building != null or build_menu.visible or craft_menu.visible \
|
||||
or formation_menu.visible or skill_menu.visible
|
||||
or formation_menu.visible or skill_menu.visible or transfer_menu.visible
|
||||
|
||||
|
||||
func _unhandled_input(event: InputEvent) -> void:
|
||||
|
|
@ -218,7 +253,8 @@ func _unhandled_input(event: InputEvent) -> void:
|
|||
formation_editor.handle_drag(event)
|
||||
get_viewport().set_input_as_handled()
|
||||
return
|
||||
if build_menu.visible or craft_menu.visible or world_map.visible or lab_menu.visible:
|
||||
if build_menu.visible or craft_menu.visible or world_map.visible or lab_menu.visible \
|
||||
or transfer_menu.visible:
|
||||
# These panels have no raw-input handler of their own, but the world
|
||||
# behind them must still not react.
|
||||
get_viewport().set_input_as_handled()
|
||||
|
|
@ -239,11 +275,18 @@ func _process(delta: float) -> void:
|
|||
# the queue down instead of looking stuck.
|
||||
_refresh_craft_status()
|
||||
|
||||
if transfer_menu.visible:
|
||||
# Also live: a hauler banking ore while the panel is open should make
|
||||
# the "to fleet" side become available without a reopen.
|
||||
_refresh_transfer()
|
||||
|
||||
if world_map.visible or build_menu.visible or craft_menu.visible \
|
||||
or formation_menu.visible or skill_menu.visible or lab_menu.visible:
|
||||
or formation_menu.visible or skill_menu.visible or lab_menu.visible \
|
||||
or transfer_menu.visible:
|
||||
current_building = null
|
||||
pending_building = null
|
||||
action_button.visible = false
|
||||
transfer_button.visible = false
|
||||
return
|
||||
|
||||
# Debounced exactly like the enter-atmosphere prompt, so the action
|
||||
|
|
@ -261,6 +304,10 @@ func _process(delta: float) -> void:
|
|||
|
||||
current_building = pending_building
|
||||
action_button.visible = current_building != null
|
||||
# Every building can hold ore, so the transfer button rides alongside the
|
||||
# action button rather than being one of the things the action button
|
||||
# turns into - the two are independent choices at the same structure.
|
||||
transfer_button.visible = current_building != null
|
||||
if current_building != null:
|
||||
action_button.icon = _action_icon_for(current_building.building_type)
|
||||
action_button.queue_redraw()
|
||||
|
|
@ -292,9 +339,14 @@ func _check_fleet_wipe() -> void:
|
|||
func _on_action_pressed() -> void:
|
||||
if current_building == null:
|
||||
return
|
||||
# Whichever panel opens, its header reports on the building it was opened
|
||||
# from. Set once here rather than in each branch, so a new building menu
|
||||
# cannot forget to do it and silently show a blank HERE column.
|
||||
for bar in resource_bars:
|
||||
bar.building_id = current_building.building_id
|
||||
|
||||
if current_building.building_type == GameState.BUILDING_MOTHERSHIP:
|
||||
skill_menu.visible = true
|
||||
_refresh_load_ore()
|
||||
_refresh_skill_menu()
|
||||
elif current_building.building_type == GameState.BUILDING_SHIP_CRAFTER:
|
||||
# Remembered explicitly: _process() clears current_building while any
|
||||
|
|
@ -591,14 +643,14 @@ func _say(message: String) -> void:
|
|||
|
||||
|
||||
func _refresh_craft_status() -> void:
|
||||
# "Here" is the ore delivered to THIS crafter, not the bank: since #16 a
|
||||
# building builds out of its own stock, and showing the bank would say
|
||||
# you can afford something the crafter cannot actually make.
|
||||
# The bank/hold/here figures moved out to the shared header (#24), so this
|
||||
# line is now only what is specific to a crafter: prices, the queue, and
|
||||
# berth pressure. It used to restate "Here %d" itself, which is exactly
|
||||
# the per-panel improvisation the header replaces.
|
||||
var queued: int = GameState.pending_orders(craft_building_id)
|
||||
var stock: int = GameState.building_stock(craft_building_id)
|
||||
var queue_text: String = "" if queued == 0 else " Queued %d" % queued
|
||||
craft_status.text = "Interceptor %d Transporter %d Here %d%s Transporters %d/%d" % [
|
||||
GameState.SHIP_COST, GameState.TRANSPORTER_COST, stock, queue_text,
|
||||
craft_status.text = "Interceptor %d Transporter %d%s Transporters %d/%d" % [
|
||||
GameState.SHIP_COST, GameState.TRANSPORTER_COST, queue_text,
|
||||
GameState.transporters_claimed(), GameState.transport_capacity()
|
||||
]
|
||||
# Nowhere to station one means the order would be refused, so say so
|
||||
|
|
@ -609,12 +661,6 @@ func _refresh_craft_status() -> void:
|
|||
|
||||
craft_shield_button.enabled = GameState.shield_vessel_unlocked()
|
||||
craft_shield_button.queue_redraw()
|
||||
craft_store_label.text = "Store ore here\nHold %d" % GameState.fleet_cargo
|
||||
# Deliberately left ENABLED with an empty hold: a greyed-out button that
|
||||
# cannot say why is exactly the dead-button problem this panel already
|
||||
# had. Pressing it explains instead.
|
||||
craft_store_button.enabled = true
|
||||
craft_store_button.queue_redraw()
|
||||
|
||||
# A full fleet cannot take another vessel, so the order would be refused.
|
||||
# Showing that on the button is the difference between "not available yet"
|
||||
|
|
@ -663,17 +709,6 @@ func _on_craft_interceptor() -> void:
|
|||
_report_order(GameState.PRODUCT_SHIP)
|
||||
|
||||
|
||||
func _refresh_load_ore() -> void:
|
||||
load_ore_label.text = "Load ore\nBank %d Hold %d" % [GameState.rocks, GameState.fleet_cargo]
|
||||
load_ore_button.enabled = GameState.rocks > 0
|
||||
load_ore_button.queue_redraw()
|
||||
|
||||
|
||||
func _on_load_ore() -> void:
|
||||
GameState.withdraw_to_fleet()
|
||||
_refresh_load_ore()
|
||||
|
||||
|
||||
func _report_order(product: String) -> void:
|
||||
var short: int = GameState.outstanding_cost(craft_building_id)
|
||||
if short > 0:
|
||||
|
|
@ -684,17 +719,6 @@ func _report_order(product: String) -> void:
|
|||
_say("%s ordered - building now" % GameState.VESSEL_NAMES.get(product, product))
|
||||
|
||||
|
||||
func _on_store_ore() -> void:
|
||||
if craft_building_id == 0:
|
||||
_say("No crafter selected - reopen this panel from the building")
|
||||
return
|
||||
if GameState.fleet_cargo <= 0:
|
||||
_say("The fleet is carrying nothing - load ore at the mothership first")
|
||||
return
|
||||
var moved: int = GameState.unload_into_building(craft_building_id)
|
||||
_say("Stored %d ore here" % moved)
|
||||
|
||||
|
||||
func _on_craft_transporter() -> void:
|
||||
if craft_building_id == 0:
|
||||
_say("No crafter selected - reopen this panel from the building")
|
||||
|
|
@ -823,6 +847,86 @@ func _on_craft_shield() -> void:
|
|||
_report_order(GameState.VESSEL_SHIELD)
|
||||
|
||||
|
||||
# --- moving ore, in both directions, at any building (#24) ----------------
|
||||
|
||||
# Sentinel for the "All" buttons. The transfer primitives cap what they move
|
||||
# by what is actually there, so asking for more than could possibly exist is
|
||||
# how you say "everything" without the UI having to work out how much that
|
||||
# is first - and the answer cannot go stale between the read and the press.
|
||||
const ALL: int = 1 << 30
|
||||
|
||||
|
||||
func _on_transfer_pressed() -> void:
|
||||
if current_building == null:
|
||||
return
|
||||
transfer_building_id = current_building.building_id
|
||||
transfer_menu.visible = true
|
||||
transfer_status.text = ""
|
||||
_refresh_transfer()
|
||||
|
||||
|
||||
func _on_transfer(to_building: bool, amount: int) -> void:
|
||||
if transfer_building_id == 0:
|
||||
transfer_status.text = "No building selected - reopen this panel from the building"
|
||||
return
|
||||
|
||||
var moved: int = 0
|
||||
if to_building:
|
||||
moved = GameState.transfer_to_building(transfer_building_id, amount)
|
||||
else:
|
||||
moved = GameState.transfer_to_fleet(transfer_building_id, amount)
|
||||
|
||||
# Nothing moving is the common case at an empty end, and a silent no-op
|
||||
# is the dead-button problem this panel exists to remove. Say which side
|
||||
# was empty rather than just refusing.
|
||||
if moved <= 0:
|
||||
if to_building:
|
||||
transfer_status.text = "The fleet is carrying nothing to unload"
|
||||
else:
|
||||
transfer_status.text = "%s has no ore to load" % _transfer_place_name()
|
||||
elif to_building:
|
||||
transfer_status.text = "Moved %d ore into %s" % [moved, _transfer_place_name()]
|
||||
else:
|
||||
transfer_status.text = "Loaded %d ore into the fleet" % moved
|
||||
_refresh_transfer()
|
||||
|
||||
|
||||
func _transfer_place_name() -> String:
|
||||
var b: Dictionary = GameState.find_building(transfer_building_id)
|
||||
if b.is_empty():
|
||||
return "this building"
|
||||
if b.type == GameState.BUILDING_MOTHERSHIP:
|
||||
# Worth naming as the bank rather than as a structure: this is the
|
||||
# one building where unloading makes the ore spendable everywhere.
|
||||
return "the bank"
|
||||
return "this building"
|
||||
|
||||
|
||||
func _refresh_transfer() -> void:
|
||||
for bar in resource_bars:
|
||||
bar.building_id = transfer_building_id
|
||||
|
||||
var hold: int = GameState.fleet_cargo
|
||||
var here: int = GameState.building_holdings(transfer_building_id)
|
||||
var batch: int = GameState.CARGO_LOAD_BATCH
|
||||
|
||||
to_building_label.text = "Unload into %s" % _transfer_place_name()
|
||||
to_fleet_label.text = "Load from %s" % _transfer_place_name()
|
||||
# The batch buttons say what they would actually move, not the nominal
|
||||
# batch size: offering "25" when the hold has 4 in it is a promise the
|
||||
# press cannot keep.
|
||||
to_building_batch_label.text = "%d" % mini(batch, hold)
|
||||
to_fleet_batch_label.text = "%d" % mini(batch, here)
|
||||
|
||||
to_building_batch_button.enabled = hold > 0
|
||||
to_building_all_button.enabled = hold > 0
|
||||
to_fleet_batch_button.enabled = here > 0
|
||||
to_fleet_all_button.enabled = here > 0
|
||||
for button in [to_building_batch_button, to_building_all_button,
|
||||
to_fleet_batch_button, to_fleet_all_button]:
|
||||
button.queue_redraw()
|
||||
|
||||
|
||||
func _on_formation_changed() -> void:
|
||||
fleet.apply_formation()
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue