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. const BAR_WIDTH: float = 54.0 const BAR_HEIGHT: float = 18.0 const BAR_GAP: float = 10.0 const BAR_TOP: float = 470.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 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) condition_label.text = "CONDITION" if not left.is_empty() else "" 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) var total: float = float(left.size()) * BAR_WIDTH + float(left.size() - 1) * BAR_GAP var x: float = (size.x - total) * 0.5 for remaining in left: var fraction: float = clampf(float(remaining) / float(full), 0.0, 1.0) draw_rect(Rect2(x - 2.0, BAR_TOP - 2.0, BAR_WIDTH + 4.0, BAR_HEIGHT + 4.0), PLATE_COLOR) 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, 1.5) x += BAR_WIDTH + BAR_GAP