Refactor gameplay menus into owned scenes
This commit is contained in:
parent
46196a1adb
commit
a17fe88197
50 changed files with 3449 additions and 3619 deletions
|
|
@ -9,6 +9,7 @@ script = ExtResource("3")
|
|||
input_buffers = {
|
||||
"gas": 40
|
||||
}
|
||||
collected_outputs = PackedStringArray("energy")
|
||||
conversion_input = "gas"
|
||||
conversion_output = "energy"
|
||||
conversion_rate = 1.0
|
||||
|
|
@ -27,6 +28,7 @@ build_resource_costs = {
|
|||
action_icon = 33
|
||||
menu_icon = 33
|
||||
visual_scene = ExtResource("2")
|
||||
capabilities = PackedStringArray("gas_burner")
|
||||
logistics = SubResource("Resource_logistics")
|
||||
map_color = Color(0.95, 0.35, 0.15, 1)
|
||||
map_sides = 5
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -46,9 +46,10 @@ func _initialize() -> void:
|
|||
|
||||
func _shown() -> Array:
|
||||
var out: Array = []
|
||||
for entry in controller.build_menu_entries:
|
||||
if entry[1].visible:
|
||||
out.append(entry)
|
||||
for entry in controller.build_menu.entries:
|
||||
if entry.button.visible:
|
||||
out.append([entry.definition.definition_id, entry.button,
|
||||
entry.label, entry.cost, entry.definition])
|
||||
return out
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -105,7 +105,7 @@ func _process(delta: float) -> bool:
|
|||
# --- D. locked state in the crafter UI -------------------------
|
||||
controller.craft_building_id = crafter_id
|
||||
controller._refresh_craft_status()
|
||||
if controller.craft_vessel_buttons[FLEET_UI_INDEX].enabled:
|
||||
if controller.craft_menu.vessel_buttons[FLEET_UI_INDEX].enabled:
|
||||
return _fail("a locked carrier shows enabled in the crafter menu")
|
||||
|
||||
stage = 1
|
||||
|
|
@ -126,8 +126,8 @@ func _process(delta: float) -> bool:
|
|||
|
||||
# --- D. unlocked state in the crafter UI ------------------------
|
||||
controller._refresh_craft_status()
|
||||
var craft_button: IconButton = controller.craft_vessel_buttons[FLEET_UI_INDEX]
|
||||
var craft_label: Label = controller.craft_vessel_labels[FLEET_UI_INDEX]
|
||||
var craft_button: IconButton = controller.craft_menu.vessel_buttons[FLEET_UI_INDEX]
|
||||
var craft_label: Label = controller.craft_menu.vessel_labels[FLEET_UI_INDEX]
|
||||
if not craft_button.enabled:
|
||||
return _fail("an unlocked carrier still shows disabled in the crafter menu")
|
||||
if craft_button.icon != definition.icon or craft_button.glow_color != definition.glow_color:
|
||||
|
|
@ -148,8 +148,8 @@ func _process(delta: float) -> bool:
|
|||
|
||||
# --- D. hangar display -------------------------------------------
|
||||
controller._refresh_hangar()
|
||||
var available_slot: IconButton = controller.hangar_available_slots[FLEET_UI_INDEX]
|
||||
var available_label: Label = controller.hangar_available_labels[FLEET_UI_INDEX]
|
||||
var available_slot: IconButton = controller.hangar_menu.available_slots[FLEET_UI_INDEX]
|
||||
var available_label: Label = controller.hangar_menu.available_labels[FLEET_UI_INDEX]
|
||||
if available_slot.icon != definition.icon or available_slot.glow_color != definition.glow_color:
|
||||
return _fail("hangar carrier slot does not match its definition's icon/colour")
|
||||
var expected_available: String = "%s\n1 available" % definition.display_name
|
||||
|
|
@ -177,8 +177,8 @@ func _process(delta: float) -> bool:
|
|||
# --- D. ship lab display -------------------------------------------
|
||||
controller.lab_vessel = GameState.VESSEL_CARRIER
|
||||
controller._refresh_lab()
|
||||
var lab_button: IconButton = controller.lab_vessel_buttons[LAB_UI_INDEX]
|
||||
var lab_label: Label = controller.lab_vessel_labels[LAB_UI_INDEX]
|
||||
var lab_button: IconButton = controller.lab_menu.vessel_buttons[LAB_UI_INDEX]
|
||||
var lab_label: Label = controller.lab_menu.vessel_labels[LAB_UI_INDEX]
|
||||
if lab_button.icon != definition.icon or lab_button.glow_color != definition.glow_color:
|
||||
return _fail("ship lab carrier slot does not match its definition's icon/colour")
|
||||
if lab_label.text != definition.display_name:
|
||||
|
|
|
|||
|
|
@ -67,7 +67,7 @@ func _tap(button: Control) -> void:
|
|||
|
||||
|
||||
func _first_line() -> String:
|
||||
return controller.craft_status.text.split("\n")[0]
|
||||
return controller.craft_menu.status.text.split("\n")[0]
|
||||
|
||||
|
||||
func _process(delta: float) -> bool:
|
||||
|
|
|
|||
|
|
@ -55,7 +55,7 @@ func _process(delta: float) -> bool:
|
|||
or controller.landing_button.visible:
|
||||
return _fail("landing was not folded into the shared action control")
|
||||
controller._on_transfer_pressed()
|
||||
if not controller.transfer_menu.visible or controller.transfer_list.extractor_index != extractor_index:
|
||||
if not controller.transfer_menu.visible or controller.transfer_menu.resource_list.extractor_index != extractor_index:
|
||||
return _fail("transfer panel did not bind to the extractor")
|
||||
var before: int = state.fleet_resource(resource_type)
|
||||
controller._on_resource_transfer(resource_type, false, 5)
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@ func _process(delta: float) -> bool:
|
|||
if elapsed < 0.2:
|
||||
return false
|
||||
# Available cards name the vessel and count what can be crewed.
|
||||
var available_label: Label = controller.hangar_available_labels[0]
|
||||
var available_label: Label = controller.hangar_menu.available_labels[0]
|
||||
if "Interceptor" not in available_label.text or "1 available" not in available_label.text:
|
||||
_fail("available interceptor card says '%s'" % available_label.text)
|
||||
return true
|
||||
|
|
|
|||
|
|
@ -69,34 +69,34 @@ func _process(delta: float) -> bool:
|
|||
# Gas Bomber is named after a resource and always will be, and
|
||||
# what #111 removed was the PRICE spelled out underneath.
|
||||
var fleet_defs: Array = VesselDefinitions.fleet()
|
||||
for i in range(mini(controller.craft_vessel_labels.size(), fleet_defs.size())):
|
||||
var caption: String = String(controller.craft_vessel_labels[i].text)
|
||||
for i in range(mini(controller.craft_menu.vessel_labels.size(), fleet_defs.size())):
|
||||
var caption: String = String(controller.craft_menu.vessel_labels[i].text)
|
||||
var expected: String = String(fleet_defs[i].display_name)
|
||||
if caption != expected:
|
||||
return _fail("a craft caption reads \"%s\", expected just \"%s\"" \
|
||||
% [caption, expected])
|
||||
# Captions must not sit on top of one another, which is what
|
||||
# made the old single row unreadable.
|
||||
for i in range(controller.craft_vessel_labels.size()):
|
||||
for j in range(i + 1, controller.craft_vessel_labels.size()):
|
||||
var a: Control = controller.craft_vessel_labels[i]
|
||||
var b: Control = controller.craft_vessel_labels[j]
|
||||
for i in range(controller.craft_menu.vessel_labels.size()):
|
||||
for j in range(i + 1, controller.craft_menu.vessel_labels.size()):
|
||||
var a: Control = controller.craft_menu.vessel_labels[i]
|
||||
var b: Control = controller.craft_menu.vessel_labels[j]
|
||||
if Rect2(a.position, a.size).intersects(Rect2(b.position, b.size)):
|
||||
return _fail("craft captions %d and %d overlap" % [i, j])
|
||||
print("craft captions: %d, one line each, none overlapping" \
|
||||
% controller.craft_vessel_labels.size())
|
||||
% controller.craft_menu.vessel_labels.size())
|
||||
|
||||
# --- B. and the price is really there ---------------------
|
||||
if controller.craft_price_strips.size() != controller.craft_vessel_buttons.size():
|
||||
if controller.craft_menu.price_tags.size() != controller.craft_menu.vessel_buttons.size():
|
||||
return _fail("%d price strips for %d vessels" \
|
||||
% [controller.craft_price_strips.size(),
|
||||
controller.craft_vessel_buttons.size()])
|
||||
% [controller.craft_menu.price_tags.size(),
|
||||
controller.craft_menu.vessel_buttons.size()])
|
||||
var priced: int = 0
|
||||
var stacked: int = 0
|
||||
for i in range(controller.craft_price_strips.size()):
|
||||
for i in range(controller.craft_menu.price_tags.size()):
|
||||
var definition: Resource = VesselDefinitions.fleet()[i]
|
||||
var costs: Dictionary = game_state.product_costs(definition.definition_id)
|
||||
var strip: Control = controller.craft_price_strips[i]
|
||||
var strip: Control = controller.craft_menu.price_tags[i]
|
||||
if costs.is_empty():
|
||||
continue
|
||||
if strip.is_free():
|
||||
|
|
@ -122,7 +122,7 @@ func _process(delta: float) -> bool:
|
|||
% [definition.definition_id, box.position.x, box.end.x, strip.size.x])
|
||||
# ...and the price sits with the button it is about, not
|
||||
# adrift below the caption.
|
||||
var button: Control = controller.craft_vessel_buttons[i]
|
||||
var button: Control = controller.craft_menu.vessel_buttons[i]
|
||||
var gap: float = strip.position.y - (button.position.y + button.size.y)
|
||||
if gap > 80.0:
|
||||
return _fail("%s's price sits %.0fpx below its button" \
|
||||
|
|
@ -135,10 +135,10 @@ func _process(delta: float) -> bool:
|
|||
% [priced, stacked])
|
||||
|
||||
# --- F. #147 - and the rows do not run into each other -------
|
||||
for i in range(controller.craft_vessel_buttons.size()):
|
||||
for j in range(i + 1, controller.craft_vessel_buttons.size()):
|
||||
for part in [controller.craft_vessel_buttons,
|
||||
controller.craft_vessel_labels, controller.craft_price_strips]:
|
||||
for i in range(controller.craft_menu.vessel_buttons.size()):
|
||||
for j in range(i + 1, controller.craft_menu.vessel_buttons.size()):
|
||||
for part in [controller.craft_menu.vessel_buttons,
|
||||
controller.craft_menu.vessel_labels, controller.craft_menu.price_tags]:
|
||||
if i >= part.size() or j >= part.size():
|
||||
continue
|
||||
var a: Control = part[i]
|
||||
|
|
@ -146,9 +146,9 @@ func _process(delta: float) -> bool:
|
|||
if Rect2(a.position, a.size).intersects(Rect2(b.position, b.size)):
|
||||
return _fail("craft entries %d and %d overlap" % [i, j])
|
||||
# A price must not reach the button of the row below it.
|
||||
var mine: Control = controller.craft_price_strips[i]
|
||||
for k in range(controller.craft_vessel_buttons.size()):
|
||||
var other: Control = controller.craft_vessel_buttons[k]
|
||||
var mine: Control = controller.craft_menu.price_tags[i]
|
||||
for k in range(controller.craft_menu.vessel_buttons.size()):
|
||||
var other: Control = controller.craft_menu.vessel_buttons[k]
|
||||
if other.position.y > mine.position.y \
|
||||
and Rect2(mine.position, mine.size).intersects(
|
||||
Rect2(other.position, other.size)):
|
||||
|
|
@ -157,26 +157,26 @@ func _process(delta: float) -> bool:
|
|||
|
||||
# --- C. the hangar ---------------------------------------
|
||||
controller._layout_hangar()
|
||||
if controller.hangar_divider_y <= 0.0:
|
||||
if controller.hangar_menu.divider_y <= 0.0:
|
||||
return _fail("the hangar laid out with no divider between its halves")
|
||||
var available_bottom: float = 0.0
|
||||
var fleet_top: float = 1.0e9
|
||||
for label in controller.hangar_available_labels:
|
||||
for label in controller.hangar_menu.available_labels:
|
||||
available_bottom = maxf(available_bottom, label.position.y + label.size.y)
|
||||
for slot in controller.hangar_fleet_slots:
|
||||
for slot in controller.hangar_menu.fleet_slots:
|
||||
fleet_top = minf(fleet_top, slot.position.y)
|
||||
if not (controller.hangar_divider_y > available_bottom - 40.0
|
||||
and controller.hangar_divider_y < fleet_top):
|
||||
if not (controller.hangar_menu.divider_y > available_bottom - 40.0
|
||||
and controller.hangar_menu.divider_y < fleet_top):
|
||||
return _fail("the divider at %.0f is not between the two grids (%.0f / %.0f)" \
|
||||
% [controller.hangar_divider_y, available_bottom, fleet_top])
|
||||
% [controller.hangar_menu.divider_y, available_bottom, fleet_top])
|
||||
# Two lines of caption. The font is 24-ish, so anything under
|
||||
# about 44 cannot show a second line at all.
|
||||
var caption_height: float = controller.hangar_available_labels[0].size.y
|
||||
var caption_height: float = controller.hangar_menu.available_labels[0].size.y
|
||||
if caption_height < 44.0:
|
||||
return _fail("hangar captions are %.0fpx tall - a two-word name is clipped" \
|
||||
% caption_height)
|
||||
print("hangar: %.0fpx captions, divider at %.0f between %.0f and %.0f" \
|
||||
% [caption_height, controller.hangar_divider_y, available_bottom, fleet_top])
|
||||
% [caption_height, controller.hangar_menu.divider_y, available_bottom, fleet_top])
|
||||
|
||||
# --- D. #143 - and the caption stays in its box --------------
|
||||
# The caption is two lines before autowrap and three after it in
|
||||
|
|
@ -185,8 +185,8 @@ func _process(delta: float) -> bool:
|
|||
# the box now, and the box clips, so nothing can reach the next
|
||||
# row however the vessel names grow.
|
||||
controller._refresh_hangar()
|
||||
for pair in [[controller.hangar_available_labels, controller.hangar_available_slots],
|
||||
[controller.hangar_fleet_labels, controller.hangar_fleet_slots]]:
|
||||
for pair in [[controller.hangar_menu.available_labels, controller.hangar_menu.available_slots],
|
||||
[controller.hangar_menu.fleet_labels, controller.hangar_menu.fleet_slots]]:
|
||||
for i in range(pair[0].size()):
|
||||
var caption: Label = pair[0][i]
|
||||
if not caption.clip_text:
|
||||
|
|
@ -205,7 +205,7 @@ func _process(delta: float) -> bool:
|
|||
and Rect2(caption.position, caption.size).intersects(below):
|
||||
return _fail("caption \"%s\" runs into the icon below it" \
|
||||
% caption.text.replace("\n", " / "))
|
||||
var probe: Label = controller.hangar_available_labels[0]
|
||||
var probe: Label = controller.hangar_menu.available_labels[0]
|
||||
print("captions fitted to %dpx and clipped; \"%s\" fits its %.0fpx box" \
|
||||
% [probe.get_theme_font_size("font_size"),
|
||||
probe.text.replace("\n", " / "), probe.size.y])
|
||||
|
|
|
|||
|
|
@ -107,12 +107,12 @@ func _process(delta: float) -> bool:
|
|||
|
||||
# --- B. one price widget everywhere ----------------------
|
||||
var tags: Array = []
|
||||
for entry in controller.build_menu_entries:
|
||||
tags.append(entry[3])
|
||||
tags.append_array(controller.craft_price_strips)
|
||||
tags.append_array(controller.lab_price_tags)
|
||||
tags.append(controller.info_cost)
|
||||
tags.append(controller.skill_cost)
|
||||
for entry in controller.build_menu.entries:
|
||||
tags.append(entry.cost)
|
||||
tags.append_array(controller.craft_menu.price_tags)
|
||||
tags.append_array(controller.lab_menu.price_tags)
|
||||
tags.append(controller.build_menu.info_cost)
|
||||
tags.append(controller.skill_menu.cost)
|
||||
if tags.size() < 15:
|
||||
return _fail("only %d price widgets found - the menus cannot all be covered" % tags.size())
|
||||
for tag in tags:
|
||||
|
|
@ -124,7 +124,7 @@ func _process(delta: float) -> bool:
|
|||
# --- C. have over cost, smaller, red when short ----------
|
||||
game_state.bank_inventory.set_amount(GameState.RESOURCE_ORE, 3)
|
||||
game_state.fleet_inventory.set_amount(GameState.RESOURCE_ORE, 0)
|
||||
var probe: Control = controller.info_cost
|
||||
var probe: Control = controller.build_menu.info_cost
|
||||
probe.show_price({GameState.RESOURCE_ORE: 25})
|
||||
if probe.priced(GameState.RESOURCE_ORE) != 25:
|
||||
return _fail("the tag does not carry the price it was given")
|
||||
|
|
@ -165,8 +165,8 @@ func _process(delta: float) -> bool:
|
|||
if String(node.desc).length() > longest.length():
|
||||
longest = String(node.desc)
|
||||
controller._refresh_skill_menu(String(node.id))
|
||||
var detail: Rect2 = _rect(controller.skill_detail)
|
||||
var price: Rect2 = _rect(controller.skill_cost)
|
||||
var detail: Rect2 = _rect(controller.skill_menu.detail)
|
||||
var price: Rect2 = _rect(controller.skill_menu.cost)
|
||||
if detail.intersects(price):
|
||||
return _fail("the explanation (%s) overlaps the price (%s)" % [detail, price])
|
||||
if detail.position.x >= price.position.x:
|
||||
|
|
@ -179,11 +179,11 @@ func _process(delta: float) -> bool:
|
|||
game_state.fleet_inventory.set_amount(GameState.RESOURCE_ORE, 0)
|
||||
game_state.unlocked.clear()
|
||||
controller._refresh_skill_menu("shipyards")
|
||||
if controller.skill_cost.is_affordable():
|
||||
if controller.skill_menu.cost.is_affordable():
|
||||
return _fail("a node reads as affordable with no ore at all")
|
||||
if controller.skill_status.text.to_lower().contains("not enough"):
|
||||
if controller.skill_menu.status.text.to_lower().contains("not enough"):
|
||||
return _fail("the shortfall is still written out as well: '%s'" \
|
||||
% controller.skill_status.text)
|
||||
% controller.skill_menu.status.text)
|
||||
print("the shortfall is shown once, on the price, and not repeated in words")
|
||||
|
||||
print("TEST_MENU_PRICE_UNIFICATION: PASS")
|
||||
|
|
|
|||
42
tests/test_menu_scene_boundaries.gd
Normal file
42
tests/test_menu_scene_boundaries.gd
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
extends SceneTree
|
||||
|
||||
const MENUS: Array[String] = [
|
||||
"BuildMenu", "CraftMenu", "LabMenu", "TransferMenu", "HangarMenu",
|
||||
"FormationMenu", "SkillMenu", "PlanningMenu", "GarrisonMenu",
|
||||
]
|
||||
|
||||
|
||||
func _initialize() -> void:
|
||||
call_deferred("_verify")
|
||||
|
||||
|
||||
func _verify() -> void:
|
||||
var packed: PackedScene = load("res://world/Main.tscn")
|
||||
if packed == null:
|
||||
return _fail("Main.tscn did not load")
|
||||
var main: Node = packed.instantiate()
|
||||
root.add_child(main)
|
||||
for menu_name in MENUS:
|
||||
var menu: Node = main.get_node_or_null("UI/%s" % menu_name)
|
||||
if menu == null:
|
||||
return _fail("%s is missing" % menu_name)
|
||||
var expected: String = "res://ui/menus/%s.tscn" % menu_name
|
||||
if menu.scene_file_path != expected:
|
||||
return _fail("%s is inline in Main.tscn instead of instancing %s" \
|
||||
% [menu_name, expected])
|
||||
if menu.get_script() == null:
|
||||
return _fail("%s has no owning script" % menu_name)
|
||||
|
||||
var source: String = FileAccess.get_file_as_string(
|
||||
"res://controllers/BuildController.gd")
|
||||
for menu_name in MENUS:
|
||||
if "../UI/%s/" % menu_name in source:
|
||||
return _fail("BuildController reaches into %s children" % menu_name)
|
||||
print("%d menu scenes own their controls; BuildController uses root APIs" % MENUS.size())
|
||||
print("TEST_MENU_SCENE_BOUNDARIES: PASS")
|
||||
quit(0)
|
||||
|
||||
|
||||
func _fail(message: String) -> void:
|
||||
print("TEST_MENU_SCENE_BOUNDARIES: FAIL (%s)" % message)
|
||||
quit(1)
|
||||
1
tests/test_menu_scene_boundaries.gd.uid
Normal file
1
tests/test_menu_scene_boundaries.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
|||
uid://bufrmk7en8qxd
|
||||
|
|
@ -253,7 +253,7 @@ func _process(delta: float) -> bool:
|
|||
|
||||
if game_state.buildings.size() != before + 1:
|
||||
return _fail("building a mothership from the fleet's own hold did not place one (%d -> %d): %s" \
|
||||
% [before, game_state.buildings.size(), build_controller.build_status.text])
|
||||
% [before, game_state.buildings.size(), build_controller.build_menu.status.text])
|
||||
# Checked as a TOTAL, not as the hold alone: a mothership standing
|
||||
# where the fleet is starts taking delivery of the hold on the
|
||||
# very next tick, so ore legitimately moves from hold to bank
|
||||
|
|
|
|||
|
|
@ -154,13 +154,13 @@ func _process(delta: float) -> bool:
|
|||
controller._refresh_skill_menu(second)
|
||||
# #134: the refusal is shown on the price rather than written out in a
|
||||
# sentence below it - what you hold over what it costs, in red.
|
||||
if controller.skill_cost.is_affordable():
|
||||
if controller.skill_menu.cost.is_affordable():
|
||||
return _fail("a node the player cannot pay for reads as affordable")
|
||||
if not controller.skill_cost.is_short(GameState.RESOURCE_ORE):
|
||||
if not controller.skill_menu.cost.is_short(GameState.RESOURCE_ORE):
|
||||
return _fail("the ore the player does not have is not marked short")
|
||||
print("unaffordable node refused, and its price says so: %d/%d ore" \
|
||||
% [controller.skill_cost.held(GameState.RESOURCE_ORE),
|
||||
controller.skill_cost.priced(GameState.RESOURCE_ORE)])
|
||||
% [controller.skill_menu.cost.held(GameState.RESOURCE_ORE),
|
||||
controller.skill_menu.cost.priced(GameState.RESOURCE_ORE)])
|
||||
|
||||
print("TEST_RESEARCH_DOUBLE_TAP: PASS")
|
||||
quit(0)
|
||||
|
|
|
|||
|
|
@ -98,9 +98,9 @@ func _process(delta: float) -> bool:
|
|||
controller._confirm_build()
|
||||
if game_state.extractors.size() != before:
|
||||
return _fail("an extractor was built on a research_lab planet")
|
||||
if not ("nothing to extract" in controller.build_status.text):
|
||||
return _fail("refusal did not explain itself, status was '%s'" % controller.build_status.text)
|
||||
print("extractor refused on a research_lab planet, explained: '%s'" % controller.build_status.text)
|
||||
if not ("nothing to extract" in controller.build_menu.status.text):
|
||||
return _fail("refusal did not explain itself, status was '%s'" % controller.build_menu.status.text)
|
||||
print("extractor refused on a research_lab planet, explained: '%s'" % controller.build_menu.status.text)
|
||||
|
||||
print("TEST_RESEARCH_LAB_EXTRACTOR_GATE: PASS")
|
||||
quit(0)
|
||||
|
|
|
|||
|
|
@ -127,16 +127,14 @@ func _process(delta: float) -> bool:
|
|||
% [controller.transfer_building_id, crafter_id])
|
||||
|
||||
# --- 6. the shared bar follows the panel --------------------
|
||||
for bar in controller.resource_bars:
|
||||
_expect(bar.building_id == crafter_id,
|
||||
"a resource bar is reporting building %d, not the crafter %d"
|
||||
% [bar.building_id, crafter_id])
|
||||
_expect(controller.transfer_menu.building_id == crafter_id,
|
||||
"transfer scene did not own the selected building context")
|
||||
|
||||
# --- 5. an empty hold explains itself -----------------------
|
||||
game_state.fleet_cargo = 0
|
||||
controller._on_transfer(true, GameState.CARGO_LOAD_BATCH)
|
||||
_expect("carrying nothing" in controller.transfer_status.text,
|
||||
"unloading an empty hold said: %s" % controller.transfer_status.text)
|
||||
_expect("carrying nothing" in controller.transfer_menu.status.text,
|
||||
"unloading an empty hold said: %s" % controller.transfer_menu.status.text)
|
||||
|
||||
# --- 2. both directions at an ordinary building -------------
|
||||
# Baseline taken AFTER the last hand-set figure: the conservation
|
||||
|
|
|
|||
|
|
@ -125,19 +125,19 @@ func _process(delta: float) -> bool:
|
|||
return true
|
||||
# The tree is a tall, vertically scrolling canvas. A branch keeps a
|
||||
# stable lane as it rises, and dragging exposes higher depths.
|
||||
var freight: Vector2 = controller.skill_tree.node_screen_pos(game_state.skill_node("freight"))
|
||||
var yards: Vector2 = controller.skill_tree.node_screen_pos(game_state.skill_node("freight_yards"))
|
||||
var freight: Vector2 = controller.skill_menu.tree.node_screen_pos(game_state.skill_node("freight"))
|
||||
var yards: Vector2 = controller.skill_menu.tree.node_screen_pos(game_state.skill_node("freight_yards"))
|
||||
if absf(freight.x - yards.x) > 1.0 or yards.y >= freight.y:
|
||||
print("TEST_SKILL_TREE: FAIL (freight branch does not rise vertically)")
|
||||
quit(1)
|
||||
return true
|
||||
var before_scroll: float = controller.skill_tree.scroll_y
|
||||
var before_scroll: float = controller.skill_menu.tree.scroll_y
|
||||
var drag: InputEventScreenDrag = InputEventScreenDrag.new()
|
||||
# Start at the root at the bottom; pull the canvas down to reveal
|
||||
# the branches rising above it.
|
||||
drag.relative = Vector2(0.0, 180.0)
|
||||
controller.skill_tree.handle_drag(drag)
|
||||
if controller.skill_tree.scroll_y >= before_scroll:
|
||||
controller.skill_menu.tree.handle_drag(drag)
|
||||
if controller.skill_menu.tree.scroll_y >= before_scroll:
|
||||
print("TEST_SKILL_TREE: FAIL (tree did not scroll upward)")
|
||||
quit(1)
|
||||
return true
|
||||
|
|
|
|||
|
|
@ -1,20 +0,0 @@
|
|||
extends Control
|
||||
|
||||
# #120: the rule between the hangar's two halves.
|
||||
#
|
||||
# The panel itself draws it rather than a separate node, because the y comes
|
||||
# from BuildController._layout_hangar() - which is also what places the two
|
||||
# grids - and a divider that had to be positioned independently would drift
|
||||
# away from the sections it divides the first time either grid changed size.
|
||||
|
||||
const RULE_COLOR: Color = Color(0.45, 0.9, 0.55)
|
||||
|
||||
@onready var controller: Node = get_node("../../BuildController")
|
||||
|
||||
|
||||
func _draw() -> void:
|
||||
if controller == null or controller.hangar_divider_y <= 0.0:
|
||||
return
|
||||
var y: float = controller.hangar_divider_y
|
||||
NeonDraw.draw_glowing_line(self, Vector2(24.0, y), Vector2(size.x - 24.0, y),
|
||||
RULE_COLOR, 0.5, 0.4)
|
||||
|
|
@ -1 +0,0 @@
|
|||
uid://bwqdhbksv0xgf
|
||||
216
ui/menus/BuildMenu.gd
Normal file
216
ui/menus/BuildMenu.gd
Normal file
|
|
@ -0,0 +1,216 @@
|
|||
extends "res://ui/menus/ModalMenu.gd"
|
||||
|
||||
signal building_selected(type: String)
|
||||
signal build_confirmed
|
||||
|
||||
const BUILDING_DEFINITIONS = preload("res://buildings/BuildingDefinitions.gd")
|
||||
const MENU_LAYOUT = preload("res://ui/menus/MenuLayout.gd")
|
||||
|
||||
const BUTTON_HALF: float = 64.0
|
||||
const BUTTON_HEIGHT: float = 100.0
|
||||
const COST_HALF: float = 74.0
|
||||
const COST_HEIGHT: float = 86.0
|
||||
const LABEL_OFFSET: float = 106.0
|
||||
const LABEL_GAP: float = 4.0
|
||||
const NATURAL_SPACING: float = 280.0
|
||||
const MIN_SPACING: float = BUTTON_HALF * 2.0 + 12.0
|
||||
const LABEL_SHARE: float = 0.46
|
||||
const LABEL_HEIGHT: float = 52.0
|
||||
const LABEL_PADDING: float = 10.0
|
||||
const COST_PADDING: float = 12.0
|
||||
const SIDE_MARGIN: float = 24.0
|
||||
const MAX_COLUMNS: int = 6
|
||||
|
||||
@onready var status: Label = $StatusLabel
|
||||
@onready var info_popup: Control = $InfoPopup
|
||||
@onready var info_title: Label = $InfoPopup/Panel/TitleLabel
|
||||
@onready var info_message: Label = $InfoPopup/Panel/MessageLabel
|
||||
@onready var info_cost: Control = $InfoPopup/Panel/CostNumber
|
||||
@onready var info_build_button: Control = $InfoPopup/Panel/BuildButton
|
||||
@onready var info_close_button: Control = $InfoPopup/Panel/CloseButton
|
||||
|
||||
var entries: Array = []
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
super._ready()
|
||||
_configure_entries()
|
||||
info_close_button.pressed.connect(close_info)
|
||||
info_build_button.pressed.connect(func(): build_confirmed.emit())
|
||||
info_popup.visible = false
|
||||
|
||||
|
||||
func _configure_entries() -> void:
|
||||
entries.clear()
|
||||
for definition in BUILDING_DEFINITIONS.all():
|
||||
if definition.menu_button_name == "":
|
||||
continue
|
||||
var button: Control = get_node(String(definition.menu_button_name))
|
||||
var label: Label = get_node(String(definition.menu_label_name))
|
||||
var cost_tag: Control = get_node(String(definition.menu_cost_name))
|
||||
button.icon = definition.menu_icon
|
||||
button.pressed.connect(
|
||||
func(): building_selected.emit(String(definition.definition_id)))
|
||||
label.text = definition.display_name
|
||||
cost_tag.show_price(GameState.building_costs(String(definition.definition_id)))
|
||||
entries.append({"definition": definition, "button": button,
|
||||
"label": label, "cost": cost_tag})
|
||||
|
||||
|
||||
func open_menu() -> void:
|
||||
super.open_menu()
|
||||
close_info()
|
||||
|
||||
|
||||
func close_menu() -> void:
|
||||
close_info()
|
||||
super.close_menu()
|
||||
|
||||
|
||||
func close_info() -> void:
|
||||
info_popup.visible = false
|
||||
|
||||
|
||||
func show_info(title: String, message: String, costs: Dictionary,
|
||||
can_build: bool) -> void:
|
||||
info_title.text = title
|
||||
info_message.text = message
|
||||
info_cost.show_price(costs)
|
||||
info_build_button.visible = can_build
|
||||
info_popup.visible = true
|
||||
|
||||
|
||||
func set_status(message: String) -> void:
|
||||
status.text = message
|
||||
|
||||
|
||||
func refresh(planet: Node2D) -> void:
|
||||
_layout_entries()
|
||||
refresh_option_states(planet)
|
||||
if planet == null:
|
||||
status.text = ""
|
||||
elif not GameState.is_planet_conquered(planet.planet_id):
|
||||
status.text = "Over %s - capture it before building an extractor" % planet.planet_name
|
||||
else:
|
||||
status.text = "Over %s - an extractor can be built here" % planet.planet_name
|
||||
|
||||
|
||||
func refresh_option_states(planet: Node2D) -> void:
|
||||
for entry in entries:
|
||||
var definition: Resource = entry.definition
|
||||
entry.cost.show_price(GameState.building_costs(String(definition.definition_id)))
|
||||
var enabled: bool = GameState.is_building_unlocked(definition.definition_id)
|
||||
if definition.placement_mode == "planet":
|
||||
enabled = enabled and planet != null \
|
||||
and GameState.is_planet_conquered(planet.planet_id)
|
||||
entry.button.enabled = enabled
|
||||
entry.button.queue_redraw()
|
||||
|
||||
|
||||
func menu_band() -> Vector2:
|
||||
return MENU_LAYOUT.grid_band(status.offset_bottom, size.y)
|
||||
|
||||
|
||||
func menu_column_spacing(columns: int) -> float:
|
||||
var room: float = size.x - SIDE_MARGIN * 2.0
|
||||
if room <= 0.0:
|
||||
room = 672.0
|
||||
return maxf(MIN_SPACING, minf(NATURAL_SPACING, room / float(columns)))
|
||||
|
||||
|
||||
func menu_label_half(columns: int) -> float:
|
||||
return menu_column_spacing(columns) * LABEL_SHARE
|
||||
|
||||
|
||||
func measured_label_height(label: Label, text: String, columns: int) -> float:
|
||||
var font: Font = label.get_theme_font("font")
|
||||
var font_size: int = label.get_theme_font_size("font_size")
|
||||
if font == null or font_size <= 0 or text == "":
|
||||
return LABEL_HEIGHT
|
||||
var height: float = font.get_multiline_string_size(text,
|
||||
HORIZONTAL_ALIGNMENT_CENTER, menu_label_half(columns) * 2.0, font_size).y
|
||||
return maxf(LABEL_HEIGHT, height + LABEL_PADDING)
|
||||
|
||||
|
||||
func menu_label_height(columns: int) -> float:
|
||||
var tallest: float = LABEL_HEIGHT
|
||||
for entry in entries:
|
||||
if entry.label.visible:
|
||||
tallest = maxf(tallest,
|
||||
measured_label_height(entry.label, entry.label.text, columns))
|
||||
return tallest
|
||||
|
||||
|
||||
func menu_cost_height() -> float:
|
||||
var tallest: float = COST_HEIGHT
|
||||
for entry in entries:
|
||||
if entry.cost.visible and entry.cost.has_method("wanted_height"):
|
||||
tallest = maxf(tallest, float(entry.cost.wanted_height()) + COST_PADDING)
|
||||
return tallest
|
||||
|
||||
|
||||
func menu_cost_offset(columns: int) -> float:
|
||||
return LABEL_OFFSET + menu_label_height(columns) + LABEL_GAP
|
||||
|
||||
|
||||
func menu_row_height(columns: int) -> float:
|
||||
return menu_cost_offset(columns) + menu_cost_height()
|
||||
|
||||
|
||||
func menu_columns(count: int) -> int:
|
||||
var widest: int = maxi(mini(MAX_COLUMNS,
|
||||
int(floor((size.x - SIDE_MARGIN * 2.0) / MIN_SPACING))), 2)
|
||||
for columns in range(2, widest + 1):
|
||||
if _rows_fit(int(ceil(float(count) / float(columns))), columns):
|
||||
return columns
|
||||
return widest
|
||||
|
||||
|
||||
func menu_rows(count: int) -> int:
|
||||
var columns: int = menu_columns(count)
|
||||
return maxi(int(ceil(float(count) / float(columns))), 1)
|
||||
|
||||
|
||||
func _rows_fit(rows: int, columns: int) -> bool:
|
||||
var height: float = menu_row_height(columns)
|
||||
var band: Vector2 = menu_band()
|
||||
if rows <= 1:
|
||||
return band.y - band.x >= height
|
||||
return (band.y - band.x - height) / float(rows - 1) >= height
|
||||
|
||||
|
||||
func menu_row_top(row: int, rows: int, columns: int) -> float:
|
||||
return MENU_LAYOUT.grid_row_top(row, rows, menu_row_height(columns),
|
||||
menu_band(), NATURAL_SPACING)
|
||||
|
||||
|
||||
func _layout_entries() -> void:
|
||||
var shown: Array = []
|
||||
for entry in entries:
|
||||
var definition: Resource = entry.definition
|
||||
var entry_visible: bool = GameState.is_building_unlocked(definition.definition_id)
|
||||
entry.button.visible = entry_visible
|
||||
entry.label.visible = entry_visible
|
||||
entry.cost.visible = entry_visible
|
||||
if entry_visible:
|
||||
entry.cost.show_price(GameState.building_costs(String(definition.definition_id)))
|
||||
shown.append(entry)
|
||||
|
||||
var columns: int = menu_columns(shown.size())
|
||||
var rows: int = menu_rows(shown.size())
|
||||
var spacing: float = menu_column_spacing(columns)
|
||||
var label_half: float = menu_label_half(columns)
|
||||
var label_height: float = menu_label_height(columns)
|
||||
var cost_offset: float = menu_cost_offset(columns)
|
||||
var cost_height: float = menu_cost_height()
|
||||
for i in range(shown.size()):
|
||||
var row: int = i / columns
|
||||
var in_row: int = mini(shown.size() - row * columns, columns)
|
||||
var column: int = i % columns
|
||||
var cx: float = (float(column) - (float(in_row) - 1.0) * 0.5) * spacing
|
||||
var top: float = menu_row_top(row, rows, columns)
|
||||
MENU_LAYOUT.place_entry(shown[i].button, cx, top, BUTTON_HALF, BUTTON_HEIGHT)
|
||||
MENU_LAYOUT.place_entry(shown[i].label, cx, top + LABEL_OFFSET,
|
||||
label_half, label_height)
|
||||
MENU_LAYOUT.place_entry(shown[i].cost, cx, top + cost_offset,
|
||||
COST_HALF, cost_height)
|
||||
1
ui/menus/BuildMenu.gd.uid
Normal file
1
ui/menus/BuildMenu.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
|||
uid://b4fmal0r6so5
|
||||
544
ui/menus/BuildMenu.tscn
Normal file
544
ui/menus/BuildMenu.tscn
Normal file
|
|
@ -0,0 +1,544 @@
|
|||
[gd_scene load_steps=6 format=3]
|
||||
|
||||
[ext_resource type="Script" path="res://ui/IconButton.gd" id="10"]
|
||||
[ext_resource type="Script" path="res://ui/NeonPanel.gd" id="20"]
|
||||
[ext_resource type="Script" path="res://ui/ResourceBar.gd" id="24"]
|
||||
[ext_resource type="Script" path="res://ui/PriceTag.gd" id="price_tag"]
|
||||
[ext_resource type="Script" path="res://ui/menus/BuildMenu.gd" id="menu_script"]
|
||||
|
||||
[node name="BuildMenu" type="Control" groups=["modal_menus"]]
|
||||
visible = false
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
script = ExtResource("menu_script")
|
||||
|
||||
[node name="Backdrop" type="ColorRect" parent="."]
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
color = Color(0.03, 0.03, 0.08, 0.94)
|
||||
|
||||
[node name="TitleLabel" type="Label" parent="."]
|
||||
mouse_filter = 2
|
||||
anchor_right = 1.0
|
||||
offset_left = 24
|
||||
offset_top = 20
|
||||
offset_right = -24
|
||||
offset_bottom = 140
|
||||
text = "Build"
|
||||
horizontal_alignment = 1
|
||||
|
||||
[node name="Bar" type="Control" parent="."]
|
||||
mouse_filter = 2
|
||||
anchor_right = 1.0
|
||||
offset_left = 24.0
|
||||
offset_top = 148
|
||||
offset_right = -24.0
|
||||
offset_bottom = 330
|
||||
script = ExtResource("24")
|
||||
|
||||
[node name="StatusLabel" type="Label" parent="."]
|
||||
mouse_filter = 2
|
||||
anchor_right = 1.0
|
||||
offset_left = 24
|
||||
offset_top = 338
|
||||
offset_right = -24
|
||||
offset_bottom = 418
|
||||
theme_override_font_sizes/font_size = 40
|
||||
autowrap_mode = 2
|
||||
text = ""
|
||||
horizontal_alignment = 1
|
||||
|
||||
[node name="MothershipButton" type="Control" parent="."]
|
||||
anchor_left = 0.5
|
||||
anchor_right = 0.5
|
||||
anchor_top = 0.5
|
||||
anchor_bottom = 0.5
|
||||
offset_left = -204
|
||||
offset_right = -76
|
||||
offset_top = -300
|
||||
offset_bottom = -172
|
||||
script = ExtResource("10")
|
||||
icon = 8
|
||||
glow_color = Color(0.45, 0.9, 0.55, 1)
|
||||
|
||||
[node name="MothershipLabel" type="Label" parent="."]
|
||||
mouse_filter = 2
|
||||
anchor_left = 0.5
|
||||
anchor_right = 0.5
|
||||
anchor_top = 0.5
|
||||
anchor_bottom = 0.5
|
||||
offset_left = -290
|
||||
offset_right = 10
|
||||
offset_top = -166
|
||||
offset_bottom = -100
|
||||
theme_override_font_sizes/font_size = 32
|
||||
autowrap_mode = 2
|
||||
text = "Mothership"
|
||||
horizontal_alignment = 1
|
||||
|
||||
[node name="MothershipCost" type="Control" parent="."]
|
||||
mouse_filter = 2
|
||||
anchor_left = 0.5
|
||||
anchor_right = 0.5
|
||||
anchor_top = 0.5
|
||||
anchor_bottom = 0.5
|
||||
offset_left = -200
|
||||
offset_right = -80
|
||||
offset_top = -96
|
||||
offset_bottom = -44
|
||||
script = ExtResource("price_tag")
|
||||
|
||||
[node name="CrafterButton" type="Control" parent="."]
|
||||
anchor_left = 0.5
|
||||
anchor_right = 0.5
|
||||
anchor_top = 0.5
|
||||
anchor_bottom = 0.5
|
||||
offset_left = 76
|
||||
offset_right = 204
|
||||
offset_top = -300
|
||||
offset_bottom = -172
|
||||
script = ExtResource("10")
|
||||
icon = 9
|
||||
glow_color = Color(1, 0.72, 0.25, 1)
|
||||
|
||||
[node name="CrafterLabel" type="Label" parent="."]
|
||||
mouse_filter = 2
|
||||
anchor_left = 0.5
|
||||
anchor_right = 0.5
|
||||
anchor_top = 0.5
|
||||
anchor_bottom = 0.5
|
||||
offset_left = -10
|
||||
offset_right = 290
|
||||
offset_top = -166
|
||||
offset_bottom = -100
|
||||
theme_override_font_sizes/font_size = 32
|
||||
autowrap_mode = 2
|
||||
text = "Ship Crafter"
|
||||
horizontal_alignment = 1
|
||||
|
||||
[node name="CrafterCost" type="Control" parent="."]
|
||||
mouse_filter = 2
|
||||
anchor_left = 0.5
|
||||
anchor_right = 0.5
|
||||
anchor_top = 0.5
|
||||
anchor_bottom = 0.5
|
||||
offset_left = 80
|
||||
offset_right = 200
|
||||
offset_top = -96
|
||||
offset_bottom = -44
|
||||
script = ExtResource("price_tag")
|
||||
|
||||
[node name="CommandButton" type="Control" parent="."]
|
||||
anchor_left = 0.5
|
||||
anchor_right = 0.5
|
||||
anchor_top = 0.5
|
||||
anchor_bottom = 0.5
|
||||
offset_left = -204
|
||||
offset_right = -76
|
||||
offset_top = -10
|
||||
offset_bottom = 118
|
||||
script = ExtResource("10")
|
||||
icon = 10
|
||||
glow_color = Color(0.55, 0.6, 1, 1)
|
||||
|
||||
[node name="CommandLabel" type="Label" parent="."]
|
||||
mouse_filter = 2
|
||||
anchor_left = 0.5
|
||||
anchor_right = 0.5
|
||||
anchor_top = 0.5
|
||||
anchor_bottom = 0.5
|
||||
offset_left = -290
|
||||
offset_right = 10
|
||||
offset_top = 124
|
||||
offset_bottom = 190
|
||||
theme_override_font_sizes/font_size = 32
|
||||
autowrap_mode = 2
|
||||
text = "Command Center"
|
||||
horizontal_alignment = 1
|
||||
|
||||
[node name="CommandCost" type="Control" parent="."]
|
||||
mouse_filter = 2
|
||||
anchor_left = 0.5
|
||||
anchor_right = 0.5
|
||||
anchor_top = 0.5
|
||||
anchor_bottom = 0.5
|
||||
offset_left = -200
|
||||
offset_right = -80
|
||||
offset_top = 194
|
||||
offset_bottom = 246
|
||||
script = ExtResource("price_tag")
|
||||
|
||||
[node name="ExtractorButton" type="Control" parent="."]
|
||||
anchor_left = 0.5
|
||||
anchor_right = 0.5
|
||||
anchor_top = 0.5
|
||||
anchor_bottom = 0.5
|
||||
offset_left = 76
|
||||
offset_right = 204
|
||||
offset_top = -10
|
||||
offset_bottom = 118
|
||||
script = ExtResource("10")
|
||||
icon = 11
|
||||
glow_color = Color(0, 0.62, 0.7, 1)
|
||||
|
||||
[node name="ExtractorLabel" type="Label" parent="."]
|
||||
mouse_filter = 2
|
||||
anchor_left = 0.5
|
||||
anchor_right = 0.5
|
||||
anchor_top = 0.5
|
||||
anchor_bottom = 0.5
|
||||
offset_left = -10
|
||||
offset_right = 290
|
||||
offset_top = 124
|
||||
offset_bottom = 190
|
||||
theme_override_font_sizes/font_size = 32
|
||||
autowrap_mode = 2
|
||||
text = "Extractor"
|
||||
horizontal_alignment = 1
|
||||
|
||||
[node name="ExtractorCost" type="Control" parent="."]
|
||||
mouse_filter = 2
|
||||
anchor_left = 0.5
|
||||
anchor_right = 0.5
|
||||
anchor_top = 0.5
|
||||
anchor_bottom = 0.5
|
||||
offset_left = 80
|
||||
offset_right = 200
|
||||
offset_top = 194
|
||||
offset_bottom = 246
|
||||
script = ExtResource("price_tag")
|
||||
|
||||
[node name="TransportHubButton" type="Control" parent="."]
|
||||
anchor_left = 0.5
|
||||
anchor_right = 0.5
|
||||
anchor_top = 0.5
|
||||
anchor_bottom = 0.5
|
||||
offset_left = -64
|
||||
offset_right = 64
|
||||
offset_top = 280
|
||||
offset_bottom = 408
|
||||
script = ExtResource("10")
|
||||
icon = 12
|
||||
glow_color = Color(0.95, 0.55, 0.85, 1)
|
||||
|
||||
[node name="TransportHubLabel" type="Label" parent="."]
|
||||
mouse_filter = 2
|
||||
anchor_left = 0.5
|
||||
anchor_right = 0.5
|
||||
anchor_top = 0.5
|
||||
anchor_bottom = 0.5
|
||||
offset_left = -150
|
||||
offset_right = 150
|
||||
offset_top = 414
|
||||
offset_bottom = 480
|
||||
theme_override_font_sizes/font_size = 32
|
||||
autowrap_mode = 2
|
||||
text = "Transport Hub"
|
||||
horizontal_alignment = 1
|
||||
|
||||
[node name="TransportHubCost" type="Control" parent="."]
|
||||
mouse_filter = 2
|
||||
anchor_left = 0.5
|
||||
anchor_right = 0.5
|
||||
anchor_top = 0.5
|
||||
anchor_bottom = 0.5
|
||||
offset_left = -60
|
||||
offset_right = 60
|
||||
offset_top = 484
|
||||
offset_bottom = 536
|
||||
script = ExtResource("price_tag")
|
||||
|
||||
[node name="ShipLabButton" type="Control" parent="."]
|
||||
anchor_left = 0.5
|
||||
anchor_right = 0.5
|
||||
anchor_top = 0.5
|
||||
anchor_bottom = 0.5
|
||||
offset_left = 76
|
||||
offset_right = 204
|
||||
offset_top = 280
|
||||
offset_bottom = 408
|
||||
script = ExtResource("10")
|
||||
icon = 13
|
||||
glow_color = Color(0.55, 0.95, 0.9, 1)
|
||||
|
||||
[node name="ShipLabLabel" type="Label" parent="."]
|
||||
mouse_filter = 2
|
||||
anchor_left = 0.5
|
||||
anchor_right = 0.5
|
||||
anchor_top = 0.5
|
||||
anchor_bottom = 0.5
|
||||
offset_left = -10
|
||||
offset_right = 290
|
||||
offset_top = 414
|
||||
offset_bottom = 480
|
||||
theme_override_font_sizes/font_size = 32
|
||||
autowrap_mode = 2
|
||||
text = "Ship Lab"
|
||||
horizontal_alignment = 1
|
||||
|
||||
[node name="ShipLabCost" type="Control" parent="."]
|
||||
mouse_filter = 2
|
||||
anchor_left = 0.5
|
||||
anchor_right = 0.5
|
||||
anchor_top = 0.5
|
||||
anchor_bottom = 0.5
|
||||
offset_left = 80
|
||||
offset_right = 200
|
||||
offset_top = 484
|
||||
offset_bottom = 536
|
||||
script = ExtResource("price_tag")
|
||||
|
||||
[node name="GasBurnerButton" type="Control" parent="."]
|
||||
anchor_left = 0.5
|
||||
anchor_right = 0.5
|
||||
anchor_top = 0.5
|
||||
anchor_bottom = 0.5
|
||||
offset_left = -64
|
||||
offset_right = 64
|
||||
offset_top = 570
|
||||
offset_bottom = 698
|
||||
script = ExtResource("10")
|
||||
icon = 33
|
||||
glow_color = Color(0.95, 0.35, 0.15, 1)
|
||||
|
||||
[node name="GasBurnerLabel" type="Label" parent="."]
|
||||
mouse_filter = 2
|
||||
anchor_left = 0.5
|
||||
anchor_right = 0.5
|
||||
anchor_top = 0.5
|
||||
anchor_bottom = 0.5
|
||||
offset_left = -150
|
||||
offset_right = 150
|
||||
offset_top = 704
|
||||
offset_bottom = 770
|
||||
theme_override_font_sizes/font_size = 32
|
||||
autowrap_mode = 2
|
||||
text = "Gas Burner"
|
||||
horizontal_alignment = 1
|
||||
|
||||
[node name="GasBurnerCost" type="Control" parent="."]
|
||||
mouse_filter = 2
|
||||
anchor_left = 0.5
|
||||
anchor_right = 0.5
|
||||
anchor_top = 0.5
|
||||
anchor_bottom = 0.5
|
||||
offset_left = -60
|
||||
offset_right = 60
|
||||
offset_top = 774
|
||||
offset_bottom = 826
|
||||
script = ExtResource("price_tag")
|
||||
|
||||
[node name="OutpostButton" type="Control" parent="."]
|
||||
anchor_left = 0.5
|
||||
anchor_right = 0.5
|
||||
anchor_top = 0.5
|
||||
anchor_bottom = 0.5
|
||||
offset_left = -64
|
||||
offset_right = 64
|
||||
offset_top = 830
|
||||
offset_bottom = 958
|
||||
script = ExtResource("10")
|
||||
icon = 40
|
||||
glow_color = Color(0.72, 0.86, 0.45, 1)
|
||||
|
||||
[node name="OutpostLabel" type="Label" parent="."]
|
||||
mouse_filter = 2
|
||||
anchor_left = 0.5
|
||||
anchor_right = 0.5
|
||||
anchor_top = 0.5
|
||||
anchor_bottom = 0.5
|
||||
offset_left = -150
|
||||
offset_right = 150
|
||||
offset_top = 964
|
||||
offset_bottom = 1030
|
||||
theme_override_font_sizes/font_size = 32
|
||||
autowrap_mode = 2
|
||||
text = "Outpost"
|
||||
horizontal_alignment = 1
|
||||
|
||||
[node name="OutpostCost" type="Control" parent="."]
|
||||
mouse_filter = 2
|
||||
anchor_left = 0.5
|
||||
anchor_right = 0.5
|
||||
anchor_top = 0.5
|
||||
anchor_bottom = 0.5
|
||||
offset_left = -60
|
||||
offset_right = 60
|
||||
offset_top = 1034
|
||||
offset_bottom = 1086
|
||||
script = ExtResource("price_tag")
|
||||
|
||||
[node name="PlanningButton" type="Control" parent="."]
|
||||
anchor_left = 0.5
|
||||
anchor_right = 0.5
|
||||
anchor_top = 0.5
|
||||
anchor_bottom = 0.5
|
||||
offset_left = -64
|
||||
offset_right = 64
|
||||
offset_top = 1090
|
||||
offset_bottom = 1218
|
||||
script = ExtResource("10")
|
||||
icon = 41
|
||||
glow_color = Color(0.62, 0.74, 0.92, 1)
|
||||
|
||||
[node name="PlanningLabel" type="Label" parent="."]
|
||||
mouse_filter = 2
|
||||
anchor_left = 0.5
|
||||
anchor_right = 0.5
|
||||
anchor_top = 0.5
|
||||
anchor_bottom = 0.5
|
||||
offset_left = -150
|
||||
offset_right = 150
|
||||
offset_top = 1224
|
||||
offset_bottom = 1290
|
||||
theme_override_font_sizes/font_size = 32
|
||||
autowrap_mode = 2
|
||||
text = "Planning Center"
|
||||
horizontal_alignment = 1
|
||||
|
||||
[node name="PlanningCost" type="Control" parent="."]
|
||||
mouse_filter = 2
|
||||
anchor_left = 0.5
|
||||
anchor_right = 0.5
|
||||
anchor_top = 0.5
|
||||
anchor_bottom = 0.5
|
||||
offset_left = -60
|
||||
offset_right = 60
|
||||
offset_top = 1294
|
||||
offset_bottom = 1346
|
||||
script = ExtResource("price_tag")
|
||||
|
||||
[node name="WorkshopButton" type="Control" parent="."]
|
||||
anchor_left = 0.5
|
||||
anchor_right = 0.5
|
||||
anchor_top = 0.5
|
||||
anchor_bottom = 0.5
|
||||
offset_left = -64
|
||||
offset_right = 64
|
||||
offset_top = 1350
|
||||
offset_bottom = 1478
|
||||
script = ExtResource("10")
|
||||
icon = 42
|
||||
glow_color = Color(0.5, 0.95, 0.8, 1)
|
||||
|
||||
[node name="WorkshopLabel" type="Label" parent="."]
|
||||
mouse_filter = 2
|
||||
anchor_left = 0.5
|
||||
anchor_right = 0.5
|
||||
anchor_top = 0.5
|
||||
anchor_bottom = 0.5
|
||||
offset_left = -150
|
||||
offset_right = 150
|
||||
offset_top = 1484
|
||||
offset_bottom = 1550
|
||||
theme_override_font_sizes/font_size = 32
|
||||
autowrap_mode = 2
|
||||
text = "Spacial Workshop"
|
||||
horizontal_alignment = 1
|
||||
|
||||
[node name="WorkshopCost" type="Control" parent="."]
|
||||
mouse_filter = 2
|
||||
anchor_left = 0.5
|
||||
anchor_right = 0.5
|
||||
anchor_top = 0.5
|
||||
anchor_bottom = 0.5
|
||||
offset_left = -60
|
||||
offset_right = 60
|
||||
offset_top = 1554
|
||||
offset_bottom = 1606
|
||||
script = ExtResource("price_tag")
|
||||
|
||||
[node name="CloseButton" type="Control" parent="."]
|
||||
anchor_left = 1.0
|
||||
anchor_right = 1.0
|
||||
offset_left = -172
|
||||
offset_right = -24
|
||||
offset_top = 24
|
||||
offset_bottom = 172
|
||||
script = ExtResource("10")
|
||||
icon = 1
|
||||
|
||||
[node name="InfoPopup" type="Control" parent="." groups=["modal_menus"]]
|
||||
visible = false
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
|
||||
[node name="Dim" type="ColorRect" parent="InfoPopup"]
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
color = Color(0.01, 0.01, 0.03, 0.55)
|
||||
|
||||
[node name="Panel" type="Control" parent="InfoPopup"]
|
||||
mouse_filter = 2
|
||||
anchor_left = 0.5
|
||||
anchor_right = 0.5
|
||||
anchor_top = 0.5
|
||||
anchor_bottom = 0.5
|
||||
offset_left = -352
|
||||
offset_right = 352
|
||||
offset_top = -600
|
||||
offset_bottom = 600
|
||||
script = ExtResource("20")
|
||||
glow_color = Color(0, 0.62, 0.7, 1)
|
||||
|
||||
[node name="TitleLabel" type="Label" parent="InfoPopup/Panel"]
|
||||
mouse_filter = 2
|
||||
anchor_right = 1.0
|
||||
offset_left = 44
|
||||
offset_right = -44
|
||||
offset_top = 30
|
||||
offset_bottom = 150
|
||||
text = ""
|
||||
horizontal_alignment = 1
|
||||
|
||||
[node name="MessageLabel" type="Label" parent="InfoPopup/Panel"]
|
||||
mouse_filter = 2
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
offset_left = 44
|
||||
offset_right = -44
|
||||
offset_top = 160
|
||||
offset_bottom = -440
|
||||
theme_override_font_sizes/font_size = 48
|
||||
text = ""
|
||||
horizontal_alignment = 1
|
||||
vertical_alignment = 1
|
||||
autowrap_mode = 2
|
||||
|
||||
[node name="CostNumber" type="Control" parent="InfoPopup/Panel"]
|
||||
mouse_filter = 2
|
||||
anchor_left = 0.5
|
||||
anchor_right = 0.5
|
||||
anchor_top = 1.0
|
||||
anchor_bottom = 1.0
|
||||
offset_left = -70
|
||||
offset_right = 90
|
||||
offset_top = -424
|
||||
offset_bottom = -334
|
||||
script = ExtResource("price_tag")
|
||||
|
||||
[node name="BuildButton" type="Control" parent="InfoPopup/Panel"]
|
||||
anchor_left = 0.5
|
||||
anchor_right = 0.5
|
||||
anchor_top = 1.0
|
||||
anchor_bottom = 1.0
|
||||
offset_left = -200
|
||||
offset_right = -40
|
||||
offset_top = -300
|
||||
offset_bottom = -140
|
||||
script = ExtResource("10")
|
||||
icon = 5
|
||||
glow_color = Color(0.45, 0.9, 0.55, 1)
|
||||
|
||||
[node name="CloseButton" type="Control" parent="InfoPopup/Panel"]
|
||||
anchor_left = 0.5
|
||||
anchor_right = 0.5
|
||||
anchor_top = 1.0
|
||||
anchor_bottom = 1.0
|
||||
offset_left = 40
|
||||
offset_right = 200
|
||||
offset_top = -300
|
||||
offset_bottom = -140
|
||||
script = ExtResource("10")
|
||||
icon = 1
|
||||
glow_color = Color(0, 0.62, 0.7, 1)
|
||||
144
ui/menus/CraftMenu.gd
Normal file
144
ui/menus/CraftMenu.gd
Normal file
|
|
@ -0,0 +1,144 @@
|
|||
extends "res://ui/menus/ModalMenu.gd"
|
||||
|
||||
signal craft_requested(vessel_type: String)
|
||||
signal queue_cancel_requested(index: int)
|
||||
|
||||
const VESSEL_DEFINITIONS = preload("res://vessels/VesselDefinitions.gd")
|
||||
const MENU_LAYOUT = preload("res://ui/menus/MenuLayout.gd")
|
||||
const PRICE_TAG = preload("res://ui/PriceTag.gd")
|
||||
const COLUMNS := 3
|
||||
const ROW_PITCH := 260.0
|
||||
const COLUMN_X := 190.0
|
||||
const BUTTON_HALF := 56.0
|
||||
const BUTTON_HEIGHT := 100.0
|
||||
const LABEL_HALF := 92.0
|
||||
const LABEL_HEIGHT := 44.0
|
||||
const LABEL_OFFSET := 106.0
|
||||
const PRICE_HALF := 92.0
|
||||
const PRICE_HEIGHT := 86.0
|
||||
const PRICE_OFFSET := 154.0
|
||||
|
||||
@onready var status: Label = $StatusLabel
|
||||
@onready var queue_detail: Label = $QueueDetail
|
||||
@onready var resource_bar: Control = $Bar
|
||||
@onready var vessel_buttons: Array = [$InterceptorButton, $ShieldButton,
|
||||
$GasBomberButton, $CarrierButton, $LaserButton, $DistorderButton]
|
||||
@onready var vessel_labels: Array = [$InterceptorLabel, $ShieldLabel,
|
||||
$GasBomberLabel, $CarrierLabel, $LaserLabel, $DistorderLabel]
|
||||
@onready var queue_slots: Array = [$QueueSlot0, $QueueSlot1, $QueueSlot2, $QueueSlot3]
|
||||
|
||||
var building_id: int = 0
|
||||
var message: String = ""
|
||||
var message_until: int = 0
|
||||
var price_tags: Array = []
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
super._ready()
|
||||
_build_price_tags()
|
||||
for i in range(mini(vessel_buttons.size(), VESSEL_DEFINITIONS.fleet().size())):
|
||||
var definition: Resource = VESSEL_DEFINITIONS.fleet()[i]
|
||||
vessel_buttons[i].pressed.connect(
|
||||
func(): craft_requested.emit(String(definition.definition_id)))
|
||||
for i in range(queue_slots.size()):
|
||||
queue_slots[i].pressed.connect(func(): queue_cancel_requested.emit(i))
|
||||
_layout_entries()
|
||||
|
||||
|
||||
func open_for(next_building_id: int) -> void:
|
||||
building_id = next_building_id
|
||||
resource_bar.building_id = building_id
|
||||
open_menu()
|
||||
refresh()
|
||||
|
||||
|
||||
func close_menu() -> void:
|
||||
super.close_menu()
|
||||
building_id = 0
|
||||
|
||||
|
||||
func say(next_message: String) -> void:
|
||||
message = next_message
|
||||
message_until = Time.get_ticks_msec() + 3000
|
||||
refresh()
|
||||
|
||||
|
||||
func refresh() -> void:
|
||||
status.text = ""
|
||||
var definitions: Array = VESSEL_DEFINITIONS.fleet()
|
||||
for i in range(mini(definitions.size(), vessel_buttons.size())):
|
||||
var definition: Resource = definitions[i]
|
||||
var button: Control = vessel_buttons[i]
|
||||
vessel_labels[i].text = String(definition.display_name)
|
||||
if i < price_tags.size():
|
||||
price_tags[i].set_costs(GameState.product_costs(definition.definition_id))
|
||||
button.icon = definition.icon
|
||||
button.glow_color = definition.glow_color
|
||||
button.enabled = GameState.vessel_is_unlocked(definition.definition_id)
|
||||
button.queue_redraw()
|
||||
refresh_queue()
|
||||
if message != "":
|
||||
if Time.get_ticks_msec() < message_until:
|
||||
status.text = "%s\n%s" % [message, status.text]
|
||||
else:
|
||||
message = ""
|
||||
|
||||
|
||||
func refresh_queue() -> void:
|
||||
var orders: Array = GameState.order_list(building_id)
|
||||
for i in range(queue_slots.size()):
|
||||
var slot: Control = queue_slots[i]
|
||||
slot.visible = i < orders.size()
|
||||
if not slot.visible:
|
||||
continue
|
||||
var order: Dictionary = orders[i]
|
||||
var definition: Resource = VESSEL_DEFINITIONS.get_definition(String(order.product))
|
||||
slot.icon = definition.icon
|
||||
slot.glow_color = vessel_colour(String(order.product))
|
||||
slot.enabled = bool(order.started)
|
||||
slot.queue_redraw()
|
||||
if orders.is_empty():
|
||||
queue_detail.text = "Nothing queued"
|
||||
return
|
||||
var head: Dictionary = orders[0]
|
||||
if bool(head.started):
|
||||
queue_detail.text = "Building %s %d%%\nTap to cancel" % [
|
||||
GameState.vessel_name(String(head.product)),
|
||||
int(round(float(head.progress) * 100.0))]
|
||||
else:
|
||||
queue_detail.text = "%s waiting for resources\nTap to cancel" \
|
||||
% GameState.vessel_name(String(head.product))
|
||||
|
||||
|
||||
func vessel_colour(vessel_type: String) -> Color:
|
||||
var definition: Resource = VESSEL_DEFINITIONS.get_definition(vessel_type)
|
||||
return definition.glow_color if definition != null else Color(0.25, 0.85, 1.0)
|
||||
|
||||
|
||||
func _build_price_tags() -> void:
|
||||
for i in range(vessel_buttons.size()):
|
||||
var tag: Control = PRICE_TAG.new()
|
||||
tag.name = "CraftPrice%d" % i
|
||||
tag.set_anchors_preset(Control.PRESET_CENTER)
|
||||
add_child(tag)
|
||||
price_tags.append(tag)
|
||||
|
||||
|
||||
func row_height() -> float:
|
||||
return PRICE_OFFSET + PRICE_HEIGHT
|
||||
|
||||
|
||||
func _layout_entries() -> void:
|
||||
var rows: int = maxi(int(ceil(float(vessel_buttons.size()) / float(COLUMNS))), 1)
|
||||
var band: Vector2 = MENU_LAYOUT.grid_band(status.offset_bottom, size.y)
|
||||
for i in range(vessel_buttons.size()):
|
||||
var row: int = i / COLUMNS
|
||||
var column: int = i % COLUMNS
|
||||
var cx: float = (float(column) - 1.0) * COLUMN_X
|
||||
var top: float = MENU_LAYOUT.grid_row_top(row, rows, row_height(), band, ROW_PITCH)
|
||||
MENU_LAYOUT.place_entry(vessel_buttons[i], cx, top, BUTTON_HALF, BUTTON_HEIGHT)
|
||||
MENU_LAYOUT.place_entry(vessel_labels[i], cx, top + LABEL_OFFSET,
|
||||
LABEL_HALF, LABEL_HEIGHT)
|
||||
if i < price_tags.size():
|
||||
MENU_LAYOUT.place_entry(price_tags[i], cx, top + PRICE_OFFSET,
|
||||
PRICE_HALF, PRICE_HEIGHT)
|
||||
1
ui/menus/CraftMenu.gd.uid
Normal file
1
ui/menus/CraftMenu.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
|||
uid://5oywglpqem62
|
||||
308
ui/menus/CraftMenu.tscn
Normal file
308
ui/menus/CraftMenu.tscn
Normal file
|
|
@ -0,0 +1,308 @@
|
|||
[gd_scene load_steps=4 format=3]
|
||||
|
||||
[ext_resource type="Script" path="res://ui/IconButton.gd" id="10"]
|
||||
[ext_resource type="Script" path="res://ui/ResourceBar.gd" id="24"]
|
||||
[ext_resource type="Script" path="res://ui/menus/CraftMenu.gd" id="menu_script"]
|
||||
|
||||
[node name="CraftMenu" type="Control" groups=["modal_menus"]]
|
||||
visible = false
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
script = ExtResource("menu_script")
|
||||
|
||||
[node name="Backdrop" type="ColorRect" parent="."]
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
color = Color(0.03, 0.03, 0.08, 0.94)
|
||||
|
||||
[node name="TitleLabel" type="Label" parent="."]
|
||||
mouse_filter = 2
|
||||
anchor_right = 1.0
|
||||
offset_left = 24
|
||||
offset_top = 20
|
||||
offset_right = -200
|
||||
offset_bottom = 82
|
||||
text = "Build a ship"
|
||||
horizontal_alignment = 1
|
||||
|
||||
[node name="Bar" type="Control" parent="."]
|
||||
anchor_right = 1.0
|
||||
mouse_filter = 2
|
||||
offset_left = 24
|
||||
offset_top = 148
|
||||
offset_right = -24
|
||||
offset_bottom = 330
|
||||
script = ExtResource("24")
|
||||
|
||||
[node name="StatusLabel" type="Label" parent="."]
|
||||
mouse_filter = 2
|
||||
anchor_right = 1.0
|
||||
offset_left = 24
|
||||
offset_top = 344
|
||||
offset_right = -200
|
||||
offset_bottom = 490
|
||||
theme_override_font_sizes/font_size = 36
|
||||
autowrap_mode = 2
|
||||
text = ""
|
||||
horizontal_alignment = 1
|
||||
|
||||
[node name="InterceptorButton" type="Control" parent="."]
|
||||
anchor_left = 0.5
|
||||
anchor_right = 0.5
|
||||
anchor_top = 0.5
|
||||
anchor_bottom = 0.5
|
||||
offset_left = -310
|
||||
offset_right = -245
|
||||
offset_top = -100
|
||||
offset_bottom = 48
|
||||
script = ExtResource("10")
|
||||
icon = 2
|
||||
|
||||
[node name="InterceptorLabel" type="Label" parent="."]
|
||||
mouse_filter = 2
|
||||
anchor_left = 0.5
|
||||
anchor_right = 0.5
|
||||
anchor_top = 0.5
|
||||
anchor_bottom = 0.5
|
||||
offset_left = -330
|
||||
offset_right = -225
|
||||
offset_top = 56
|
||||
offset_bottom = 136
|
||||
theme_override_font_sizes/font_size = 24
|
||||
text = "Interceptor"
|
||||
horizontal_alignment = 1
|
||||
|
||||
[node name="ShieldButton" type="Control" parent="."]
|
||||
anchor_left = 0.5
|
||||
anchor_right = 0.5
|
||||
anchor_top = 0.5
|
||||
anchor_bottom = 0.5
|
||||
offset_left = -221
|
||||
offset_right = -156
|
||||
offset_top = -100
|
||||
offset_bottom = 48
|
||||
script = ExtResource("10")
|
||||
icon = 2
|
||||
glow_color = Color(0.45, 0.8, 1, 1)
|
||||
|
||||
[node name="ShieldLabel" type="Label" parent="."]
|
||||
mouse_filter = 2
|
||||
anchor_left = 0.5
|
||||
anchor_right = 0.5
|
||||
anchor_top = 0.5
|
||||
anchor_bottom = 0.5
|
||||
offset_left = -241
|
||||
offset_right = -136
|
||||
offset_top = 56
|
||||
offset_bottom = 136
|
||||
theme_override_font_sizes/font_size = 24
|
||||
autowrap_mode = 2
|
||||
text = "Shield Vessel"
|
||||
horizontal_alignment = 1
|
||||
|
||||
[node name="GasBomberButton" type="Control" parent="."]
|
||||
anchor_left = 0.5
|
||||
anchor_right = 0.5
|
||||
anchor_top = 0.5
|
||||
anchor_bottom = 0.5
|
||||
offset_left = -132
|
||||
offset_right = -67
|
||||
offset_top = -100
|
||||
offset_bottom = 28
|
||||
script = ExtResource("10")
|
||||
icon = 31
|
||||
glow_color = Color(0.96, 0.32, 0.78, 1)
|
||||
|
||||
[node name="GasBomberLabel" type="Label" parent="."]
|
||||
mouse_filter = 2
|
||||
anchor_left = 0.5
|
||||
anchor_right = 0.5
|
||||
anchor_top = 0.5
|
||||
anchor_bottom = 0.5
|
||||
offset_left = -152
|
||||
offset_right = -47
|
||||
offset_top = 56
|
||||
offset_bottom = 150
|
||||
theme_override_font_sizes/font_size = 24
|
||||
autowrap_mode = 2
|
||||
text = "Gas Bomber"
|
||||
horizontal_alignment = 1
|
||||
|
||||
[node name="CarrierButton" type="Control" parent="."]
|
||||
anchor_left = 0.5
|
||||
anchor_right = 0.5
|
||||
anchor_top = 0.5
|
||||
anchor_bottom = 0.5
|
||||
offset_left = -43
|
||||
offset_right = 22
|
||||
offset_top = -100
|
||||
offset_bottom = 48
|
||||
script = ExtResource("10")
|
||||
icon = 34
|
||||
glow_color = Color(1, 0.78, 0.3, 1)
|
||||
|
||||
[node name="CarrierLabel" type="Label" parent="."]
|
||||
mouse_filter = 2
|
||||
anchor_left = 0.5
|
||||
anchor_right = 0.5
|
||||
anchor_top = 0.5
|
||||
anchor_bottom = 0.5
|
||||
offset_left = -63
|
||||
offset_right = 42
|
||||
offset_top = 56
|
||||
offset_bottom = 136
|
||||
theme_override_font_sizes/font_size = 24
|
||||
autowrap_mode = 2
|
||||
text = "Carrier"
|
||||
horizontal_alignment = 1
|
||||
|
||||
[node name="LaserButton" type="Control" parent="."]
|
||||
anchor_left = 0.5
|
||||
anchor_right = 0.5
|
||||
anchor_top = 0.5
|
||||
anchor_bottom = 0.5
|
||||
offset_left = 46
|
||||
offset_right = 111
|
||||
offset_top = -100
|
||||
offset_bottom = 48
|
||||
script = ExtResource("10")
|
||||
icon = 35
|
||||
glow_color = Color(0.3, 0.9, 1, 1)
|
||||
|
||||
[node name="LaserLabel" type="Label" parent="."]
|
||||
mouse_filter = 2
|
||||
anchor_left = 0.5
|
||||
anchor_right = 0.5
|
||||
anchor_top = 0.5
|
||||
anchor_bottom = 0.5
|
||||
offset_left = 26
|
||||
offset_right = 131
|
||||
offset_top = 56
|
||||
offset_bottom = 136
|
||||
theme_override_font_sizes/font_size = 24
|
||||
autowrap_mode = 2
|
||||
text = "Laser Ship"
|
||||
horizontal_alignment = 1
|
||||
|
||||
[node name="DistorderButton" type="Control" parent="."]
|
||||
anchor_left = 0.5
|
||||
anchor_right = 0.5
|
||||
anchor_top = 0.5
|
||||
anchor_bottom = 0.5
|
||||
offset_left = 135
|
||||
offset_right = 200
|
||||
offset_top = -100
|
||||
offset_bottom = 48
|
||||
script = ExtResource("10")
|
||||
icon = 37
|
||||
glow_color = Color(0.7, 0.3, 1, 1)
|
||||
|
||||
[node name="DistorderLabel" type="Label" parent="."]
|
||||
mouse_filter = 2
|
||||
anchor_left = 0.5
|
||||
anchor_right = 0.5
|
||||
anchor_top = 0.5
|
||||
anchor_bottom = 0.5
|
||||
offset_left = 115
|
||||
offset_right = 220
|
||||
offset_top = 56
|
||||
offset_bottom = 136
|
||||
theme_override_font_sizes/font_size = 24
|
||||
autowrap_mode = 2
|
||||
text = "Distorder"
|
||||
horizontal_alignment = 1
|
||||
|
||||
[node name="QueueLabel" type="Label" parent="."]
|
||||
mouse_filter = 2
|
||||
anchor_left = 1.0
|
||||
anchor_top = 0.5
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 0.5
|
||||
offset_left = -200
|
||||
offset_right = -10
|
||||
offset_top = -450
|
||||
offset_bottom = -390
|
||||
theme_override_font_sizes/font_size = 26
|
||||
autowrap_mode = 2
|
||||
horizontal_alignment = 1
|
||||
text = "Queue"
|
||||
|
||||
[node name="QueueDetail" type="Label" parent="."]
|
||||
mouse_filter = 2
|
||||
anchor_right = 1.0
|
||||
anchor_top = 1.0
|
||||
anchor_bottom = 1.0
|
||||
offset_left = 24
|
||||
offset_right = -24
|
||||
offset_top = -150
|
||||
offset_bottom = -30
|
||||
theme_override_font_sizes/font_size = 26
|
||||
autowrap_mode = 2
|
||||
horizontal_alignment = 1
|
||||
text = ""
|
||||
|
||||
[node name="QueueSlot0" type="Control" parent="."]
|
||||
visible = false
|
||||
anchor_left = 1.0
|
||||
anchor_top = 0.5
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 0.5
|
||||
offset_left = -140
|
||||
offset_right = -30
|
||||
offset_top = -380
|
||||
offset_bottom = -270
|
||||
script = ExtResource("10")
|
||||
icon = 2
|
||||
glow_color = Color(0.25, 0.85, 1, 1)
|
||||
|
||||
[node name="QueueSlot1" type="Control" parent="."]
|
||||
visible = false
|
||||
anchor_left = 1.0
|
||||
anchor_top = 0.5
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 0.5
|
||||
offset_left = -140
|
||||
offset_right = -30
|
||||
offset_top = -262
|
||||
offset_bottom = -152
|
||||
script = ExtResource("10")
|
||||
icon = 2
|
||||
glow_color = Color(0.25, 0.85, 1, 1)
|
||||
|
||||
[node name="QueueSlot2" type="Control" parent="."]
|
||||
visible = false
|
||||
anchor_left = 1.0
|
||||
anchor_top = 0.5
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 0.5
|
||||
offset_left = -140
|
||||
offset_right = -30
|
||||
offset_top = -144
|
||||
offset_bottom = -34
|
||||
script = ExtResource("10")
|
||||
icon = 2
|
||||
glow_color = Color(0.25, 0.85, 1, 1)
|
||||
|
||||
[node name="QueueSlot3" type="Control" parent="."]
|
||||
visible = false
|
||||
anchor_left = 1.0
|
||||
anchor_top = 0.5
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 0.5
|
||||
offset_left = -140
|
||||
offset_right = -30
|
||||
offset_top = -26
|
||||
offset_bottom = 84
|
||||
script = ExtResource("10")
|
||||
icon = 2
|
||||
glow_color = Color(0.25, 0.85, 1, 1)
|
||||
|
||||
[node name="CloseButton" type="Control" parent="."]
|
||||
anchor_left = 1.0
|
||||
anchor_right = 1.0
|
||||
offset_left = -140
|
||||
offset_right = -24
|
||||
offset_top = 20
|
||||
offset_bottom = 136
|
||||
script = ExtResource("10")
|
||||
icon = 1
|
||||
36
ui/menus/FormationMenu.gd
Normal file
36
ui/menus/FormationMenu.gd
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
extends "res://ui/menus/ModalMenu.gd"
|
||||
|
||||
signal formation_changed
|
||||
signal reset_requested
|
||||
|
||||
@onready var editor: Control = $Editor
|
||||
@onready var reset_button: Control = $ResetButton
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
super._ready()
|
||||
reset_button.pressed.connect(func(): reset_requested.emit())
|
||||
editor.formation_changed.connect(func(): formation_changed.emit())
|
||||
|
||||
|
||||
func open_menu() -> void:
|
||||
super.open_menu()
|
||||
editor.queue_redraw()
|
||||
|
||||
|
||||
func redraw() -> void:
|
||||
editor.queue_redraw()
|
||||
|
||||
|
||||
func handle_unhandled_input(event: InputEvent) -> bool:
|
||||
if not visible:
|
||||
return false
|
||||
if event is InputEventScreenTouch:
|
||||
editor.handle_touch(event)
|
||||
elif event is InputEventScreenDrag:
|
||||
editor.handle_drag(event)
|
||||
elif event is InputEventMouseButton:
|
||||
editor.handle_mouse_button(event)
|
||||
elif event is InputEventMouseMotion:
|
||||
editor.handle_mouse_motion(event)
|
||||
return true
|
||||
1
ui/menus/FormationMenu.gd.uid
Normal file
1
ui/menus/FormationMenu.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
|||
uid://bigv0ubmyddob
|
||||
90
ui/menus/FormationMenu.tscn
Normal file
90
ui/menus/FormationMenu.tscn
Normal file
|
|
@ -0,0 +1,90 @@
|
|||
[gd_scene load_steps=4 format=3]
|
||||
|
||||
[ext_resource type="Script" path="res://ui/IconButton.gd" id="10"]
|
||||
[ext_resource type="Script" path="res://ui/FormationEditor.gd" id="17"]
|
||||
[ext_resource type="Script" path="res://ui/menus/FormationMenu.gd" id="menu_script"]
|
||||
|
||||
[node name="FormationMenu" type="Control" groups=["modal_menus"]]
|
||||
visible = false
|
||||
mouse_filter = 2
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
script = ExtResource("menu_script")
|
||||
|
||||
[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.94)
|
||||
|
||||
[node name="TitleLabel" type="Label" parent="."]
|
||||
mouse_filter = 2
|
||||
anchor_right = 1.0
|
||||
offset_left = 24
|
||||
offset_top = 70
|
||||
offset_right = -24
|
||||
offset_bottom = 220
|
||||
theme_override_font_sizes/font_size = 44
|
||||
autowrap_mode = 2
|
||||
text = "Fleet formation - drag to arrange"
|
||||
horizontal_alignment = 1
|
||||
|
||||
[node name="Editor" type="Control" parent="."]
|
||||
mouse_filter = 2
|
||||
anchor_left = 0.5
|
||||
anchor_right = 0.5
|
||||
anchor_top = 0.5
|
||||
anchor_bottom = 0.5
|
||||
offset_left = -300
|
||||
offset_right = 300
|
||||
offset_top = -300
|
||||
offset_bottom = 300
|
||||
script = ExtResource("17")
|
||||
|
||||
[node name="ResetButton" type="Control" parent="."]
|
||||
anchor_left = 0.5
|
||||
anchor_right = 0.5
|
||||
anchor_top = 1.0
|
||||
anchor_bottom = 1.0
|
||||
offset_left = -74
|
||||
offset_right = 74
|
||||
offset_top = -270
|
||||
offset_bottom = -122
|
||||
script = ExtResource("10")
|
||||
icon = 3
|
||||
|
||||
[node name="ResetLabel" type="Label" parent="."]
|
||||
mouse_filter = 2
|
||||
anchor_left = 0.5
|
||||
anchor_right = 0.5
|
||||
anchor_top = 1.0
|
||||
anchor_bottom = 1.0
|
||||
offset_left = -180
|
||||
offset_right = 180
|
||||
offset_top = -114
|
||||
offset_bottom = -8
|
||||
theme_override_font_sizes/font_size = 60
|
||||
text = "Reset"
|
||||
horizontal_alignment = 1
|
||||
|
||||
[node name="CloseButton" type="Control" parent="."]
|
||||
anchor_left = 1.0
|
||||
anchor_right = 1.0
|
||||
offset_left = -172
|
||||
offset_right = -24
|
||||
offset_top = 24
|
||||
offset_bottom = 172
|
||||
script = ExtResource("10")
|
||||
icon = 1
|
||||
|
||||
[node name="FadeOverlay" type="CanvasLayer" parent="."]
|
||||
layer = 10
|
||||
|
||||
[node name="FadeRect" type="ColorRect" parent="FadeOverlay"]
|
||||
mouse_filter = 2
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
color = Color(0, 0, 0, 0)
|
||||
39
ui/menus/GarrisonMenu.gd
Normal file
39
ui/menus/GarrisonMenu.gd
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
extends "res://ui/menus/ModalMenu.gd"
|
||||
|
||||
@onready var panel: Control = $Panel
|
||||
@onready var status: Label = $StatusLabel
|
||||
|
||||
var building_id: int = 0
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
super._ready()
|
||||
panel.changed.connect(refresh)
|
||||
|
||||
|
||||
func open_for(next_building_id: int) -> void:
|
||||
building_id = next_building_id
|
||||
panel.building_id = building_id
|
||||
open_menu()
|
||||
refresh()
|
||||
|
||||
|
||||
func close_menu() -> void:
|
||||
super.close_menu()
|
||||
building_id = 0
|
||||
panel.building_id = 0
|
||||
|
||||
|
||||
func refresh() -> void:
|
||||
if building_id == 0:
|
||||
return
|
||||
panel.building_id = building_id
|
||||
panel.refresh()
|
||||
var ordered: int = GameState.garrison_desired_total(building_id)
|
||||
var crewed: int = GameState.garrison_crew(building_id).size()
|
||||
if ordered == 0:
|
||||
status.text = "No vessels ordered. Only armed vessels can hold a position."
|
||||
elif crewed >= ordered:
|
||||
status.text = "Garrison at full strength"
|
||||
else:
|
||||
status.text = "%d of %d berths crewed - vessels are sent from the mothership as they become available" % [crewed, ordered]
|
||||
1
ui/menus/GarrisonMenu.gd.uid
Normal file
1
ui/menus/GarrisonMenu.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
|||
uid://cdfkcdqvwdsh3
|
||||
62
ui/menus/GarrisonMenu.tscn
Normal file
62
ui/menus/GarrisonMenu.tscn
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
[gd_scene load_steps=4 format=3]
|
||||
|
||||
[ext_resource type="Script" path="res://ui/IconButton.gd" id="10"]
|
||||
[ext_resource type="Script" path="res://ui/GarrisonPanel.gd" id="33"]
|
||||
[ext_resource type="Script" path="res://ui/menus/GarrisonMenu.gd" id="menu_script"]
|
||||
|
||||
[node name="GarrisonMenu" type="Control" groups=["modal_menus"]]
|
||||
visible = false
|
||||
mouse_filter = 2
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
script = ExtResource("menu_script")
|
||||
|
||||
[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.94)
|
||||
|
||||
[node name="TitleLabel" type="Label" parent="."]
|
||||
mouse_filter = 2
|
||||
anchor_right = 1.0
|
||||
offset_left = 24.0
|
||||
offset_top = 20.0
|
||||
offset_right = -200.0
|
||||
offset_bottom = 82.0
|
||||
text = "Outpost Garrison"
|
||||
horizontal_alignment = 1
|
||||
|
||||
[node name="Panel" type="Control" parent="."]
|
||||
mouse_filter = 2
|
||||
anchor_right = 1.0
|
||||
offset_left = 40.0
|
||||
offset_top = 120.0
|
||||
offset_right = -40.0
|
||||
offset_bottom = 620.0
|
||||
script = ExtResource("33")
|
||||
|
||||
[node name="StatusLabel" type="Label" parent="."]
|
||||
mouse_filter = 2
|
||||
anchor_right = 1.0
|
||||
anchor_top = 1.0
|
||||
anchor_bottom = 1.0
|
||||
offset_left = 32.0
|
||||
offset_top = -160.0
|
||||
offset_right = -32.0
|
||||
offset_bottom = -24.0
|
||||
theme_override_font_sizes/font_size = 30
|
||||
autowrap_mode = 2
|
||||
horizontal_alignment = 1
|
||||
text = ""
|
||||
|
||||
[node name="CloseButton" type="Control" parent="."]
|
||||
anchor_left = 1.0
|
||||
anchor_right = 1.0
|
||||
offset_left = -140.0
|
||||
offset_top = 20.0
|
||||
offset_right = -24.0
|
||||
offset_bottom = 136.0
|
||||
script = ExtResource("10")
|
||||
icon = 1
|
||||
glow_color = Color(0.72, 0.86, 0.45, 1)
|
||||
138
ui/menus/HangarMenu.gd
Normal file
138
ui/menus/HangarMenu.gd
Normal file
|
|
@ -0,0 +1,138 @@
|
|||
extends "res://ui/menus/ModalMenu.gd"
|
||||
|
||||
signal crew_requested(vessel_type: String)
|
||||
signal store_requested(vessel_type: String)
|
||||
|
||||
const VESSEL_DEFINITIONS = preload("res://vessels/VesselDefinitions.gd")
|
||||
const RULE_COLOR := Color(0.45, 0.9, 0.55)
|
||||
const COLUMNS := 3
|
||||
const LABEL_GAP := 2.0
|
||||
const DIVIDER_GAP := 10.0
|
||||
const CAPTION_LINES := 3.0
|
||||
const CAPTION_MIN := 13
|
||||
const CAPTION_MAX := 22
|
||||
const LINE_RATIO := 1.25
|
||||
|
||||
@onready var status: Label = $StatusLabel
|
||||
@onready var available_title: Label = $AvailableTitle
|
||||
@onready var fleet_title: Label = $FleetTitle
|
||||
@onready var available_slots: Array = [$AvailableInterceptor, $AvailableShield,
|
||||
$AvailableGasBomber, $AvailableCarrier, $AvailableLaser, $AvailableDistorder]
|
||||
@onready var available_labels: Array = [$AvailableInterceptorLabel, $AvailableShieldLabel,
|
||||
$AvailableGasBomberLabel, $AvailableCarrierLabel, $AvailableLaserLabel,
|
||||
$AvailableDistorderLabel]
|
||||
@onready var fleet_slots: Array = [$FleetInterceptor, $FleetShield, $FleetGasBomber,
|
||||
$FleetCarrier, $FleetLaser, $FleetDistorder]
|
||||
@onready var fleet_labels: Array = [$FleetInterceptorLabel, $FleetShieldLabel,
|
||||
$FleetGasBomberLabel, $FleetCarrierLabel, $FleetLaserLabel, $FleetDistorderLabel]
|
||||
|
||||
var divider_y: float = 0.0
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
super._ready()
|
||||
for i in range(available_slots.size()):
|
||||
available_slots[i].pressed.connect(
|
||||
func(): crew_requested.emit(_vessel_types()[i]))
|
||||
fleet_slots[i].pressed.connect(
|
||||
func(): store_requested.emit(_vessel_types()[i]))
|
||||
_layout_sections()
|
||||
|
||||
|
||||
func open_for(fleet: Node) -> void:
|
||||
status.text = ""
|
||||
open_menu()
|
||||
refresh(fleet)
|
||||
|
||||
|
||||
func set_status(message: String) -> void:
|
||||
status.text = message
|
||||
|
||||
|
||||
func refresh(fleet: Node) -> void:
|
||||
var types: Array = _vessel_types()
|
||||
for i in range(mini(types.size(), available_slots.size())):
|
||||
var vessel_type: String = types[i]
|
||||
var definition: Resource = VESSEL_DEFINITIONS.get_definition(vessel_type)
|
||||
var available: int = GameState.stored_vessels.count(vessel_type)
|
||||
var deployed: int = 0
|
||||
for ship in fleet.ships:
|
||||
if is_instance_valid(ship) and String(ship.vessel_type) == vessel_type:
|
||||
deployed += 1
|
||||
available_labels[i].text = "%s\n%d available" % [definition.display_name, available]
|
||||
fleet_labels[i].text = "%s\n%d in fleet" % [definition.display_name, deployed]
|
||||
for slot in [available_slots[i], fleet_slots[i]]:
|
||||
slot.icon = definition.icon
|
||||
slot.glow_color = definition.glow_color
|
||||
available_slots[i].enabled = available > 0 \
|
||||
and fleet.ships.size() < GameState.max_fleet_size()
|
||||
fleet_slots[i].enabled = deployed > 0 and fleet.ships.size() > 1
|
||||
available_slots[i].queue_redraw()
|
||||
fleet_slots[i].queue_redraw()
|
||||
|
||||
|
||||
func _vessel_types() -> Array:
|
||||
var types: Array = []
|
||||
for definition in VESSEL_DEFINITIONS.fleet():
|
||||
types.append(String(definition.definition_id))
|
||||
return types
|
||||
|
||||
|
||||
func _layout_sections() -> void:
|
||||
var count: int = available_slots.size()
|
||||
if count == 0:
|
||||
return
|
||||
var columns: int = mini(COLUMNS, count)
|
||||
var rows: int = int(ceil(float(count) / float(columns)))
|
||||
var top: float = available_title.position.y + available_title.size.y + 8.0
|
||||
var bottom: float = status.position.y - 12.0
|
||||
var title_height: float = fleet_title.size.y
|
||||
var section_height: float = (bottom - top - title_height - 16.0) * 0.5
|
||||
if section_height <= 0.0:
|
||||
return
|
||||
var cell_width: float = size.x / float(columns)
|
||||
var cell_height: float = section_height / float(rows)
|
||||
var slot_size: float = minf(cell_height * 0.46, cell_width * 0.40)
|
||||
var label_height: float = maxf(cell_height - slot_size - LABEL_GAP * 2.0, 1.0)
|
||||
_layout_section(available_slots, available_labels, top, columns, cell_width,
|
||||
cell_height, slot_size, label_height)
|
||||
var available_bottom: float = top + section_height
|
||||
divider_y = available_bottom + DIVIDER_GAP
|
||||
fleet_title.position.y = divider_y + DIVIDER_GAP
|
||||
var fleet_top: float = fleet_title.position.y + title_height + 8.0
|
||||
_layout_section(fleet_slots, fleet_labels, fleet_top, columns, cell_width,
|
||||
cell_height, slot_size, label_height)
|
||||
queue_redraw()
|
||||
|
||||
|
||||
func _layout_section(slots: Array, labels: Array, top: float, columns: int,
|
||||
cell_width: float, cell_height: float, slot_size: float,
|
||||
label_height: float) -> void:
|
||||
if columns <= 0:
|
||||
return
|
||||
for i in range(slots.size()):
|
||||
var column: int = i % columns
|
||||
var row: int = i / columns
|
||||
var cell_x: float = float(column) * cell_width
|
||||
var cell_y: float = top + float(row) * cell_height
|
||||
slots[i].position = Vector2(cell_x + (cell_width - slot_size) * 0.5, cell_y)
|
||||
slots[i].size = Vector2(slot_size, slot_size)
|
||||
labels[i].position = Vector2(cell_x, cell_y + slot_size + LABEL_GAP)
|
||||
labels[i].size = Vector2(cell_width, label_height)
|
||||
labels[i].horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
|
||||
labels[i].vertical_alignment = VERTICAL_ALIGNMENT_TOP
|
||||
labels[i].autowrap_mode = TextServer.AUTOWRAP_WORD_SMART
|
||||
labels[i].add_theme_font_size_override("font_size", caption_size(label_height))
|
||||
labels[i].clip_text = true
|
||||
|
||||
|
||||
func caption_size(label_height: float) -> int:
|
||||
return clampi(int(label_height / (CAPTION_LINES * LINE_RATIO)),
|
||||
CAPTION_MIN, CAPTION_MAX)
|
||||
|
||||
|
||||
func _draw() -> void:
|
||||
if divider_y <= 0.0:
|
||||
return
|
||||
NeonDraw.draw_glowing_line(self, Vector2(24.0, divider_y),
|
||||
Vector2(size.x - 24.0, divider_y), RULE_COLOR, 0.5, 0.4)
|
||||
1
ui/menus/HangarMenu.gd.uid
Normal file
1
ui/menus/HangarMenu.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
|||
uid://c386w72vtqmdw
|
||||
388
ui/menus/HangarMenu.tscn
Normal file
388
ui/menus/HangarMenu.tscn
Normal file
|
|
@ -0,0 +1,388 @@
|
|||
[gd_scene load_steps=3 format=3]
|
||||
|
||||
[ext_resource type="Script" path="res://ui/IconButton.gd" id="10"]
|
||||
[ext_resource type="Script" path="res://ui/menus/HangarMenu.gd" id="39"]
|
||||
|
||||
[node name="HangarMenu" type="Control" groups=["modal_menus"]]
|
||||
visible = false
|
||||
mouse_filter = 2
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
script = ExtResource("39")
|
||||
|
||||
[node name="Backdrop" type="ColorRect" parent="."]
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
color = Color(0.03, 0.03, 0.08, 0.94)
|
||||
|
||||
[node name="TitleLabel" type="Label" parent="."]
|
||||
mouse_filter = 2
|
||||
anchor_right = 1.0
|
||||
offset_left = 24
|
||||
offset_top = 60
|
||||
offset_right = -210
|
||||
offset_bottom = 170
|
||||
text = "Hangar"
|
||||
horizontal_alignment = 1
|
||||
|
||||
[node name="ListLabel" type="Label" parent="."]
|
||||
visible = false
|
||||
mouse_filter = 2
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
offset_left = 32
|
||||
offset_top = 200
|
||||
offset_right = -32
|
||||
offset_bottom = -420
|
||||
theme_override_font_sizes/font_size = 30
|
||||
autowrap_mode = 2
|
||||
horizontal_alignment = 1
|
||||
text = ""
|
||||
|
||||
[node name="StatusLabel" type="Label" parent="."]
|
||||
mouse_filter = 2
|
||||
anchor_right = 1.0
|
||||
anchor_top = 1.0
|
||||
anchor_bottom = 1.0
|
||||
offset_left = 32
|
||||
offset_top = -410
|
||||
offset_right = -32
|
||||
offset_bottom = -300
|
||||
theme_override_font_sizes/font_size = 30
|
||||
autowrap_mode = 2
|
||||
horizontal_alignment = 1
|
||||
text = ""
|
||||
|
||||
[node name="NextButton" type="Control" parent="."]
|
||||
visible = false
|
||||
anchor_left = 0.5
|
||||
anchor_top = 1.0
|
||||
anchor_right = 0.5
|
||||
anchor_bottom = 1.0
|
||||
offset_left = -230
|
||||
offset_right = -110
|
||||
offset_top = -280
|
||||
offset_bottom = -160
|
||||
script = ExtResource("10")
|
||||
icon = 6
|
||||
glow_color = Color(0.55, 0.95, 0.9, 1)
|
||||
|
||||
[node name="CrewButton" type="Control" parent="."]
|
||||
visible = false
|
||||
anchor_left = 0.5
|
||||
anchor_top = 1.0
|
||||
anchor_right = 0.5
|
||||
anchor_bottom = 1.0
|
||||
offset_left = 110
|
||||
offset_right = 230
|
||||
offset_top = -280
|
||||
offset_bottom = -160
|
||||
script = ExtResource("10")
|
||||
icon = 2
|
||||
glow_color = Color(0.45, 0.9, 0.55, 1)
|
||||
|
||||
[node name="HintLabel" type="Label" parent="."]
|
||||
visible = false
|
||||
mouse_filter = 2
|
||||
anchor_right = 1.0
|
||||
anchor_top = 1.0
|
||||
anchor_bottom = 1.0
|
||||
offset_left = 24
|
||||
offset_top = -150
|
||||
offset_right = -24
|
||||
offset_bottom = -60
|
||||
theme_override_font_sizes/font_size = 28
|
||||
autowrap_mode = 2
|
||||
horizontal_alignment = 1
|
||||
text = "Next Crew"
|
||||
|
||||
[node name="AvailableTitle" type="Label" parent="."]
|
||||
mouse_filter = 2
|
||||
anchor_right = 1.0
|
||||
offset_top = 190
|
||||
offset_bottom = 240
|
||||
theme_override_font_sizes/font_size = 28
|
||||
text = "AVAILABLE — TAP TO CREW"
|
||||
horizontal_alignment = 1
|
||||
|
||||
[node name="AvailableInterceptor" type="Control" parent="."]
|
||||
anchor_left = 0.5
|
||||
anchor_right = 0.5
|
||||
offset_left = -290
|
||||
offset_right = -215
|
||||
offset_top = 255
|
||||
offset_bottom = 375
|
||||
script = ExtResource("10")
|
||||
icon = 2
|
||||
|
||||
[node name="AvailableInterceptorLabel" type="Label" parent="."]
|
||||
mouse_filter = 2
|
||||
anchor_left = 0.5
|
||||
anchor_right = 0.5
|
||||
offset_left = -330
|
||||
offset_right = -175
|
||||
offset_top = 380
|
||||
offset_bottom = 460
|
||||
theme_override_font_sizes/font_size = 22
|
||||
horizontal_alignment = 1
|
||||
|
||||
[node name="AvailableShield" type="Control" parent="."]
|
||||
anchor_left = 0.5
|
||||
anchor_right = 0.5
|
||||
offset_left = -189
|
||||
offset_right = -114
|
||||
offset_top = 255
|
||||
offset_bottom = 375
|
||||
script = ExtResource("10")
|
||||
icon = 2
|
||||
glow_color = Color(0.45, 0.8, 1, 1)
|
||||
|
||||
[node name="AvailableShieldLabel" type="Label" parent="."]
|
||||
mouse_filter = 2
|
||||
anchor_left = 0.5
|
||||
anchor_right = 0.5
|
||||
offset_left = -229
|
||||
offset_right = -74
|
||||
offset_top = 380
|
||||
offset_bottom = 460
|
||||
theme_override_font_sizes/font_size = 22
|
||||
horizontal_alignment = 1
|
||||
|
||||
[node name="AvailableGasBomber" type="Control" parent="."]
|
||||
anchor_left = 0.5
|
||||
anchor_right = 0.5
|
||||
offset_left = -88
|
||||
offset_right = -13
|
||||
offset_top = 255
|
||||
offset_bottom = 375
|
||||
script = ExtResource("10")
|
||||
icon = 31
|
||||
glow_color = Color(0.96, 0.32, 0.78, 1)
|
||||
|
||||
[node name="AvailableGasBomberLabel" type="Label" parent="."]
|
||||
mouse_filter = 2
|
||||
anchor_left = 0.5
|
||||
anchor_right = 0.5
|
||||
offset_left = -128
|
||||
offset_right = 27
|
||||
offset_top = 380
|
||||
offset_bottom = 460
|
||||
theme_override_font_sizes/font_size = 22
|
||||
horizontal_alignment = 1
|
||||
|
||||
[node name="AvailableCarrier" type="Control" parent="."]
|
||||
anchor_left = 0.5
|
||||
anchor_right = 0.5
|
||||
offset_left = 13
|
||||
offset_right = 88
|
||||
offset_top = 255
|
||||
offset_bottom = 375
|
||||
script = ExtResource("10")
|
||||
icon = 34
|
||||
glow_color = Color(1, 0.78, 0.3, 1)
|
||||
|
||||
[node name="AvailableCarrierLabel" type="Label" parent="."]
|
||||
mouse_filter = 2
|
||||
anchor_left = 0.5
|
||||
anchor_right = 0.5
|
||||
offset_left = -27
|
||||
offset_right = 128
|
||||
offset_top = 380
|
||||
offset_bottom = 460
|
||||
theme_override_font_sizes/font_size = 22
|
||||
horizontal_alignment = 1
|
||||
|
||||
[node name="AvailableLaser" type="Control" parent="."]
|
||||
anchor_left = 0.5
|
||||
anchor_right = 0.5
|
||||
offset_left = 114
|
||||
offset_right = 189
|
||||
offset_top = 255
|
||||
offset_bottom = 375
|
||||
script = ExtResource("10")
|
||||
icon = 35
|
||||
glow_color = Color(0.3, 0.9, 1, 1)
|
||||
|
||||
[node name="AvailableLaserLabel" type="Label" parent="."]
|
||||
mouse_filter = 2
|
||||
anchor_left = 0.5
|
||||
anchor_right = 0.5
|
||||
offset_left = 74
|
||||
offset_right = 229
|
||||
offset_top = 380
|
||||
offset_bottom = 460
|
||||
theme_override_font_sizes/font_size = 22
|
||||
horizontal_alignment = 1
|
||||
|
||||
[node name="AvailableDistorder" type="Control" parent="."]
|
||||
anchor_left = 0.5
|
||||
anchor_right = 0.5
|
||||
offset_left = 215
|
||||
offset_right = 290
|
||||
offset_top = 255
|
||||
offset_bottom = 375
|
||||
script = ExtResource("10")
|
||||
icon = 37
|
||||
glow_color = Color(0.7, 0.3, 1, 1)
|
||||
|
||||
[node name="AvailableDistorderLabel" type="Label" parent="."]
|
||||
mouse_filter = 2
|
||||
anchor_left = 0.5
|
||||
anchor_right = 0.5
|
||||
offset_left = 175
|
||||
offset_right = 330
|
||||
offset_top = 380
|
||||
offset_bottom = 460
|
||||
theme_override_font_sizes/font_size = 22
|
||||
horizontal_alignment = 1
|
||||
|
||||
[node name="FleetTitle" type="Label" parent="."]
|
||||
mouse_filter = 2
|
||||
anchor_right = 1.0
|
||||
offset_top = 500
|
||||
offset_bottom = 550
|
||||
theme_override_font_sizes/font_size = 28
|
||||
text = "FLEET — TAP TO STORE"
|
||||
horizontal_alignment = 1
|
||||
|
||||
[node name="FleetInterceptor" type="Control" parent="."]
|
||||
anchor_left = 0.5
|
||||
anchor_right = 0.5
|
||||
offset_left = -290
|
||||
offset_right = -215
|
||||
offset_top = 565
|
||||
offset_bottom = 685
|
||||
script = ExtResource("10")
|
||||
icon = 2
|
||||
|
||||
[node name="FleetInterceptorLabel" type="Label" parent="."]
|
||||
mouse_filter = 2
|
||||
anchor_left = 0.5
|
||||
anchor_right = 0.5
|
||||
offset_left = -330
|
||||
offset_right = -175
|
||||
offset_top = 690
|
||||
offset_bottom = 770
|
||||
theme_override_font_sizes/font_size = 22
|
||||
horizontal_alignment = 1
|
||||
|
||||
[node name="FleetShield" type="Control" parent="."]
|
||||
anchor_left = 0.5
|
||||
anchor_right = 0.5
|
||||
offset_left = -189
|
||||
offset_right = -114
|
||||
offset_top = 565
|
||||
offset_bottom = 685
|
||||
script = ExtResource("10")
|
||||
icon = 2
|
||||
glow_color = Color(0.45, 0.8, 1, 1)
|
||||
|
||||
[node name="FleetShieldLabel" type="Label" parent="."]
|
||||
mouse_filter = 2
|
||||
anchor_left = 0.5
|
||||
anchor_right = 0.5
|
||||
offset_left = -229
|
||||
offset_right = -74
|
||||
offset_top = 690
|
||||
offset_bottom = 770
|
||||
theme_override_font_sizes/font_size = 22
|
||||
horizontal_alignment = 1
|
||||
|
||||
[node name="FleetGasBomber" type="Control" parent="."]
|
||||
anchor_left = 0.5
|
||||
anchor_right = 0.5
|
||||
offset_left = -88
|
||||
offset_right = -13
|
||||
offset_top = 565
|
||||
offset_bottom = 685
|
||||
script = ExtResource("10")
|
||||
icon = 31
|
||||
glow_color = Color(0.96, 0.32, 0.78, 1)
|
||||
|
||||
[node name="FleetGasBomberLabel" type="Label" parent="."]
|
||||
mouse_filter = 2
|
||||
anchor_left = 0.5
|
||||
anchor_right = 0.5
|
||||
offset_left = -128
|
||||
offset_right = 27
|
||||
offset_top = 690
|
||||
offset_bottom = 770
|
||||
theme_override_font_sizes/font_size = 22
|
||||
horizontal_alignment = 1
|
||||
|
||||
[node name="FleetCarrier" type="Control" parent="."]
|
||||
anchor_left = 0.5
|
||||
anchor_right = 0.5
|
||||
offset_left = 13
|
||||
offset_right = 88
|
||||
offset_top = 565
|
||||
offset_bottom = 685
|
||||
script = ExtResource("10")
|
||||
icon = 34
|
||||
glow_color = Color(1, 0.78, 0.3, 1)
|
||||
|
||||
[node name="FleetCarrierLabel" type="Label" parent="."]
|
||||
mouse_filter = 2
|
||||
anchor_left = 0.5
|
||||
anchor_right = 0.5
|
||||
offset_left = -27
|
||||
offset_right = 128
|
||||
offset_top = 690
|
||||
offset_bottom = 770
|
||||
theme_override_font_sizes/font_size = 22
|
||||
horizontal_alignment = 1
|
||||
|
||||
[node name="FleetLaser" type="Control" parent="."]
|
||||
anchor_left = 0.5
|
||||
anchor_right = 0.5
|
||||
offset_left = 114
|
||||
offset_right = 189
|
||||
offset_top = 565
|
||||
offset_bottom = 685
|
||||
script = ExtResource("10")
|
||||
icon = 35
|
||||
glow_color = Color(0.3, 0.9, 1, 1)
|
||||
|
||||
[node name="FleetLaserLabel" type="Label" parent="."]
|
||||
mouse_filter = 2
|
||||
anchor_left = 0.5
|
||||
anchor_right = 0.5
|
||||
offset_left = 74
|
||||
offset_right = 229
|
||||
offset_top = 690
|
||||
offset_bottom = 770
|
||||
theme_override_font_sizes/font_size = 22
|
||||
horizontal_alignment = 1
|
||||
|
||||
[node name="FleetDistorder" type="Control" parent="."]
|
||||
anchor_left = 0.5
|
||||
anchor_right = 0.5
|
||||
offset_left = 215
|
||||
offset_right = 290
|
||||
offset_top = 565
|
||||
offset_bottom = 685
|
||||
script = ExtResource("10")
|
||||
icon = 37
|
||||
glow_color = Color(0.7, 0.3, 1, 1)
|
||||
|
||||
[node name="FleetDistorderLabel" type="Label" parent="."]
|
||||
mouse_filter = 2
|
||||
anchor_left = 0.5
|
||||
anchor_right = 0.5
|
||||
offset_left = 175
|
||||
offset_right = 330
|
||||
offset_top = 690
|
||||
offset_bottom = 770
|
||||
theme_override_font_sizes/font_size = 22
|
||||
horizontal_alignment = 1
|
||||
|
||||
[node name="CloseButton" type="Control" parent="."]
|
||||
anchor_left = 1.0
|
||||
anchor_right = 1.0
|
||||
offset_left = -172
|
||||
offset_top = 24
|
||||
offset_right = -24
|
||||
offset_bottom = 172
|
||||
script = ExtResource("10")
|
||||
icon = 1
|
||||
glow_color = Color(0.45, 0.9, 0.55, 1)
|
||||
157
ui/menus/LabMenu.gd
Normal file
157
ui/menus/LabMenu.gd
Normal file
|
|
@ -0,0 +1,157 @@
|
|||
extends "res://ui/menus/ModalMenu.gd"
|
||||
|
||||
signal vessel_selected(index: int)
|
||||
signal upgrade_selected(index: int)
|
||||
|
||||
const PRICE_TAG = preload("res://ui/PriceTag.gd")
|
||||
const TAG_HEIGHT := 38.0
|
||||
const LABEL_HEIGHT := 40.0
|
||||
const TAG_PADDING := 8.0
|
||||
const ROW_GAP := 18.0
|
||||
const VESSEL_HALF := 30.0
|
||||
const VESSEL_SPACING := 90.0
|
||||
const VESSEL_MARGIN := 24.0
|
||||
|
||||
@onready var vessel_buttons: Array = [$VesselA, $VesselB, $VesselC, $VesselD,
|
||||
$VesselE, $VesselF, $VesselG, $VesselH]
|
||||
@onready var vessel_labels: Array = [$VesselALabel, $VesselBLabel, $VesselCLabel,
|
||||
$VesselDLabel, $VesselELabel, $VesselFLabel, $VesselGLabel, $VesselHLabel]
|
||||
@onready var upgrade_buttons: Array = [$Upgrade0, $Upgrade1, $Upgrade2, $Upgrade3]
|
||||
@onready var upgrade_labels: Array = [$Upgrade0Label, $Upgrade1Label,
|
||||
$Upgrade2Label, $Upgrade3Label]
|
||||
@onready var vessel_heading: Label = $VesselLabel
|
||||
@onready var detail: Label = $DetailLabel
|
||||
@onready var status: Label = $StatusLabel
|
||||
@onready var resource_bar: Control = $Bar
|
||||
|
||||
var building_id: int = 0
|
||||
var price_tags: Array = []
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
super._ready()
|
||||
_build_price_tags()
|
||||
for i in range(vessel_buttons.size()):
|
||||
vessel_buttons[i].pressed.connect(func(): vessel_selected.emit(i))
|
||||
for i in range(upgrade_buttons.size()):
|
||||
upgrade_buttons[i].pressed.connect(func(): upgrade_selected.emit(i))
|
||||
|
||||
|
||||
func open_for(next_building_id: int) -> void:
|
||||
building_id = next_building_id
|
||||
resource_bar.building_id = building_id
|
||||
open_menu()
|
||||
|
||||
|
||||
func close_menu() -> void:
|
||||
super.close_menu()
|
||||
building_id = 0
|
||||
|
||||
|
||||
func render_vessels(definitions: Array, selected_type: String) -> void:
|
||||
for i in range(mini(vessel_buttons.size(), definitions.size())):
|
||||
var definition: Resource = definitions[i]
|
||||
vessel_buttons[i].enabled = true
|
||||
vessel_buttons[i].icon = definition.icon
|
||||
vessel_buttons[i].glow_color = definition.glow_color
|
||||
vessel_buttons[i].highlighted = String(definition.definition_id) == selected_type
|
||||
vessel_labels[i].text = definition.display_name
|
||||
vessel_buttons[i].queue_redraw()
|
||||
_layout_vessels()
|
||||
|
||||
|
||||
func render_options(options: Array, selected: int, vessel_colour: Color) -> void:
|
||||
for i in range(upgrade_buttons.size()):
|
||||
var shown: bool = i < options.size()
|
||||
upgrade_buttons[i].visible = shown
|
||||
upgrade_labels[i].visible = shown
|
||||
price_tags[i].visible = shown
|
||||
if not shown:
|
||||
continue
|
||||
var option: Dictionary = options[i]
|
||||
var maxed: bool = bool(option.get("maxed", false))
|
||||
upgrade_labels[i].text = String(option.label)
|
||||
price_tags[i].visible = not maxed
|
||||
price_tags[i].show_price({} if maxed else option.costs,
|
||||
0 if maxed else int(option.points))
|
||||
upgrade_buttons[i].icon = int(option.icon)
|
||||
upgrade_buttons[i].glow_color = vessel_colour
|
||||
upgrade_buttons[i].highlighted = i == selected
|
||||
upgrade_buttons[i].enabled = true
|
||||
upgrade_buttons[i].queue_redraw()
|
||||
_resize_price_tags()
|
||||
|
||||
|
||||
func show_detail(heading: String, description: String, points: int) -> void:
|
||||
detail.text = "%s\n%s" % [heading, description]
|
||||
if points > 0:
|
||||
detail.text += "\nResearch points: %d/%d" % [GameState.research_points, points]
|
||||
|
||||
|
||||
func clear_detail() -> void:
|
||||
detail.text = ""
|
||||
|
||||
|
||||
func set_status(message: String) -> void:
|
||||
status.text = message
|
||||
|
||||
|
||||
func _build_price_tags() -> void:
|
||||
for i in range(upgrade_labels.size()):
|
||||
var label: Control = upgrade_labels[i]
|
||||
var tag: Control = PRICE_TAG.new()
|
||||
tag.name = "LabPrice%d" % i
|
||||
tag.anchor_left = label.anchor_left
|
||||
tag.anchor_right = label.anchor_right
|
||||
tag.anchor_top = label.anchor_top
|
||||
tag.anchor_bottom = label.anchor_bottom
|
||||
tag.offset_left = label.offset_left
|
||||
tag.offset_right = label.offset_right
|
||||
label.offset_bottom = label.offset_top + LABEL_HEIGHT
|
||||
tag.offset_top = label.offset_bottom + 2.0
|
||||
tag.offset_bottom = tag.offset_top + tag_height()
|
||||
add_child(tag)
|
||||
price_tags.append(tag)
|
||||
|
||||
|
||||
func tag_height() -> float:
|
||||
var tallest: float = TAG_HEIGHT
|
||||
for tag in price_tags:
|
||||
if tag != null and tag.has_method("wanted_height"):
|
||||
tallest = maxf(tallest, float(tag.wanted_height()) + TAG_PADDING)
|
||||
return tallest
|
||||
|
||||
|
||||
func _layout_vessels() -> void:
|
||||
var shown: Array = []
|
||||
for i in range(vessel_buttons.size()):
|
||||
if vessel_buttons[i].visible:
|
||||
shown.append(i)
|
||||
if shown.is_empty():
|
||||
return
|
||||
var room: float = size.x - VESSEL_MARGIN * 2.0
|
||||
if room <= 0.0:
|
||||
room = 672.0
|
||||
var spacing: float = minf(VESSEL_SPACING, room / float(shown.size()))
|
||||
for slot in range(shown.size()):
|
||||
var i: int = shown[slot]
|
||||
var cx: float = (float(slot) - (float(shown.size()) - 1.0) * 0.5) * spacing
|
||||
vessel_buttons[i].offset_left = cx - VESSEL_HALF
|
||||
vessel_buttons[i].offset_right = cx + VESSEL_HALF
|
||||
vessel_labels[i].offset_left = cx - spacing * 0.5
|
||||
vessel_labels[i].offset_right = cx + spacing * 0.5
|
||||
|
||||
|
||||
func _resize_price_tags() -> void:
|
||||
var height: float = tag_height()
|
||||
for tag in price_tags:
|
||||
tag.offset_bottom = tag.offset_top + height
|
||||
if price_tags.size() < 3:
|
||||
return
|
||||
var shift: float = price_tags[0].offset_bottom + ROW_GAP - upgrade_buttons[2].offset_top
|
||||
if absf(shift) < 0.5:
|
||||
return
|
||||
for i in range(2, upgrade_buttons.size()):
|
||||
for node in [upgrade_buttons[i], upgrade_labels[i], price_tags[i]]:
|
||||
node.offset_top += shift
|
||||
node.offset_bottom += shift
|
||||
1
ui/menus/LabMenu.gd.uid
Normal file
1
ui/menus/LabMenu.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
|||
uid://dq44uh8vf0qp0
|
||||
426
ui/menus/LabMenu.tscn
Normal file
426
ui/menus/LabMenu.tscn
Normal file
|
|
@ -0,0 +1,426 @@
|
|||
[gd_scene load_steps=4 format=3]
|
||||
|
||||
[ext_resource type="Script" path="res://ui/IconButton.gd" id="10"]
|
||||
[ext_resource type="Script" path="res://ui/ResourceBar.gd" id="24"]
|
||||
[ext_resource type="Script" path="res://ui/menus/LabMenu.gd" id="menu_script"]
|
||||
|
||||
[node name="LabMenu" type="Control" groups=["modal_menus"]]
|
||||
visible = false
|
||||
mouse_filter = 2
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
script = ExtResource("menu_script")
|
||||
|
||||
[node name="Backdrop" type="ColorRect" parent="."]
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
color = Color(0.03, 0.03, 0.08, 0.94)
|
||||
|
||||
[node name="TitleLabel" type="Label" parent="."]
|
||||
mouse_filter = 2
|
||||
anchor_right = 1.0
|
||||
offset_left = 24
|
||||
offset_top = 20
|
||||
offset_right = -200
|
||||
offset_bottom = 82
|
||||
text = "Ship Lab"
|
||||
horizontal_alignment = 1
|
||||
|
||||
[node name="Bar" type="Control" parent="."]
|
||||
mouse_filter = 2
|
||||
anchor_right = 1.0
|
||||
offset_left = 24
|
||||
offset_top = 148
|
||||
offset_right = -24
|
||||
offset_bottom = 330
|
||||
script = ExtResource("24")
|
||||
|
||||
[node name="VesselA" type="Control" parent="."]
|
||||
anchor_left = 0.5
|
||||
anchor_right = 0.5
|
||||
offset_left = -300
|
||||
offset_right = -240
|
||||
offset_top = 346
|
||||
offset_bottom = 466
|
||||
script = ExtResource("10")
|
||||
icon = 2
|
||||
glow_color = Color(0.25, 0.85, 1, 1)
|
||||
|
||||
[node name="VesselB" type="Control" parent="."]
|
||||
anchor_left = 0.5
|
||||
anchor_right = 0.5
|
||||
offset_left = -210
|
||||
offset_right = -150
|
||||
offset_top = 346
|
||||
offset_bottom = 466
|
||||
script = ExtResource("10")
|
||||
icon = 2
|
||||
glow_color = Color(0.45, 0.8, 1, 1)
|
||||
|
||||
[node name="VesselC" type="Control" parent="."]
|
||||
anchor_left = 0.5
|
||||
anchor_right = 0.5
|
||||
offset_left = -120
|
||||
offset_right = -60
|
||||
offset_top = 346
|
||||
offset_bottom = 466
|
||||
script = ExtResource("10")
|
||||
icon = 31
|
||||
glow_color = Color(0.96, 0.32, 0.78, 1)
|
||||
|
||||
[node name="VesselD" type="Control" parent="."]
|
||||
anchor_left = 0.5
|
||||
anchor_right = 0.5
|
||||
offset_left = -30
|
||||
offset_right = 30
|
||||
offset_top = 346
|
||||
offset_bottom = 466
|
||||
script = ExtResource("10")
|
||||
icon = 12
|
||||
glow_color = Color(0.95, 0.55, 0.85, 1)
|
||||
|
||||
[node name="VesselE" type="Control" parent="."]
|
||||
anchor_left = 0.5
|
||||
anchor_right = 0.5
|
||||
offset_left = 60
|
||||
offset_right = 120
|
||||
offset_top = 346
|
||||
offset_bottom = 466
|
||||
script = ExtResource("10")
|
||||
icon = 34
|
||||
glow_color = Color(1, 0.78, 0.3, 1)
|
||||
|
||||
[node name="VesselF" type="Control" parent="."]
|
||||
anchor_left = 0.5
|
||||
anchor_right = 0.5
|
||||
offset_left = 150
|
||||
offset_right = 210
|
||||
offset_top = 346
|
||||
offset_bottom = 466
|
||||
script = ExtResource("10")
|
||||
icon = 35
|
||||
glow_color = Color(0.3, 0.9, 1, 1)
|
||||
|
||||
[node name="VesselG" type="Control" parent="."]
|
||||
anchor_left = 0.5
|
||||
anchor_right = 0.5
|
||||
offset_left = 240
|
||||
offset_right = 300
|
||||
offset_top = 346
|
||||
offset_bottom = 466
|
||||
script = ExtResource("10")
|
||||
icon = 37
|
||||
glow_color = Color(0.7, 0.3, 1, 1)
|
||||
|
||||
[node name="VesselH" type="Control" parent="."]
|
||||
anchor_left = 0.5
|
||||
anchor_right = 0.5
|
||||
offset_left = 320
|
||||
offset_right = 380
|
||||
offset_top = 346
|
||||
offset_bottom = 466
|
||||
script = ExtResource("10")
|
||||
icon = 43
|
||||
glow_color = Color(0.5, 0.95, 0.8, 1)
|
||||
|
||||
[node name="VesselLabel" type="Label" parent="."]
|
||||
visible = false
|
||||
mouse_filter = 2
|
||||
anchor_right = 1.0
|
||||
offset_left = 24
|
||||
offset_top = 470
|
||||
offset_right = -24
|
||||
offset_bottom = 528
|
||||
theme_override_font_sizes/font_size = 34
|
||||
horizontal_alignment = 1
|
||||
text = ""
|
||||
|
||||
[node name="VesselALabel" type="Label" parent="."]
|
||||
mouse_filter = 2
|
||||
anchor_left = 0.5
|
||||
anchor_right = 0.5
|
||||
offset_left = -310
|
||||
offset_right = -230
|
||||
offset_top = 470
|
||||
offset_bottom = 542
|
||||
theme_override_font_sizes/font_size = 15
|
||||
autowrap_mode = 2
|
||||
horizontal_alignment = 1
|
||||
text = "Interceptor"
|
||||
|
||||
[node name="VesselBLabel" type="Label" parent="."]
|
||||
mouse_filter = 2
|
||||
anchor_left = 0.5
|
||||
anchor_right = 0.5
|
||||
offset_left = -220
|
||||
offset_right = -140
|
||||
offset_top = 470
|
||||
offset_bottom = 542
|
||||
theme_override_font_sizes/font_size = 15
|
||||
autowrap_mode = 2
|
||||
horizontal_alignment = 1
|
||||
text = "Shield"
|
||||
|
||||
[node name="VesselCLabel" type="Label" parent="."]
|
||||
mouse_filter = 2
|
||||
anchor_left = 0.5
|
||||
anchor_right = 0.5
|
||||
offset_left = -130
|
||||
offset_right = -50
|
||||
offset_top = 470
|
||||
offset_bottom = 542
|
||||
theme_override_font_sizes/font_size = 15
|
||||
autowrap_mode = 2
|
||||
horizontal_alignment = 1
|
||||
text = "Gas Bomber"
|
||||
|
||||
[node name="VesselDLabel" type="Label" parent="."]
|
||||
mouse_filter = 2
|
||||
anchor_left = 0.5
|
||||
anchor_right = 0.5
|
||||
offset_left = -40
|
||||
offset_right = 40
|
||||
offset_top = 470
|
||||
offset_bottom = 542
|
||||
theme_override_font_sizes/font_size = 15
|
||||
autowrap_mode = 2
|
||||
horizontal_alignment = 1
|
||||
text = "Transporter"
|
||||
|
||||
[node name="VesselELabel" type="Label" parent="."]
|
||||
mouse_filter = 2
|
||||
anchor_left = 0.5
|
||||
anchor_right = 0.5
|
||||
offset_left = 50
|
||||
offset_right = 130
|
||||
offset_top = 470
|
||||
offset_bottom = 542
|
||||
theme_override_font_sizes/font_size = 15
|
||||
autowrap_mode = 2
|
||||
horizontal_alignment = 1
|
||||
text = "Carrier"
|
||||
|
||||
[node name="VesselFLabel" type="Label" parent="."]
|
||||
mouse_filter = 2
|
||||
anchor_left = 0.5
|
||||
anchor_right = 0.5
|
||||
offset_left = 140
|
||||
offset_right = 220
|
||||
offset_top = 470
|
||||
offset_bottom = 542
|
||||
theme_override_font_sizes/font_size = 15
|
||||
autowrap_mode = 2
|
||||
horizontal_alignment = 1
|
||||
text = "Laser Ship"
|
||||
|
||||
[node name="VesselGLabel" type="Label" parent="."]
|
||||
mouse_filter = 2
|
||||
anchor_left = 0.5
|
||||
anchor_right = 0.5
|
||||
offset_left = 230
|
||||
offset_right = 310
|
||||
offset_top = 470
|
||||
offset_bottom = 542
|
||||
theme_override_font_sizes/font_size = 15
|
||||
autowrap_mode = 2
|
||||
horizontal_alignment = 1
|
||||
text = "Distorder"
|
||||
|
||||
[node name="VesselHLabel" type="Label" parent="."]
|
||||
mouse_filter = 2
|
||||
anchor_left = 0.5
|
||||
anchor_right = 0.5
|
||||
offset_left = 310
|
||||
offset_right = 390
|
||||
offset_top = 470
|
||||
offset_bottom = 542
|
||||
theme_override_font_sizes/font_size = 15
|
||||
autowrap_mode = 2
|
||||
horizontal_alignment = 1
|
||||
text = "Repair Drone"
|
||||
|
||||
[node name="VesselUpgradeSeparator" type="ColorRect" parent="."]
|
||||
mouse_filter = 2
|
||||
anchor_right = 1.0
|
||||
offset_left = 48
|
||||
offset_top = 550
|
||||
offset_right = -48
|
||||
offset_bottom = 554
|
||||
color = Color(0.25, 0.85, 1, 0.6)
|
||||
|
||||
[node name="UpgradeList" type="Label" parent="."]
|
||||
visible = false
|
||||
mouse_filter = 2
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
offset_left = 32
|
||||
offset_top = 562
|
||||
offset_right = -32
|
||||
offset_bottom = -390
|
||||
theme_override_font_sizes/font_size = 30
|
||||
autowrap_mode = 2
|
||||
text = ""
|
||||
|
||||
[node name="DetailLabel" type="Label" parent="."]
|
||||
mouse_filter = 2
|
||||
anchor_right = 1.0
|
||||
anchor_top = 1.0
|
||||
anchor_bottom = 1.0
|
||||
offset_left = 32
|
||||
offset_top = -300
|
||||
offset_right = -32
|
||||
offset_bottom = -180
|
||||
theme_override_font_sizes/font_size = 32
|
||||
autowrap_mode = 2
|
||||
horizontal_alignment = 1
|
||||
text = ""
|
||||
|
||||
[node name="StatusLabel" type="Label" parent="."]
|
||||
mouse_filter = 2
|
||||
anchor_right = 1.0
|
||||
anchor_top = 1.0
|
||||
anchor_bottom = 1.0
|
||||
offset_left = 32
|
||||
offset_top = -174
|
||||
offset_right = -32
|
||||
offset_bottom = -120
|
||||
theme_override_font_sizes/font_size = 30
|
||||
autowrap_mode = 2
|
||||
horizontal_alignment = 1
|
||||
text = ""
|
||||
|
||||
[node name="NextButton" type="Control" parent="."]
|
||||
visible = false
|
||||
anchor_left = 0.5
|
||||
anchor_top = 1.0
|
||||
anchor_right = 0.5
|
||||
anchor_bottom = 1.0
|
||||
offset_left = -230
|
||||
offset_right = -110
|
||||
offset_top = -112
|
||||
offset_bottom = -22
|
||||
script = ExtResource("10")
|
||||
icon = 6
|
||||
glow_color = Color(0.55, 0.95, 0.9, 1)
|
||||
|
||||
[node name="HintLabel" type="Label" parent="."]
|
||||
visible = false
|
||||
mouse_filter = 2
|
||||
anchor_right = 1.0
|
||||
anchor_top = 1.0
|
||||
anchor_bottom = 1.0
|
||||
offset_left = 24
|
||||
offset_top = -102
|
||||
offset_right = -24
|
||||
offset_bottom = -22
|
||||
theme_override_font_sizes/font_size = 28
|
||||
autowrap_mode = 2
|
||||
horizontal_alignment = 1
|
||||
text = "Next upgrade Buy"
|
||||
|
||||
[node name="Upgrade0" type="Control" parent="."]
|
||||
anchor_left = 0.5
|
||||
anchor_right = 0.5
|
||||
offset_left = -240
|
||||
offset_right = -120
|
||||
offset_top = 562
|
||||
offset_bottom = 672
|
||||
script = ExtResource("10")
|
||||
icon = 13
|
||||
glow_color = Color(0.25, 0.85, 1, 1)
|
||||
|
||||
[node name="Upgrade0Label" type="Label" parent="."]
|
||||
mouse_filter = 2
|
||||
anchor_left = 0.5
|
||||
anchor_right = 0.5
|
||||
offset_left = -310
|
||||
offset_right = -50
|
||||
offset_top = 676
|
||||
offset_bottom = 746
|
||||
theme_override_font_sizes/font_size = 22
|
||||
autowrap_mode = 2
|
||||
horizontal_alignment = 1
|
||||
text = ""
|
||||
|
||||
[node name="Upgrade1" type="Control" parent="."]
|
||||
anchor_left = 0.5
|
||||
anchor_right = 0.5
|
||||
offset_left = 120
|
||||
offset_right = 240
|
||||
offset_top = 562
|
||||
offset_bottom = 672
|
||||
script = ExtResource("10")
|
||||
icon = 13
|
||||
glow_color = Color(0.25, 0.85, 1, 1)
|
||||
|
||||
[node name="Upgrade1Label" type="Label" parent="."]
|
||||
mouse_filter = 2
|
||||
anchor_left = 0.5
|
||||
anchor_right = 0.5
|
||||
offset_left = 50
|
||||
offset_right = 310
|
||||
offset_top = 676
|
||||
offset_bottom = 746
|
||||
theme_override_font_sizes/font_size = 22
|
||||
autowrap_mode = 2
|
||||
horizontal_alignment = 1
|
||||
text = ""
|
||||
|
||||
[node name="Upgrade2" type="Control" parent="."]
|
||||
anchor_left = 0.5
|
||||
anchor_right = 0.5
|
||||
offset_left = -240
|
||||
offset_right = -120
|
||||
offset_top = 790
|
||||
offset_bottom = 900
|
||||
script = ExtResource("10")
|
||||
icon = 13
|
||||
glow_color = Color(0.25, 0.85, 1, 1)
|
||||
|
||||
[node name="Upgrade2Label" type="Label" parent="."]
|
||||
mouse_filter = 2
|
||||
anchor_left = 0.5
|
||||
anchor_right = 0.5
|
||||
offset_left = -310
|
||||
offset_right = -50
|
||||
offset_top = 904
|
||||
offset_bottom = 974
|
||||
theme_override_font_sizes/font_size = 22
|
||||
autowrap_mode = 2
|
||||
horizontal_alignment = 1
|
||||
text = ""
|
||||
|
||||
[node name="Upgrade3" type="Control" parent="."]
|
||||
anchor_left = 0.5
|
||||
anchor_right = 0.5
|
||||
offset_left = 120
|
||||
offset_right = 240
|
||||
offset_top = 790
|
||||
offset_bottom = 900
|
||||
script = ExtResource("10")
|
||||
icon = 13
|
||||
glow_color = Color(0.25, 0.85, 1, 1)
|
||||
|
||||
[node name="Upgrade3Label" type="Label" parent="."]
|
||||
mouse_filter = 2
|
||||
anchor_left = 0.5
|
||||
anchor_right = 0.5
|
||||
offset_left = 50
|
||||
offset_right = 310
|
||||
offset_top = 904
|
||||
offset_bottom = 974
|
||||
theme_override_font_sizes/font_size = 22
|
||||
autowrap_mode = 2
|
||||
horizontal_alignment = 1
|
||||
text = ""
|
||||
|
||||
[node name="CloseButton" type="Control" parent="."]
|
||||
anchor_left = 1.0
|
||||
anchor_right = 1.0
|
||||
offset_left = -140
|
||||
offset_top = 20
|
||||
offset_right = -24
|
||||
offset_bottom = 136
|
||||
script = ExtResource("10")
|
||||
icon = 1
|
||||
glow_color = Color(0.55, 0.95, 0.9, 1)
|
||||
27
ui/menus/MenuLayout.gd
Normal file
27
ui/menus/MenuLayout.gd
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
extends RefCounted
|
||||
|
||||
const HEADER_GAP: float = 16.0
|
||||
const BOTTOM_MARGIN: float = 28.0
|
||||
|
||||
|
||||
static func grid_band(header_bottom: float, panel_height: float) -> Vector2:
|
||||
var half: float = panel_height * 0.5
|
||||
if half <= 0.0:
|
||||
half = 640.0
|
||||
return Vector2(header_bottom + HEADER_GAP - half, half - BOTTOM_MARGIN)
|
||||
|
||||
|
||||
static func grid_row_top(row: int, rows: int, row_height: float, band: Vector2,
|
||||
natural_pitch: float) -> float:
|
||||
var pitch: float = natural_pitch
|
||||
if rows > 1:
|
||||
pitch = minf(pitch, (band.y - band.x - row_height) / float(rows - 1))
|
||||
return band.x + maxf(pitch, row_height) * float(row)
|
||||
|
||||
|
||||
static func place_entry(node: Control, cx: float, top: float, half: float,
|
||||
height: float) -> void:
|
||||
node.offset_left = cx - half
|
||||
node.offset_right = cx + half
|
||||
node.offset_top = top
|
||||
node.offset_bottom = top + height
|
||||
1
ui/menus/MenuLayout.gd.uid
Normal file
1
ui/menus/MenuLayout.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
|||
uid://mhjg8jhbmy6f
|
||||
24
ui/menus/ModalMenu.gd
Normal file
24
ui/menus/ModalMenu.gd
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
extends Control
|
||||
|
||||
signal closed
|
||||
|
||||
@onready var close_button: Control = get_node_or_null("CloseButton")
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
visible = false
|
||||
if close_button != null and close_button.has_signal("pressed"):
|
||||
close_button.pressed.connect(close_menu)
|
||||
|
||||
|
||||
func open_menu() -> void:
|
||||
visible = true
|
||||
|
||||
|
||||
func close_menu() -> void:
|
||||
visible = false
|
||||
closed.emit()
|
||||
|
||||
|
||||
func handle_unhandled_input(_event: InputEvent) -> bool:
|
||||
return visible
|
||||
1
ui/menus/ModalMenu.gd.uid
Normal file
1
ui/menus/ModalMenu.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
|||
uid://dkpcfwj4unbbf
|
||||
25
ui/menus/PlanningMenu.gd
Normal file
25
ui/menus/PlanningMenu.gd
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
extends "res://ui/menus/ModalMenu.gd"
|
||||
|
||||
@onready var panel: Control = $Panel
|
||||
@onready var status: Label = $StatusLabel
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
super._ready()
|
||||
panel.changed.connect(refresh)
|
||||
|
||||
|
||||
func open_menu() -> void:
|
||||
super.open_menu()
|
||||
refresh()
|
||||
|
||||
|
||||
func refresh() -> void:
|
||||
panel.refresh()
|
||||
var short: PackedStringArray = PackedStringArray()
|
||||
for vessel_type in GameState.planned_vessel_types():
|
||||
var missing: int = GameState.vessel_shortfall(String(vessel_type))
|
||||
if missing > 0:
|
||||
short.append("%d %s" % [missing, GameState.vessel_name(String(vessel_type))])
|
||||
status.text = "Every standing order is met or already being built" if short.is_empty() \
|
||||
else "Short: %s" % ", ".join(short)
|
||||
1
ui/menus/PlanningMenu.gd.uid
Normal file
1
ui/menus/PlanningMenu.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
|||
uid://b80lmxhmmqw8a
|
||||
63
ui/menus/PlanningMenu.tscn
Normal file
63
ui/menus/PlanningMenu.tscn
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
[gd_scene load_steps=4 format=3]
|
||||
|
||||
[ext_resource type="Script" path="res://ui/IconButton.gd" id="10"]
|
||||
[ext_resource type="Script" path="res://ui/PlanningPanel.gd" id="35"]
|
||||
[ext_resource type="Script" path="res://ui/menus/PlanningMenu.gd" id="menu_script"]
|
||||
|
||||
[node name="PlanningMenu" type="Control" groups=["modal_menus"]]
|
||||
visible = false
|
||||
mouse_filter = 2
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
script = ExtResource("menu_script")
|
||||
|
||||
[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.94)
|
||||
|
||||
[node name="TitleLabel" type="Label" parent="."]
|
||||
mouse_filter = 2
|
||||
anchor_right = 1.0
|
||||
offset_left = 24.0
|
||||
offset_top = 20.0
|
||||
offset_right = -200.0
|
||||
offset_bottom = 82.0
|
||||
text = "Planning Center"
|
||||
horizontal_alignment = 1
|
||||
|
||||
[node name="Panel" type="Control" parent="."]
|
||||
mouse_filter = 2
|
||||
anchor_right = 1.0
|
||||
offset_left = 40.0
|
||||
offset_top = 120.0
|
||||
offset_right = -40.0
|
||||
offset_bottom = -180.0
|
||||
anchor_bottom = 1.0
|
||||
script = ExtResource("35")
|
||||
|
||||
[node name="StatusLabel" type="Label" parent="."]
|
||||
mouse_filter = 2
|
||||
anchor_right = 1.0
|
||||
anchor_top = 1.0
|
||||
anchor_bottom = 1.0
|
||||
offset_left = 32.0
|
||||
offset_top = -160.0
|
||||
offset_right = -32.0
|
||||
offset_bottom = -24.0
|
||||
theme_override_font_sizes/font_size = 28
|
||||
autowrap_mode = 2
|
||||
horizontal_alignment = 1
|
||||
text = ""
|
||||
|
||||
[node name="CloseButton" type="Control" parent="."]
|
||||
anchor_left = 1.0
|
||||
anchor_right = 1.0
|
||||
offset_left = -140.0
|
||||
offset_top = 20.0
|
||||
offset_right = -24.0
|
||||
offset_bottom = 136.0
|
||||
script = ExtResource("10")
|
||||
icon = 1
|
||||
glow_color = Color(0.62, 0.74, 0.92, 1)
|
||||
70
ui/menus/SkillMenu.gd
Normal file
70
ui/menus/SkillMenu.gd
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
extends "res://ui/menus/ModalMenu.gd"
|
||||
|
||||
signal research_requested(id: String)
|
||||
|
||||
@onready var tree: Control = $Tree
|
||||
@onready var detail: Label = $DetailLabel
|
||||
@onready var cost: Control = $CostNumber
|
||||
@onready var status: Label = $StatusLabel
|
||||
@onready var resource_bar: Control = $Bar
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
super._ready()
|
||||
tree.node_picked.connect(refresh)
|
||||
tree.node_confirmed.connect(func(id: String): research_requested.emit(id))
|
||||
|
||||
|
||||
func open_for(building_id: int) -> void:
|
||||
resource_bar.building_id = building_id
|
||||
open_menu()
|
||||
tree.reset_scroll()
|
||||
refresh()
|
||||
|
||||
|
||||
func selected_id() -> String:
|
||||
return String(tree.selected_id)
|
||||
|
||||
|
||||
func research_completed(id: String) -> void:
|
||||
tree.queue_redraw()
|
||||
refresh(id)
|
||||
|
||||
|
||||
func refresh(id: String = "") -> void:
|
||||
if id == "":
|
||||
id = String(tree.selected_id)
|
||||
if id == "":
|
||||
detail.text = "Select a node to see what it unlocks."
|
||||
cost.show_price({})
|
||||
status.text = "Fleet capacity %d · Research points %d" \
|
||||
% [GameState.max_fleet_size(), GameState.research_points]
|
||||
return
|
||||
|
||||
var node: Dictionary = GameState.skill_node(id)
|
||||
if node.is_empty():
|
||||
return
|
||||
detail.text = "%s\n%s" % [node.name, node.desc]
|
||||
cost.show_price(GameState.skill_costs(id), GameState.skill_research_point_cost(id))
|
||||
if GameState.is_unlocked(id):
|
||||
status.text = "Researched"
|
||||
elif not GameState.prerequisite_met(id):
|
||||
status.text = "Needs %s first" % GameState.skill_node(node.requires).name
|
||||
elif not cost.is_affordable():
|
||||
status.text = ""
|
||||
else:
|
||||
status.text = "Tap again to research"
|
||||
|
||||
|
||||
func handle_unhandled_input(event: InputEvent) -> bool:
|
||||
if not visible:
|
||||
return false
|
||||
if event is InputEventScreenTouch:
|
||||
tree.handle_touch(event)
|
||||
elif event is InputEventScreenDrag:
|
||||
tree.handle_drag(event)
|
||||
elif event is InputEventMouseButton:
|
||||
tree.handle_mouse_button(event)
|
||||
elif event is InputEventMouseMotion:
|
||||
tree.handle_mouse_motion(event)
|
||||
return true
|
||||
1
ui/menus/SkillMenu.gd.uid
Normal file
1
ui/menus/SkillMenu.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
|||
uid://bhgf1risnbb03
|
||||
92
ui/menus/SkillMenu.tscn
Normal file
92
ui/menus/SkillMenu.tscn
Normal file
|
|
@ -0,0 +1,92 @@
|
|||
[gd_scene load_steps=6 format=3]
|
||||
|
||||
[ext_resource type="Script" path="res://ui/IconButton.gd" id="10"]
|
||||
[ext_resource type="Script" path="res://ui/SkillTreeView.gd" id="21"]
|
||||
[ext_resource type="Script" path="res://ui/ResourceBar.gd" id="24"]
|
||||
[ext_resource type="Script" path="res://ui/PriceTag.gd" id="price_tag"]
|
||||
[ext_resource type="Script" path="res://ui/menus/SkillMenu.gd" id="menu_script"]
|
||||
|
||||
[node name="SkillMenu" type="Control" groups=["modal_menus"]]
|
||||
visible = false
|
||||
mouse_filter = 2
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
script = ExtResource("menu_script")
|
||||
|
||||
[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.94)
|
||||
|
||||
[node name="Bar" type="Control" parent="."]
|
||||
mouse_filter = 2
|
||||
anchor_right = 1.0
|
||||
offset_left = 24.0
|
||||
offset_top = 20
|
||||
offset_right = -160.0
|
||||
offset_bottom = 202
|
||||
script = ExtResource("24")
|
||||
|
||||
[node name="Tree" type="Control" parent="."]
|
||||
mouse_filter = 2
|
||||
clip_contents = true
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
offset_left = 24.0
|
||||
offset_top = 214
|
||||
offset_right = -24.0
|
||||
offset_bottom = -280.0
|
||||
script = ExtResource("21")
|
||||
|
||||
[node name="DetailLabel" type="Label" parent="."]
|
||||
mouse_filter = 2
|
||||
anchor_right = 1.0
|
||||
anchor_top = 1.0
|
||||
anchor_bottom = 1.0
|
||||
offset_left = 32.0
|
||||
offset_top = -272.0
|
||||
offset_right = -300.0
|
||||
offset_bottom = -152.0
|
||||
theme_override_font_sizes/font_size = 34
|
||||
autowrap_mode = 2
|
||||
horizontal_alignment = 0
|
||||
text = ""
|
||||
|
||||
[node name="CostNumber" type="Control" parent="."]
|
||||
alignment = 2
|
||||
mouse_filter = 2
|
||||
anchor_left = 1.0
|
||||
anchor_top = 1.0
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
offset_left = -288.0
|
||||
offset_top = -272.0
|
||||
offset_right = -32.0
|
||||
offset_bottom = -152.0
|
||||
script = ExtResource("price_tag")
|
||||
|
||||
[node name="StatusLabel" type="Label" parent="."]
|
||||
mouse_filter = 2
|
||||
anchor_right = 1.0
|
||||
anchor_top = 1.0
|
||||
anchor_bottom = 1.0
|
||||
offset_left = 32.0
|
||||
offset_top = -76.0
|
||||
offset_right = -32.0
|
||||
offset_bottom = -24.0
|
||||
theme_override_font_sizes/font_size = 32
|
||||
autowrap_mode = 2
|
||||
horizontal_alignment = 1
|
||||
text = ""
|
||||
|
||||
[node name="CloseButton" type="Control" parent="."]
|
||||
anchor_left = 1.0
|
||||
anchor_right = 1.0
|
||||
offset_left = -140.0
|
||||
offset_top = 20.0
|
||||
offset_right = -24.0
|
||||
offset_bottom = 136.0
|
||||
script = ExtResource("10")
|
||||
icon = 1
|
||||
glow_color = Color(0.55, 0.6, 1, 1)
|
||||
56
ui/menus/TransferMenu.gd
Normal file
56
ui/menus/TransferMenu.gd
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
extends "res://ui/menus/ModalMenu.gd"
|
||||
|
||||
signal transfer_requested(resource_type: String, to_building: bool, amount: int)
|
||||
|
||||
@onready var status: Label = $StatusLabel
|
||||
@onready var resource_list: Control = $ResourceList
|
||||
|
||||
var building_id: int = 0
|
||||
var extractor_index: int = -1
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
super._ready()
|
||||
resource_list.transfer_requested.connect(
|
||||
func(resource_type: String, to_building: bool, amount: int):
|
||||
transfer_requested.emit(resource_type, to_building, amount))
|
||||
|
||||
|
||||
func open_destination(next_building_id: int, next_extractor_index: int) -> void:
|
||||
building_id = next_building_id
|
||||
extractor_index = next_extractor_index
|
||||
status.text = ""
|
||||
open_menu()
|
||||
refresh()
|
||||
|
||||
|
||||
func close_menu() -> void:
|
||||
super.close_menu()
|
||||
building_id = 0
|
||||
extractor_index = -1
|
||||
|
||||
|
||||
func refresh() -> void:
|
||||
if extractor_index >= 0:
|
||||
resource_list.set_extractor_destination(extractor_index, "Planet extractor")
|
||||
return
|
||||
var building: Dictionary = GameState.find_building(building_id)
|
||||
var heading: String = "This building"
|
||||
if GameState.building_has_capability(building, "bank"):
|
||||
heading = "Mothership bank"
|
||||
resource_list.set_destination(building_id, heading)
|
||||
|
||||
|
||||
func place_name() -> String:
|
||||
if extractor_index >= 0:
|
||||
return "the extractor"
|
||||
var building: Dictionary = GameState.find_building(building_id)
|
||||
if building.is_empty():
|
||||
return "this building"
|
||||
if GameState.building_has_capability(building, "bank"):
|
||||
return "the bank"
|
||||
return "this building"
|
||||
|
||||
|
||||
func show_status(message: String) -> void:
|
||||
status.text = message
|
||||
1
ui/menus/TransferMenu.gd.uid
Normal file
1
ui/menus/TransferMenu.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
|||
uid://bw1aiy8jt817c
|
||||
73
ui/menus/TransferMenu.tscn
Normal file
73
ui/menus/TransferMenu.tscn
Normal file
|
|
@ -0,0 +1,73 @@
|
|||
[gd_scene load_steps=4 format=3]
|
||||
|
||||
[ext_resource type="Script" path="res://ui/IconButton.gd" id="10"]
|
||||
[ext_resource type="Script" path="res://ui/ResourceTransferList.gd" id="27"]
|
||||
[ext_resource type="Script" path="res://ui/menus/TransferMenu.gd" id="menu_script"]
|
||||
|
||||
[node name="TransferMenu" type="Control" groups=["modal_menus"]]
|
||||
visible = false
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
script = ExtResource("menu_script")
|
||||
|
||||
[node name="Backdrop" type="ColorRect" parent="."]
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
color = Color(0.03, 0.03, 0.08, 0.94)
|
||||
|
||||
[node name="TitleLabel" type="Label" parent="."]
|
||||
mouse_filter = 2
|
||||
anchor_right = 1.0
|
||||
offset_left = 24
|
||||
offset_top = 36
|
||||
offset_right = -200
|
||||
offset_bottom = 166
|
||||
text = "Transfer cargo"
|
||||
horizontal_alignment = 1
|
||||
vertical_alignment = 1
|
||||
autowrap_mode = 2
|
||||
theme_override_font_sizes/font_size = 44
|
||||
|
||||
[node name="StatusLabel" type="Label" parent="."]
|
||||
mouse_filter = 2
|
||||
anchor_right = 1.0
|
||||
offset_left = 24
|
||||
offset_top = 184
|
||||
offset_right = -24
|
||||
offset_bottom = 284
|
||||
theme_override_font_sizes/font_size = 32
|
||||
autowrap_mode = 2
|
||||
text = ""
|
||||
horizontal_alignment = 1
|
||||
|
||||
[node name="ResourceList" type="Control" parent="."]
|
||||
mouse_filter = 2
|
||||
anchor_right = 1.0
|
||||
offset_left = 16
|
||||
offset_top = 294
|
||||
offset_right = -16
|
||||
offset_bottom = 1080
|
||||
script = ExtResource("27")
|
||||
|
||||
[node name="CloseButton" type="Control" parent="."]
|
||||
anchor_left = 1.0
|
||||
anchor_right = 1.0
|
||||
offset_left = -172
|
||||
offset_right = -24
|
||||
offset_top = 24
|
||||
offset_bottom = 172
|
||||
script = ExtResource("10")
|
||||
icon = 1
|
||||
glow_color = Color(1, 0.78, 0.25, 1)
|
||||
|
||||
[node name="HintLabel" type="Label" parent="."]
|
||||
mouse_filter = 2
|
||||
anchor_right = 1.0
|
||||
offset_left = 24
|
||||
offset_top = 1092
|
||||
offset_right = -24
|
||||
offset_bottom = 1150
|
||||
text = "Arrows move the selected amount from that side"
|
||||
horizontal_alignment = 1
|
||||
theme_override_colors/font_color = Color(0.55, 0.7, 0.78, 1)
|
||||
theme_override_font_sizes/font_size = 23
|
||||
2020
world/Main.tscn
2020
world/Main.tscn
File diff suppressed because it is too large
Load diff
Loading…
Reference in a new issue