2026-08-12 13:07:52 +02:00
class_name ResourceBar
extends Control
# The header every building menu now carries (#24): banked ore, what the
# fleet is holding, and what THIS building has. Before this, each panel
# improvised its own - the crafter spelled the same three figures into a
# run-on StatusLabel string, the research screen printed a bank total inside
# a button caption - so the same numbers looked different in every room.
#
# Three columns rather than a sentence, because the point of the bar is that
# a figure stays in the same place as the player moves between menus.
#
# Reads GameState directly every frame, like ResourceCounter and CargoCounter
# do, so it stays correct across the space <-> planet-surface scene swap with
# nobody having to push updates into it. Only `building_id` is pushed in,
# because "here" is the one thing the bar cannot work out for itself.
# Which building the HERE column is reporting. 0 means none, which greys the
# column rather than showing a confident zero.
var building_id : int = 0
# The caption box has to be a full line tall, not just the font size: a Label
# renders its line height, not its point size, and the first version sat the
# digits 26px down from the top straight through the middle of the caption.
const CAPTION_HEIGHT : float = 34.0
const CAPTION_GAP : float = 4.0
const CAPTION_FONT_SIZE : int = 24
const DIGIT_HEIGHT : float = 34.0
# Bank keeps NeonNumber's own ore-teal, and the hold keeps the amber
# CargoCounter established for ore in transit. Only HERE needed a new colour;
# it borrows the mothership's green, which already reads as "landed
# somewhere and staying there" everywhere else in the game.
const BANK_GLOW : Color = Color ( 0.0 , 0.62 , 0.7 )
const BANK_CORE : Color = Color ( 0.0 , 0.12 , 0.15 )
const HOLD_GLOW : Color = Color ( 1.0 , 0.78 , 0.25 )
const HOLD_CORE : Color = Color ( 0.22 , 0.12 , 0.0 )
const HERE_GLOW : Color = Color ( 0.45 , 0.9 , 0.55 )
const HERE_CORE : Color = Color ( 0.05 , 0.16 , 0.08 )
const RULE_COLOR : Color = Color ( 0.25 , 0.55 , 0.7 )
var _numbers : Array [ NeonNumber ] = [ ]
var _captions : Array [ Label ] = [ ]
2026-08-13 21:07:35 +02:00
var _gas_caption : Label
2026-08-13 22:33:12 +02:00
var _gas_icon : IconButton
2026-08-13 23:02:09 +02:00
var _summary : Label
2026-08-12 13:07:52 +02:00
func _ready ( ) - > void :
mouse_filter = Control . MOUSE_FILTER_IGNORE
var columns : Array = [
[ " BANK " , BANK_GLOW , BANK_CORE ] ,
[ " HOLD " , HOLD_GLOW , HOLD_CORE ] ,
[ " HERE " , HERE_GLOW , HERE_CORE ] ,
]
for column in columns :
var caption : Label = Label . new ( )
caption . text = column [ 0 ]
caption . mouse_filter = Control . MOUSE_FILTER_IGNORE
caption . add_theme_font_size_override ( " font_size " , CAPTION_FONT_SIZE )
caption . add_theme_color_override ( " font_color " , column [ 1 ] )
add_child ( caption )
_captions . append ( caption )
var number : NeonNumber = NeonNumber . new ( )
number . mouse_filter = Control . MOUSE_FILTER_IGNORE
number . glow_color = column [ 1 ]
number . core_color = column [ 2 ]
number . digit_height = DIGIT_HEIGHT
add_child ( number )
_numbers . append ( number )
_layout ( )
resized . connect ( _layout )
2026-08-13 21:07:35 +02:00
_gas_caption = Label . new ( )
_gas_caption . mouse_filter = Control . MOUSE_FILTER_IGNORE
_gas_caption . add_theme_font_size_override ( " font_size " , 20 )
_gas_caption . add_theme_color_override ( " font_color " , Color ( 0.85 , 0.52 , 1.0 ) )
add_child ( _gas_caption )
2026-08-13 22:33:12 +02:00
_gas_icon = IconButton . new ( )
_gas_icon . mouse_filter = Control . MOUSE_FILTER_IGNORE
_gas_icon . icon = IconButton . Icon . GAS
_gas_icon . glow_color = Color ( 0.85 , 0.52 , 1.0 )
add_child ( _gas_icon )
2026-08-13 23:02:09 +02:00
_summary = Label . new ( )
_summary . mouse_filter = Control . MOUSE_FILTER_IGNORE
_summary . add_theme_font_size_override ( " font_size " , 18 )
_summary . horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
_summary . size = size
add_child ( _summary )
2026-08-12 13:07:52 +02:00
func _layout ( ) - > void :
var column_width : float = size . x / float ( _numbers . size ( ) )
for i in _numbers . size ( ) :
var x : float = column_width * float ( i )
_captions [ i ] . position = Vector2 ( x , 0.0 )
_captions [ i ] . size = Vector2 ( column_width , CAPTION_HEIGHT )
# The hexagon and digits are drawn from the node's own origin, so the
# number is positioned rather than sized.
_numbers [ i ] . position = Vector2 ( x , CAPTION_HEIGHT + CAPTION_GAP )
2026-08-13 21:07:35 +02:00
if _gas_caption != null :
_gas_caption . position = Vector2 ( size . x - 110.0 , 2.0 )
_gas_caption . size = Vector2 ( 106.0 , CAPTION_HEIGHT )
_gas_caption . horizontal_alignment = HORIZONTAL_ALIGNMENT_RIGHT
2026-08-13 22:33:12 +02:00
if _gas_icon != null :
_gas_icon . position = Vector2 ( size . x - 34.0 , 0.0 )
_gas_icon . size = Vector2 ( 32.0 , 32.0 )
_gas_caption . size . x = maxf ( 0.0 , _gas_caption . size . x - 36.0 )
2026-08-12 13:07:52 +02:00
func _process ( _delta : float ) - > void :
2026-08-13 23:02:09 +02:00
# Resource rows scale without inventing a new menu per resource. The old
# ore-only columns remain behind this concise, explicit summary.
_summary . text = " ORE Bank %d Fleet %d Local %d \n GAS Bank %d Fleet %d Local %d " % [ GameState . rocks , GameState . fleet_cargo , GameState . building_holdings ( building_id ) , GameState . gas , GameState . fleet_gas_cargo , GameState . building_gas_holdings ( building_id ) ]
for number in _numbers : number . visible = false
for caption in _captions : caption . visible = false
_gas_caption . visible = false
_gas_icon . visible = false
2026-08-13 22:17:24 +02:00
_gas_caption . text = " GAS %d / %d / %d " % [ GameState . gas , GameState . fleet_gas_cargo , GameState . building_gas_holdings ( building_id ) ]
2026-08-12 13:07:52 +02:00
_numbers [ 0 ] . set_amount ( GameState . rocks )
_numbers [ 1 ] . set_amount ( GameState . fleet_cargo )
# A building with no id is not a building: showing "0" there would claim
# the store is empty rather than that there is no store to look at.
var known : bool = building_id != 0
_numbers [ 2 ] . visible = known
_captions [ 2 ] . visible = known
if known :
_numbers [ 2 ] . set_amount ( GameState . building_holdings ( building_id ) )
# The height the bar needs for a caption line and a row of digits. The scene
# sizes the node, so this is what those offsets have to add up to; anything
# less and the rule is drawn back through the digits.
static func natural_height ( ) - > float :
return CAPTION_HEIGHT + CAPTION_GAP + DIGIT_HEIGHT + 8.0
func _draw ( ) - > void :
# One rule under the whole bar, so the header reads as a band separating
# the standing figures from whatever the panel below them does.
var rule_y : float = maxf ( size . y , natural_height ( ) )
NeonDraw . draw_glowing_line (
self , Vector2 ( 0.0 , rule_y ) , Vector2 ( size . x , rule_y ) , RULE_COLOR , 0.55 , 1.0
)