Add timed craft queue and hangar
This commit is contained in:
parent
b6427b080d
commit
82552464d2
14 changed files with 660 additions and 191 deletions
|
|
@ -42,6 +42,21 @@ extends Node2D
|
|||
@onready var lab_buy_button: IconButton = get_node("../UI/LabMenu/BuyButton")
|
||||
@onready var lab_close_button: IconButton = get_node("../UI/LabMenu/CloseButton")
|
||||
@onready var craft_shield_button: IconButton = get_node("../UI/CraftMenu/ShieldButton")
|
||||
@onready var queue_slots: Array = [
|
||||
get_node("../UI/CraftMenu/QueueSlot0"), get_node("../UI/CraftMenu/QueueSlot1"),
|
||||
get_node("../UI/CraftMenu/QueueSlot2"), get_node("../UI/CraftMenu/QueueSlot3"),
|
||||
]
|
||||
@onready var queue_detail: Label = get_node("../UI/CraftMenu/QueueDetail")
|
||||
@onready var hangar_button: IconButton = get_node("../UI/HangarButton")
|
||||
@onready var hangar_menu: Control = get_node("../UI/HangarMenu")
|
||||
@onready var hangar_list: Label = get_node("../UI/HangarMenu/ListLabel")
|
||||
@onready var hangar_status: Label = get_node("../UI/HangarMenu/StatusLabel")
|
||||
@onready var hangar_next_button: IconButton = get_node("../UI/HangarMenu/NextButton")
|
||||
@onready var hangar_crew_button: IconButton = get_node("../UI/HangarMenu/CrewButton")
|
||||
@onready var hangar_close_button: IconButton = get_node("../UI/HangarMenu/CloseButton")
|
||||
|
||||
# Which stored vessel the hangar is offering to crew.
|
||||
var hangar_choice: int = 0
|
||||
@onready var build_menu_entries: Array = [
|
||||
[GameState.BUILDING_MOTHERSHIP, build_mothership_button,
|
||||
get_node("../UI/BuildMenu/MothershipLabel"), get_node("../UI/BuildMenu/MothershipCost")],
|
||||
|
|
@ -199,6 +214,12 @@ func _ready() -> void:
|
|||
craft_close_button.pressed.connect(func(): craft_menu.visible = false)
|
||||
|
||||
transfer_button.pressed.connect(_on_transfer_pressed)
|
||||
hangar_button.pressed.connect(_on_hangar_pressed)
|
||||
hangar_close_button.pressed.connect(func(): hangar_menu.visible = false)
|
||||
hangar_next_button.pressed.connect(_on_hangar_next)
|
||||
hangar_crew_button.pressed.connect(_on_hangar_crew)
|
||||
for i in range(queue_slots.size()):
|
||||
queue_slots[i].pressed.connect(_on_queue_slot.bind(i))
|
||||
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))
|
||||
|
|
@ -222,13 +243,16 @@ func _ready() -> void:
|
|||
transfer_menu.visible = false
|
||||
action_button.visible = false
|
||||
transfer_button.visible = false
|
||||
hangar_button.visible = false
|
||||
hangar_menu.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 transfer_menu.visible
|
||||
or formation_menu.visible or skill_menu.visible or transfer_menu.visible \
|
||||
or hangar_menu.visible
|
||||
|
||||
|
||||
func _unhandled_input(event: InputEvent) -> void:
|
||||
|
|
@ -254,7 +278,7 @@ func _unhandled_input(event: InputEvent) -> void:
|
|||
get_viewport().set_input_as_handled()
|
||||
return
|
||||
if build_menu.visible or craft_menu.visible or world_map.visible or lab_menu.visible \
|
||||
or transfer_menu.visible:
|
||||
or transfer_menu.visible or hangar_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()
|
||||
|
|
@ -282,11 +306,12 @@ func _process(delta: float) -> void:
|
|||
|
||||
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 transfer_menu.visible:
|
||||
or transfer_menu.visible or hangar_menu.visible:
|
||||
current_building = null
|
||||
pending_building = null
|
||||
action_button.visible = false
|
||||
transfer_button.visible = false
|
||||
hangar_button.visible = false
|
||||
return
|
||||
|
||||
# Debounced exactly like the enter-atmosphere prompt, so the action
|
||||
|
|
@ -304,6 +329,10 @@ func _process(delta: float) -> void:
|
|||
|
||||
current_building = pending_building
|
||||
action_button.visible = current_building != null
|
||||
# The hangar is where finished vessels are delivered (#23), so it belongs
|
||||
# at the mothership and nowhere else.
|
||||
hangar_button.visible = current_building != null \
|
||||
and current_building.building_type == GameState.BUILDING_MOTHERSHIP
|
||||
# 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.
|
||||
|
|
@ -662,27 +691,19 @@ func _refresh_craft_status() -> void:
|
|||
craft_shield_button.enabled = GameState.shield_vessel_unlocked()
|
||||
craft_shield_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"
|
||||
# and a button that looks live and silently does nothing when pressed.
|
||||
var room: bool = fleet.ships.size() + GameState.vessels_owed.size() \
|
||||
+ GameState.pending_orders_of(craft_building_id, GameState.PRODUCT_SHIP) \
|
||||
< GameState.max_fleet_size()
|
||||
craft_interceptor_button.enabled = room
|
||||
# Fleet capacity no longer gates ORDERING (#23). A finished vessel waits
|
||||
# at the mothership until the player crews it, so a full fleet is a
|
||||
# reason not to collect one yet - not a reason the crafter cannot build.
|
||||
# This is also what stopped the crafter being inert on a fresh save,
|
||||
# where the fleet starts at exactly its cap.
|
||||
craft_interceptor_button.enabled = true
|
||||
craft_interceptor_button.queue_redraw()
|
||||
# One statement of the fleet count, either way round: the capacity line
|
||||
# replaces the plain readout rather than being bolted in front of it.
|
||||
if room:
|
||||
craft_status.text += " Fleet %d/%d" % [fleet.ships.size(), GameState.max_fleet_size()]
|
||||
else:
|
||||
var queued_ships: int = GameState.pending_orders_of(craft_building_id, GameState.PRODUCT_SHIP)
|
||||
var owed: int = GameState.vessels_owed.size() + queued_ships
|
||||
var pending_note: String = "" if owed == 0 else " (%d already on order)" % owed
|
||||
craft_status.text = "No room in the fleet: %d/%d%s - research capacity at the mothership\n%s" % [
|
||||
fleet.ships.size(), GameState.max_fleet_size(), pending_note, craft_status.text
|
||||
]
|
||||
craft_status.text += " Fleet %d/%d Ready %d" % [
|
||||
fleet.ships.size(), GameState.max_fleet_size(), GameState.stored_vessels.size()
|
||||
]
|
||||
# LAST, so a message about what just happened is the first line the
|
||||
# player reads rather than being buried under the standing state.
|
||||
_refresh_queue()
|
||||
if craft_message != "":
|
||||
if Time.get_ticks_msec() < craft_message_until:
|
||||
craft_status.text = "%s\n%s" % [craft_message, craft_status.text]
|
||||
|
|
@ -694,13 +715,6 @@ func _on_craft_interceptor() -> void:
|
|||
if craft_building_id == 0:
|
||||
_say("No crafter selected - reopen this panel from the building")
|
||||
return
|
||||
# Still refused when there is nowhere to put the vessel - queueing an
|
||||
# order that can never be delivered would just bank vessels_owed forever.
|
||||
if fleet.ships.size() + GameState.vessels_owed.size() \
|
||||
+ GameState.pending_orders_of(craft_building_id, GameState.PRODUCT_SHIP) \
|
||||
>= GameState.max_fleet_size():
|
||||
_say("Fleet is full (%d slots)" % GameState.max_fleet_size())
|
||||
return
|
||||
# No affordability check: an order the crafter cannot pay for yet is
|
||||
# QUEUED, and completes by itself once ore is delivered here (#16). But
|
||||
# queueing silently looks identical to a dead button, so it says which
|
||||
|
|
@ -839,10 +853,6 @@ func _on_craft_shield() -> void:
|
|||
if not GameState.shield_vessel_unlocked():
|
||||
_say("Shield vessels must be unlocked at a ship lab first")
|
||||
return
|
||||
if fleet.ships.size() + GameState.vessels_owed.size() \
|
||||
+ GameState.pending_orders(craft_building_id) >= GameState.max_fleet_size():
|
||||
_say("Fleet is full (%d slots)" % GameState.max_fleet_size())
|
||||
return
|
||||
GameState.queue_order(craft_building_id, GameState.VESSEL_SHIELD)
|
||||
_report_order(GameState.VESSEL_SHIELD)
|
||||
|
||||
|
|
@ -927,6 +937,115 @@ func _refresh_transfer() -> void:
|
|||
button.queue_redraw()
|
||||
|
||||
|
||||
func _refresh_queue() -> void:
|
||||
# The queue down the right of the craft panel: one slot per pending
|
||||
# vessel, the first being the one actually under construction. Tapping a
|
||||
# slot cancels it (#23).
|
||||
var orders: Array = GameState.order_list(craft_building_id)
|
||||
for i in range(queue_slots.size()):
|
||||
var slot: IconButton = queue_slots[i]
|
||||
slot.visible = i < orders.size()
|
||||
if not slot.visible:
|
||||
continue
|
||||
var order: Dictionary = orders[i]
|
||||
slot.icon = IconButton.Icon.TRANSPORT_HUB if order.product == GameState.PRODUCT_TRANSPORTER \
|
||||
else IconButton.Icon.SHIP
|
||||
slot.glow_color = _vessel_colour(String(order.product))
|
||||
# Only the one under construction reads as active; the rest are
|
||||
# waiting, and greyed says so without needing a caption each.
|
||||
slot.enabled = bool(order.started)
|
||||
slot.queue_redraw()
|
||||
|
||||
if orders.is_empty():
|
||||
queue_detail.text = "Nothing queued"
|
||||
return
|
||||
var head: Dictionary = orders[0]
|
||||
if bool(head.started):
|
||||
queue_detail.text = "Building %s %d%%\nTap to cancel" % [
|
||||
GameState.VESSEL_NAMES.get(head.product, head.product),
|
||||
int(round(float(head.progress) * 100.0)),
|
||||
]
|
||||
else:
|
||||
queue_detail.text = "%s waiting for ore\nTap to cancel" % \
|
||||
GameState.VESSEL_NAMES.get(head.product, head.product)
|
||||
|
||||
|
||||
func _vessel_colour(product: String) -> Color:
|
||||
match product:
|
||||
GameState.VESSEL_SHIELD:
|
||||
return Color(0.45, 0.8, 1.0)
|
||||
GameState.PRODUCT_TRANSPORTER:
|
||||
return Color(0.95, 0.55, 0.85)
|
||||
_:
|
||||
return Color(0.25, 0.85, 1.0)
|
||||
|
||||
|
||||
func _on_queue_slot(index: int) -> void:
|
||||
var orders: Array = GameState.order_list(craft_building_id)
|
||||
if index >= orders.size():
|
||||
return
|
||||
var vessel: String = GameState.VESSEL_NAMES.get(orders[index].product, orders[index].product)
|
||||
var refunded: bool = bool(orders[index].started)
|
||||
if not GameState.cancel_order(craft_building_id, index):
|
||||
return
|
||||
_say("%s cancelled%s" % [vessel, " - ore refunded here" if refunded else ""])
|
||||
_refresh_queue()
|
||||
|
||||
|
||||
# --- hangar (#23) ---------------------------------------------------------
|
||||
|
||||
func _on_hangar_pressed() -> void:
|
||||
hangar_choice = 0
|
||||
hangar_status.text = ""
|
||||
hangar_menu.visible = true
|
||||
_refresh_hangar()
|
||||
|
||||
|
||||
func _on_hangar_next() -> void:
|
||||
if GameState.stored_vessels.is_empty():
|
||||
return
|
||||
hangar_choice = (hangar_choice + 1) % GameState.stored_vessels.size()
|
||||
_refresh_hangar()
|
||||
|
||||
|
||||
func _on_hangar_crew() -> void:
|
||||
if GameState.stored_vessels.is_empty():
|
||||
hangar_status.text = "Nothing built yet - order vessels at a ship crafter"
|
||||
return
|
||||
if fleet.ships.size() >= GameState.max_fleet_size():
|
||||
hangar_status.text = "Fleet is full (%d/%d) - research capacity at the mothership" % [
|
||||
fleet.ships.size(), GameState.max_fleet_size()
|
||||
]
|
||||
return
|
||||
var product: String = GameState.claim_stored_vessel(hangar_choice)
|
||||
if product == "" or not fleet.add_ship(product):
|
||||
hangar_status.text = "Could not crew that vessel"
|
||||
return
|
||||
GameState.take_stored_vessel(hangar_choice)
|
||||
hangar_status.text = "%s joined the fleet" % GameState.VESSEL_NAMES.get(product, product)
|
||||
hangar_choice = 0
|
||||
_refresh_hangar()
|
||||
|
||||
|
||||
func _refresh_hangar() -> void:
|
||||
var stored: Array = GameState.stored_vessels
|
||||
if stored.is_empty():
|
||||
hangar_list.text = "No vessels waiting.\n\nOrder them at a ship crafter - finished vessels are delivered here."
|
||||
hangar_crew_button.enabled = false
|
||||
hangar_next_button.enabled = false
|
||||
else:
|
||||
hangar_choice = clampi(hangar_choice, 0, stored.size() - 1)
|
||||
var lines: Array = []
|
||||
for i in range(stored.size()):
|
||||
var marker: String = ">" if i == hangar_choice else " "
|
||||
lines.append("%s %s" % [marker, GameState.VESSEL_NAMES.get(stored[i], stored[i])])
|
||||
hangar_list.text = "\n".join(lines)
|
||||
hangar_crew_button.enabled = fleet.ships.size() < GameState.max_fleet_size()
|
||||
hangar_next_button.enabled = stored.size() > 1
|
||||
hangar_crew_button.queue_redraw()
|
||||
hangar_next_button.queue_redraw()
|
||||
|
||||
|
||||
func _on_formation_changed() -> void:
|
||||
fleet.apply_formation()
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue