#95: stop printing the bank twice in the research menu

The research table's LOCAL column was not merely equal to BANKED, it was the
same store: research lives on the mothership, the mothership is also the
bank, and building_inventory() redirects any bank-capable building to
bank_inventory itself. ResourceBar now drops LOCAL wherever it resolves to
the bank and lets the remaining two columns share the width. Anywhere else -
a crafter, a lab, the transfer panel - the column is untouched.

The "Research" heading went with it. It named a panel you can only reach by
pressing the research button, and it cost the tree canvas 128px, which the
table and the tree have now taken back.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Loïc Wisniewski 2026-08-23 11:35:01 +02:00
commit 5f1b5a9b29
3 changed files with 205 additions and 19 deletions

View file

@ -25,6 +25,11 @@ const LOCAL_COLOR: Color = Color(0.45, 0.9, 0.55)
var _header_labels: Array[Label] = []
var _rows: Dictionary = {}
# The value columns, in the order they are drawn. LOCAL is dropped from this
# list at a building that IS the bank - see _local_is_banked().
const VALUE_KEYS: Array = ["bank", "fleet", "local"]
var _local_shown: bool = true
func _ready() -> void:
mouse_filter = Control.MOUSE_FILTER_IGNORE
@ -74,15 +79,38 @@ func _make_value_label(colour: Color) -> Label:
return label
# #95: at a building that IS the bank - the mothership carries both the "bank"
# and the "research" capability, so the research menu is always opened from one
# - building_inventory() redirects to bank_inventory itself, and LOCAL is not
# merely equal to BANKED but the very same store read twice. Printing the
# number again teaches nothing and costs a third of the table, so the column
# goes away there and the remaining two share the width.
func _local_is_banked() -> bool:
if building_id == 0:
return false
return GameState.building_inventory(building_id) == GameState.bank_inventory
func _visible_value_keys() -> Array:
return VALUE_KEYS if _local_shown else VALUE_KEYS.slice(0, 2)
func _layout() -> void:
if _header_labels.is_empty():
return
var keys: Array = _visible_value_keys()
var resource_width: float = size.x * 0.25
var value_width: float = (size.x - resource_width) / 3.0
var columns: Array = [0.0, resource_width, resource_width + value_width,
resource_width + value_width * 2.0]
var widths: Array = [resource_width, value_width, value_width, value_width]
var value_width: float = (size.x - resource_width) / float(keys.size())
var columns: Array = [0.0]
var widths: Array = [resource_width]
for i in range(keys.size()):
columns.append(resource_width + value_width * float(i))
widths.append(value_width)
for i in range(_header_labels.size()):
var shown: bool = i < columns.size()
_header_labels[i].visible = shown
if not shown:
continue
_header_labels[i].position = Vector2(columns[i], 0.0)
_header_labels[i].size = Vector2(widths[i], HEADER_HEIGHT)
@ -100,8 +128,11 @@ func _layout() -> void:
row.glyph.size = Vector2(content_height, content_height)
row.name.position = Vector2(content_height + 10.0, y)
row.name.size = Vector2(resource_width - content_height - 10.0, row_height)
for i in range(3):
var label: Label = row[["bank", "fleet", "local"][i]]
for i in range(VALUE_KEYS.size()):
var label: Label = row[VALUE_KEYS[i]]
label.visible = i < keys.size()
if not label.visible:
continue
label.position = Vector2(columns[i + 1], y)
label.size = Vector2(widths[i + 1], row_height)
row_index += 1
@ -109,6 +140,12 @@ func _layout() -> void:
func _process(_delta: float) -> void:
# building_id is assigned by whichever panel opens, so the column count can
# change between frames; re-lay out only when it actually flips.
var local_shown: bool = not _local_is_banked()
if local_shown != _local_shown:
_local_shown = local_shown
_layout()
for resource_type in GameState.resource_types():
var row: Dictionary = _rows.get(resource_type, {})
if row.is_empty():