Charge more for each berth, and show the bill
#220: every berth past the first paid one costs 1.12x the one before it, on top of the flat per-vessel charge. A linear bill makes the tenth hull no more of a decision than the second; compounding weighs each addition against the whole fleet behind it. Shallow on purpose - the thirteenth berth costs about three and a half times the second, the twentieth about seven and a half. Fleet Offices gain a menu naming the whole bill per minute, a line per paying berth with its multiplier, and the arithmetic in words. It renders fleet_upkeep_breakdown(), which is the calculation the charging loop itself runs: a readout that summed independently could quote a bill the game does not take, which is the thing worth preventing here. The test pins that what the menu quotes for a berth is what that office is charged. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019AJMdB7iuHuLFZM1aBu3GD
This commit is contained in:
parent
cc71811d89
commit
2bb46cba94
9 changed files with 369 additions and 5 deletions
|
|
@ -8,4 +8,4 @@ script = ExtResource("1")
|
|||
|
||||
[node name="ActionProvider" type="Node" parent="."]
|
||||
script = ExtResource("2")
|
||||
actions = PackedStringArray("transfer")
|
||||
actions = PackedStringArray("upkeep", "transfer")
|
||||
|
|
|
|||
|
|
@ -34,6 +34,8 @@ const HUD_ROW_GAP := 16.0
|
|||
@onready var garrison_menu: Control = get_node("../UI/GarrisonMenu")
|
||||
# #216: where a hub or a workshop is told how many craft to keep.
|
||||
@onready var station_menu: Control = get_node("../UI/StationMenu")
|
||||
# #220: what the fleet costs to keep, and the arithmetic behind it.
|
||||
@onready var upkeep_menu: Control = get_node("../UI/FleetUpkeepMenu")
|
||||
@onready var scanner_menu: Control = get_node("../UI/ScannerMenu")
|
||||
|
||||
var pending_build_type: String = ""
|
||||
|
|
@ -114,7 +116,7 @@ func _seat_hud_columns() -> void:
|
|||
func _menu_is_open() -> bool:
|
||||
for menu in [build_menu, craft_menu, lab_menu, transfer_menu, hangar_menu,
|
||||
formation_menu, skill_menu, planning_menu, garrison_menu, scanner_menu,
|
||||
station_menu]:
|
||||
station_menu, upkeep_menu]:
|
||||
if menu.visible:
|
||||
return true
|
||||
return false
|
||||
|
|
@ -319,6 +321,8 @@ func _on_action_pressed() -> void:
|
|||
scanner_menu.open_menu()
|
||||
elif building_action == "staff":
|
||||
station_menu.open_for(building_id)
|
||||
elif building_action == "upkeep":
|
||||
upkeep_menu.open_for(building_id)
|
||||
|
||||
|
||||
func _on_scan_requested(definition_id: String) -> void:
|
||||
|
|
@ -797,6 +801,7 @@ func _layout_hangar() -> void:
|
|||
func _refresh_garrison() -> void:
|
||||
garrison_menu.refresh()
|
||||
station_menu.refresh()
|
||||
upkeep_menu.refresh()
|
||||
|
||||
|
||||
func _refresh_planning() -> void:
|
||||
|
|
|
|||
|
|
@ -776,6 +776,16 @@ signal fleet_upkeep_failed(slot_index: int, vessel_type: String)
|
|||
# ticket asks for and needs no second table to fall out of step with.
|
||||
const FLEET_OFFICE_UPKEEP_SECONDS: float = 25.0
|
||||
const FLEET_OFFICE_UPKEEP_DIVISOR: int = 8
|
||||
# #220: and each berth costs more than the one before it. A flat per-vessel
|
||||
# charge means a big fleet is only linearly harder to keep, so the tenth hull
|
||||
# is no more of a decision than the second; compounding makes every addition
|
||||
# weigh against the whole fleet behind it.
|
||||
#
|
||||
# Deliberately shallow - the ticket asks for a slow one. At 1.12 the thirteenth
|
||||
# berth costs about three and a half times the second, and the twentieth about
|
||||
# seven and a half. A steeper rate reaches "unaffordable" while the player is
|
||||
# still learning what the fleet is for.
|
||||
const FLEET_UPKEEP_GROWTH: float = 1.12
|
||||
|
||||
|
||||
# Offices in the order they were built, which is the order they are matched to
|
||||
|
|
@ -800,16 +810,62 @@ func supplied_fleet_office_count() -> int:
|
|||
# What one berth costs per charge, for the vessel actually sitting in it. An
|
||||
# empty answer means this vessel is free to keep - which is true of nothing
|
||||
# the crafter builds, and is what an unknown type falls back to.
|
||||
func fleet_office_upkeep(vessel_type: String) -> Dictionary:
|
||||
# What one berth costs per charge. `slot_index` is the fleet position it
|
||||
# keeps, so the first berth past the free one pays the base rate and every
|
||||
# berth after it pays the compounded one (#220).
|
||||
func fleet_office_upkeep(vessel_type: String, slot_index: int = BASE_FLEET_SIZE) -> Dictionary:
|
||||
var upkeep: Dictionary = {}
|
||||
var scale: float = fleet_upkeep_scale(slot_index)
|
||||
for resource_type in product_costs(vessel_type):
|
||||
var share: int = int(ceil(float(product_costs(vessel_type)[resource_type])
|
||||
/ float(FLEET_OFFICE_UPKEEP_DIVISOR)))
|
||||
/ float(FLEET_OFFICE_UPKEEP_DIVISOR) * scale))
|
||||
if share > 0:
|
||||
upkeep[resource_type] = share
|
||||
return upkeep
|
||||
|
||||
|
||||
# The multiplier on a berth at this fleet position. The free hull and the
|
||||
# first paid berth both sit at 1.0, so the curve starts where the charging
|
||||
# starts rather than partway up it.
|
||||
func fleet_upkeep_scale(slot_index: int) -> float:
|
||||
return pow(FLEET_UPKEEP_GROWTH, maxi(slot_index - BASE_FLEET_SIZE, 0))
|
||||
|
||||
|
||||
# The whole bill, berth by berth, for the readout #220 asks for: what each
|
||||
# one is keeping, what it is charged, and what that is per minute. Computed
|
||||
# here rather than in the menu so the numbers shown are the numbers charged -
|
||||
# a readout that recomputes them separately can disagree with the loop that
|
||||
# actually takes the resources.
|
||||
func fleet_upkeep_breakdown() -> Dictionary:
|
||||
var berths: Array = []
|
||||
var per_minute: Dictionary = {}
|
||||
var charges_per_minute: float = 60.0 / FLEET_OFFICE_UPKEEP_SECONDS
|
||||
var offices: Array = fleet_offices()
|
||||
for i in range(offices.size()):
|
||||
var slot_index: int = i + BASE_FLEET_SIZE
|
||||
var vessel_type: String = fleet_office_vessel(slot_index)
|
||||
if vessel_type == "":
|
||||
continue # a berth standing empty is charged nothing
|
||||
var costs: Dictionary = fleet_office_upkeep(vessel_type, slot_index)
|
||||
berths.append({
|
||||
"slot": slot_index + 1,
|
||||
"vessel_type": vessel_type,
|
||||
"scale": fleet_upkeep_scale(slot_index),
|
||||
"costs": costs,
|
||||
"starved": bool(offices[i].get("starved", false)),
|
||||
})
|
||||
for resource_type in costs:
|
||||
per_minute[resource_type] = float(per_minute.get(resource_type, 0.0)) \
|
||||
+ float(costs[resource_type]) * charges_per_minute
|
||||
return {
|
||||
"berths": berths,
|
||||
"per_minute": per_minute,
|
||||
"charge_seconds": FLEET_OFFICE_UPKEEP_SECONDS,
|
||||
"divisor": FLEET_OFFICE_UPKEEP_DIVISOR,
|
||||
"growth": FLEET_UPKEEP_GROWTH,
|
||||
}
|
||||
|
||||
|
||||
# The vessel an office is answerable for, or "" when the fleet is smaller than
|
||||
# the berths built for it - an office with nothing in it costs nothing.
|
||||
func fleet_office_vessel(slot_index: int) -> String:
|
||||
|
|
@ -841,7 +897,8 @@ func _advance_fleet_office_upkeep(delta: float) -> void:
|
|||
office.upkeep_progress = progress
|
||||
continue
|
||||
office.upkeep_progress = progress - FLEET_OFFICE_UPKEEP_SECONDS
|
||||
var upkeep: Dictionary = fleet_office_upkeep(vessel_type)
|
||||
var upkeep: Dictionary = fleet_office_upkeep(vessel_type,
|
||||
i + BASE_FLEET_SIZE)
|
||||
var inventory: RefCounted = _inventory_for_record(office)
|
||||
var affordable: bool = true
|
||||
for resource_type in upkeep:
|
||||
|
|
|
|||
34
tests/_fleet_upkeep_preview.gd
Normal file
34
tests/_fleet_upkeep_preview.gd
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
extends Node2D
|
||||
|
||||
# Preview, not a test - #220's upkeep readout with a fleet worth reading:
|
||||
# several berths of different hulls, so the per-berth lines, the compounding
|
||||
# multiplier and the per-minute total all have something to show.
|
||||
#
|
||||
# bash tests/screenshot.sh res://tests/_fleet_upkeep_preview.tscn shots/fleet_upkeep.png 3 720x1280
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
GameState.buildings.clear()
|
||||
GameState.extractors.clear()
|
||||
GameState.transporters.clear()
|
||||
GameState.reset_progression()
|
||||
GameState.intro_active = false
|
||||
GameState.add_building(GameState.BUILDING_MOTHERSHIP, Vector2.ZERO)
|
||||
var office_ids: Array = []
|
||||
for i in range(5):
|
||||
office_ids.append(GameState.add_building(GameState.BUILDING_FLEET_OFFICE,
|
||||
Vector2(400.0 * float(i + 1), 300.0)))
|
||||
var main: Node = load("res://world/Main.tscn").instantiate()
|
||||
add_child(main)
|
||||
main.get_node("AsteroidField").set_process(false)
|
||||
main.get_node("EnemySpawner").set_process(false)
|
||||
# Spawned for real rather than by writing fleet_vessel_types directly: the
|
||||
# Fleet rewrites that from what is actually flying the moment it composes
|
||||
# itself, so a value set beforehand is discarded.
|
||||
main.get_node("Fleet").spawn_ships(6, Vector2.ZERO, PackedStringArray([
|
||||
GameState.VESSEL_INTERCEPTOR, GameState.VESSEL_LASER,
|
||||
GameState.VESSEL_GAS_BOMBER, GameState.VESSEL_DISTORDER,
|
||||
GameState.VESSEL_LASER, GameState.VESSEL_SHIELD]))
|
||||
# One office left unsupplied, so the unpaid marker is visible too.
|
||||
GameState.find_building(int(office_ids[3])).starved = true
|
||||
main.get_node("UI/FleetUpkeepMenu").open_for(int(office_ids[0]))
|
||||
6
tests/_fleet_upkeep_preview.tscn
Normal file
6
tests/_fleet_upkeep_preview.tscn
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
[gd_scene load_steps=2 format=3]
|
||||
|
||||
[ext_resource type="Script" path="res://tests/_fleet_upkeep_preview.gd" id="1"]
|
||||
|
||||
[node name="FleetUpkeepPreview" type="Node2D"]
|
||||
script = ExtResource("1")
|
||||
111
tests/test_fleet_upkeep_scaling.gd
Normal file
111
tests/test_fleet_upkeep_scaling.gd
Normal file
|
|
@ -0,0 +1,111 @@
|
|||
extends SceneTree
|
||||
|
||||
# Forgejo #220: the fleet costs more per hull as it grows, and the Fleet
|
||||
# Office says so with the arithmetic shown.
|
||||
#
|
||||
# The interesting failure is not "the sum is wrong" - it is the readout and
|
||||
# the charging loop drifting apart, so the menu quotes a bill the game does
|
||||
# not take. So what is checked is that the SAME numbers come out of both.
|
||||
#
|
||||
# Covers:
|
||||
# A. the first paid berth pays the base rate, undialled
|
||||
# B. each berth past it pays more than the one before, compounding
|
||||
# C. the growth is slow - a mid-sized fleet is dearer, not ruinous
|
||||
# D. the breakdown's per-minute total matches its own per-berth charges
|
||||
# E. and the charges it quotes are the ones actually withdrawn
|
||||
# F. an empty berth is quoted nothing
|
||||
|
||||
var state: Node
|
||||
|
||||
|
||||
func _initialize() -> void:
|
||||
state = root.get_node("GameState")
|
||||
state.buildings.clear()
|
||||
state.transporters.clear()
|
||||
state.reset_progression()
|
||||
state.reset_new_game()
|
||||
state.intro_active = false
|
||||
state.fleet_vessel_types = PackedStringArray()
|
||||
|
||||
|
||||
func _process(_delta: float) -> bool:
|
||||
var vessel: String = GameState.VESSEL_LASER
|
||||
var base: Dictionary = state.fleet_office_upkeep(vessel, GameState.BASE_FLEET_SIZE)
|
||||
if base.is_empty():
|
||||
return _fail("a laser berth is charged nothing at all")
|
||||
|
||||
# --- A. the first paid berth is the base rate -------------------
|
||||
if not is_equal_approx(state.fleet_upkeep_scale(GameState.BASE_FLEET_SIZE), 1.0):
|
||||
return _fail("the first paid berth is already dialled up (x%.2f)" \
|
||||
% state.fleet_upkeep_scale(GameState.BASE_FLEET_SIZE))
|
||||
|
||||
# --- B. and every berth after it costs more ---------------------
|
||||
var previous: float = 0.0
|
||||
for slot in range(GameState.BASE_FLEET_SIZE, GameState.BASE_FLEET_SIZE + 12):
|
||||
var scale: float = state.fleet_upkeep_scale(slot)
|
||||
if scale < previous:
|
||||
return _fail("berth %d is cheaper than the one before it" % (slot + 1))
|
||||
previous = scale
|
||||
var twelfth: float = state.fleet_upkeep_scale(GameState.BASE_FLEET_SIZE + 11)
|
||||
if twelfth <= 1.0:
|
||||
return _fail("twelve berths in, upkeep has not risen at all")
|
||||
|
||||
# --- C. slowly, though ------------------------------------------
|
||||
if twelfth > 6.0:
|
||||
return _fail("the twelfth berth costs x%.1f - that is not a slow exponential" % twelfth)
|
||||
print("berth scaling: 1.00 at the first paid berth, x%.2f twelve in" % twelfth)
|
||||
|
||||
# --- D/E/F. the quoted bill IS the charged one ------------------
|
||||
# Three offices, two of them crewed: the third berth stands empty and
|
||||
# must be quoted nothing.
|
||||
var office_ids: Array = []
|
||||
for i in range(3):
|
||||
office_ids.append(state.add_building(GameState.BUILDING_FLEET_OFFICE,
|
||||
Vector2(500.0 * float(i + 1), 0.0)))
|
||||
state.fleet_vessel_types = PackedStringArray([
|
||||
GameState.VESSEL_INTERCEPTOR, vessel, vessel])
|
||||
|
||||
var breakdown: Dictionary = state.fleet_upkeep_breakdown()
|
||||
var berths: Array = breakdown.berths
|
||||
if berths.size() != 2:
|
||||
return _fail("%d berths quoted for a fleet of 3 with 3 offices, expected 2 paying" \
|
||||
% berths.size())
|
||||
if int(berths[1].costs.get(GameState.RESOURCE_ORE, 0)) \
|
||||
<= int(berths[0].costs.get(GameState.RESOURCE_ORE, 0)) - 1:
|
||||
return _fail("the second paid berth is quoted less than the first")
|
||||
|
||||
# The per-minute figure has to be the per-berth charges, at the rate they
|
||||
# are actually taken - not a separate estimate.
|
||||
var charges: float = 60.0 / float(breakdown.charge_seconds)
|
||||
for resource_type in breakdown.per_minute:
|
||||
var summed: float = 0.0
|
||||
for berth in berths:
|
||||
summed += float(berth.costs.get(resource_type, 0)) * charges
|
||||
if not is_equal_approx(float(breakdown.per_minute[resource_type]), summed):
|
||||
return _fail("%s quoted at %.2f/min, its own berths add to %.2f" % [
|
||||
resource_type, float(breakdown.per_minute[resource_type]), summed])
|
||||
print("bill: %s, from %d paying berths" % [breakdown.per_minute, berths.size()])
|
||||
|
||||
# And a charge actually taken matches what was quoted for that berth.
|
||||
var quoted: int = int(berths[0].costs.get(GameState.RESOURCE_ORE, 0))
|
||||
var office: Dictionary = state.find_building(int(office_ids[0]))
|
||||
var store: RefCounted = state.building_inventory(int(office_ids[0]))
|
||||
store.set_amount(GameState.RESOURCE_ORE, 500)
|
||||
store.set_amount(GameState.RESOURCE_ENERGY, 500)
|
||||
var before: int = store.amount(GameState.RESOURCE_ORE)
|
||||
office.upkeep_progress = GameState.FLEET_OFFICE_UPKEEP_SECONDS
|
||||
state._advance_fleet_office_upkeep(0.1)
|
||||
var taken: int = before - store.amount(GameState.RESOURCE_ORE)
|
||||
if taken != quoted:
|
||||
return _fail("berth 2 was quoted %d ore and charged %d" % [quoted, taken])
|
||||
print("what the menu quotes for a berth is what the office pays: %d ore" % taken)
|
||||
|
||||
print("TEST_FLEET_UPKEEP_SCALING: PASS")
|
||||
quit(0)
|
||||
return true
|
||||
|
||||
|
||||
func _fail(message: String) -> bool:
|
||||
print("TEST_FLEET_UPKEEP_SCALING: FAIL (%s)" % message)
|
||||
quit(1)
|
||||
return true
|
||||
71
ui/menus/FleetUpkeepMenu.gd
Normal file
71
ui/menus/FleetUpkeepMenu.gd
Normal file
|
|
@ -0,0 +1,71 @@
|
|||
extends "res://ui/menus/ModalMenu.gd"
|
||||
|
||||
# Forgejo #220: what the fleet costs to keep, and WHY it costs that.
|
||||
#
|
||||
# A Fleet Office charges for the vessel in its berth every 25 seconds, and
|
||||
# each berth costs more than the one before it. Neither of those is visible
|
||||
# from the resource bar - the player watches a number fall and cannot tell
|
||||
# which of their own decisions is draining it - so this states the bill and
|
||||
# shows the arithmetic that produced it, line by line.
|
||||
#
|
||||
# Every number here comes from GameState.fleet_upkeep_breakdown(), which is
|
||||
# the same calculation the charging loop runs. A readout that did its own sum
|
||||
# could disagree with what is actually being taken, which is exactly the kind
|
||||
# of "the game is lying to me" the ticket is about.
|
||||
|
||||
@onready var total_label: Label = $TotalLabel
|
||||
@onready var detail_label: Label = $DetailLabel
|
||||
@onready var formula_label: Label = $FormulaLabel
|
||||
|
||||
var building_id: int = 0
|
||||
|
||||
|
||||
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 refresh() -> void:
|
||||
if not visible:
|
||||
return
|
||||
var breakdown: Dictionary = GameState.fleet_upkeep_breakdown()
|
||||
var berths: Array = breakdown.berths
|
||||
var per_minute: Dictionary = breakdown.per_minute
|
||||
|
||||
if per_minute.is_empty():
|
||||
total_label.text = "NOTHING TO KEEP"
|
||||
else:
|
||||
var parts: PackedStringArray = PackedStringArray()
|
||||
for resource_type in per_minute:
|
||||
parts.append("%.1f %s" % [float(per_minute[resource_type]),
|
||||
GameState.resource_name(String(resource_type)).to_lower()])
|
||||
total_label.text = "%s PER MINUTE" % " · ".join(parts)
|
||||
|
||||
# One line per paying berth: which hull, what it is charged, and the
|
||||
# multiplier that got it there. An empty berth is charged nothing and is
|
||||
# left out rather than listed at zero.
|
||||
var lines: PackedStringArray = PackedStringArray()
|
||||
for berth in berths:
|
||||
var costs: PackedStringArray = PackedStringArray()
|
||||
for resource_type in berth.costs:
|
||||
costs.append("%d %s" % [int(berth.costs[resource_type]),
|
||||
GameState.resource_name(String(resource_type)).to_lower()])
|
||||
lines.append("BERTH %d %-16s %s (x%.2f)%s" % [
|
||||
int(berth.slot), GameState.vessel_name(String(berth.vessel_type)),
|
||||
" ".join(costs), float(berth.scale),
|
||||
" — UNPAID" if bool(berth.starved) else "",
|
||||
])
|
||||
detail_label.text = "\n".join(lines) if not lines.is_empty() \
|
||||
else "No berth is being charged. Build a Fleet Office and put a vessel in it."
|
||||
|
||||
formula_label.text = ("Each berth is charged every %ds: the vessel's build price "
|
||||
+ "divided by %d, then multiplied by %.2f for every berth past the first "
|
||||
+ "paid one. The first vessel is free.") % [
|
||||
int(breakdown.charge_seconds), int(breakdown.divisor),
|
||||
float(breakdown.growth)]
|
||||
77
ui/menus/FleetUpkeepMenu.tscn
Normal file
77
ui/menus/FleetUpkeepMenu.tscn
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
[gd_scene load_steps=3 format=3]
|
||||
|
||||
[ext_resource type="Script" path="res://ui/IconButton.gd" id="icon"]
|
||||
[ext_resource type="Script" path="res://ui/menus/FleetUpkeepMenu.gd" id="menu"]
|
||||
|
||||
[node name="FleetUpkeepMenu" type="Control" groups=["modal_menus"]]
|
||||
visible = false
|
||||
mouse_filter = 2
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
script = ExtResource("menu")
|
||||
|
||||
[node name="Backdrop" type="ColorRect" parent="."]
|
||||
mouse_filter = 2
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
color = Color(0.03, 0.03, 0.08, 0.96)
|
||||
|
||||
[node name="TitleLabel" type="Label" parent="."]
|
||||
mouse_filter = 2
|
||||
anchor_right = 1.0
|
||||
offset_left = 24.0
|
||||
offset_top = 24.0
|
||||
offset_right = -180.0
|
||||
offset_bottom = 100.0
|
||||
theme_override_font_sizes/font_size = 40
|
||||
text = "FLEET UPKEEP"
|
||||
horizontal_alignment = 1
|
||||
|
||||
[node name="CloseButton" type="Control" parent="."]
|
||||
anchor_left = 1.0
|
||||
anchor_right = 1.0
|
||||
offset_left = -140.0
|
||||
offset_top = 24.0
|
||||
offset_right = -24.0
|
||||
offset_bottom = 140.0
|
||||
script = ExtResource("icon")
|
||||
icon = 1
|
||||
glow_color = Color(0.55, 0.6, 1, 1)
|
||||
|
||||
[node name="TotalLabel" type="Label" parent="."]
|
||||
mouse_filter = 2
|
||||
anchor_right = 1.0
|
||||
offset_left = 32.0
|
||||
offset_top = 150.0
|
||||
offset_right = -32.0
|
||||
offset_bottom = 220.0
|
||||
theme_override_font_sizes/font_size = 32
|
||||
theme_override_colors/font_color = Color(1, 0.85, 0.35, 1)
|
||||
text = ""
|
||||
horizontal_alignment = 1
|
||||
|
||||
[node name="DetailLabel" type="Label" parent="."]
|
||||
mouse_filter = 2
|
||||
anchor_right = 1.0
|
||||
offset_left = 32.0
|
||||
offset_top = 250.0
|
||||
offset_right = -32.0
|
||||
offset_bottom = 860.0
|
||||
theme_override_font_sizes/font_size = 30
|
||||
theme_override_colors/font_color = Color(0.72, 0.88, 0.96, 1)
|
||||
text = ""
|
||||
autowrap_mode = 2
|
||||
|
||||
[node name="FormulaLabel" type="Label" parent="."]
|
||||
mouse_filter = 2
|
||||
anchor_right = 1.0
|
||||
offset_left = 40.0
|
||||
offset_top = 880.0
|
||||
offset_right = -40.0
|
||||
offset_bottom = 1060.0
|
||||
theme_override_font_sizes/font_size = 26
|
||||
theme_override_colors/font_color = Color(0.55, 0.78, 0.86, 1)
|
||||
text = ""
|
||||
horizontal_alignment = 1
|
||||
vertical_alignment = 1
|
||||
autowrap_mode = 2
|
||||
|
|
@ -11,6 +11,7 @@
|
|||
[ext_resource type="PackedScene" path="res://ui/menus/DevMenu.tscn" id="menu_dev"]
|
||||
[ext_resource type="PackedScene" path="res://ui/menus/ScannerMenu.tscn" id="menu_scanner"]
|
||||
[ext_resource type="PackedScene" path="res://ui/menus/StationMenu.tscn" id="menu_station"]
|
||||
[ext_resource type="PackedScene" path="res://ui/menus/FleetUpkeepMenu.tscn" id="menu_upkeep"]
|
||||
[ext_resource type="PackedScene" path="res://ui/ScannerGuidance.tscn" id="scanner_guidance"]
|
||||
|
||||
|
||||
|
|
@ -530,6 +531,8 @@ icon = 1
|
|||
[node name="ScannerMenu" parent="UI" instance=ExtResource("menu_scanner")]
|
||||
|
||||
[node name="StationMenu" parent="UI" instance=ExtResource("menu_station")]
|
||||
|
||||
[node name="FleetUpkeepMenu" parent="UI" instance=ExtResource("menu_upkeep")]
|
||||
[node name="QuestPanel" type="Control" parent="UI" groups=["modal_menus"]]
|
||||
visible = false
|
||||
mouse_filter = 2
|
||||
|
|
|
|||
Loading…
Reference in a new issue