extends "res://ui/menus/ModalMenu.gd" # Forgejo #216: transport hubs and spacial workshops used to conjure their own # crews, free and permanent. The player orders them at a ship crafter now, and # this is where they say how many they want standing HERE. # # The menu edits the ORDER, not the crew - the same split GarrisonPanel makes # for outposts, and for the same reason: a hub that has asked for three and # been sent one is waiting, not broken, and has to read that way. # # It also answers "how long will these last". Each vessel is spent by the work # it does, so the bar row below shows what each of them has left, worst first, # which is the number that decides whether another needs building. # One bar, wide, for the vessel closest to being spent - the one that decides # whether another needs building. The per-vessel figures are listed as TEXT # below it: a row of small bars was unreadable at the size a phone draws this # menu, and "cycles left" is a number the player wants to actually read. const BAR_WIDTH: float = 420.0 const BAR_HEIGHT: float = 40.0 const BAR_TOP: float = 494.0 const WORN_COLOR: Color = Color(1.0, 0.35, 0.25) const FRESH_COLOR: Color = Color(0.5, 1.0, 0.55) const PLATE_COLOR: Color = Color(0.02, 0.02, 0.06, 0.9) const FRAME_COLOR: Color = Color(0.85, 0.96, 1.0, 0.85) @onready var title: Label = $TitleLabel @onready var assigned_label: Label = $AssignedLabel @onready var status: Label = $StatusLabel @onready var condition_label: Label = $ConditionLabel @onready var condition_list: Label = $ConditionList @onready var less_button: IconButton = $LessButton @onready var more_button: IconButton = $MoreButton var building_id: int = 0 func _ready() -> void: super._ready() # ModalMenu already owns $CloseButton and wires it. less_button.pressed.connect(func(): _step(-1)) more_button.pressed.connect(func(): _step(1)) func open_for(next_building_id: int) -> void: building_id = next_building_id open_menu() refresh() func close_menu() -> void: super.close_menu() building_id = 0 func _step(delta: int) -> void: if building_id == 0: return GameState.set_station_desired(building_id, GameState.station_desired(building_id) + delta) refresh() func refresh() -> void: if building_id == 0: return var building: Dictionary = GameState.find_building(building_id) if building.is_empty(): close_menu() return var vessel_type: String = GameState.station_vessel_type(building) var wanted: int = GameState.station_desired(building_id) var here: int = GameState.station_crew(building_id) var capacity: int = GameState.station_capacity(building) title.text = String(building.get("type", "")).to_upper().replace("_", " ") assigned_label.text = "%d / %d ASSIGNED (room for %d)" % [here, wanted, capacity] less_button.enabled = wanted > 0 more_button.enabled = wanted < capacity var name: String = GameState.vessel_name(vessel_type) if wanted == 0: status.text = "None assigned. Build %s at a ship crafter, then ask for them here." % name.to_lower() elif here >= wanted: status.text = "Fully crewed. Each one wears out with use and is not replaced by itself." else: status.text = "%d on order - sent from the mothership hangar as they are built." % (wanted - here) var left: Array = GameState.station_condition(building_id) var full: int = maxi(GameState.station_work_capacity(building_id), 1) var unit: String = "RUNS" if vessel_type == GameState.VESSEL_TRANSPORTER else "REPAIRS" if left.is_empty(): condition_label.text = "" condition_list.text = "" else: condition_label.text = "CONDITION - %s LEFT" % unit # Worst first, which is the order station_condition() answers in: the # one about to be spent is the one being decided about. var lines: PackedStringArray = PackedStringArray() for i in range(left.size()): lines.append("%s %d %d / %d %s" % [ name.to_upper(), i + 1, int(left[i]), full, unit]) condition_list.text = "\n".join(lines) queue_redraw() func _draw() -> void: if building_id == 0: return # One bar per vessel standing here, worst first: what is left of the work # it was built to do. Drawn rather than built from nodes because the count # changes as vessels arrive and wear out, and a row of bars is cheaper to # draw than to keep a pool of Controls in step with. var left: Array = GameState.station_condition(building_id) if left.is_empty(): return var full: int = maxi(GameState.station_work_capacity(building_id), 1) # The worst of them. station_condition() answers worst first. var fraction: float = clampf(float(left[0]) / float(full), 0.0, 1.0) var x: float = (size.x - BAR_WIDTH) * 0.5 draw_rect(Rect2(x - 3.0, BAR_TOP - 3.0, BAR_WIDTH + 6.0, BAR_HEIGHT + 6.0), PLATE_COLOR) draw_rect(Rect2(x, BAR_TOP, BAR_WIDTH, BAR_HEIGHT), Color(FRESH_COLOR.r, FRESH_COLOR.g, FRESH_COLOR.b, 0.16)) draw_rect(Rect2(x, BAR_TOP, BAR_WIDTH * fraction, BAR_HEIGHT), WORN_COLOR.lerp(FRESH_COLOR, fraction)) draw_rect(Rect2(x, BAR_TOP, BAR_WIDTH, BAR_HEIGHT), FRAME_COLOR, false, 2.0)