spaceship/ui/menus/StationMenu.gd

127 lines
4.9 KiB
GDScript3
Raw Normal View History

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)