Randoloot/scripts/game/flight_hud.gd
2026-10-18 18:47:18 +02:00

577 lines
26 KiB
GDScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

extends CanvasLayer
const RENDER_LAYERS := preload("res://scripts/ui/render_layers.gd")
@onready var debug_toggle: Button = $HUDRoot/DebugToggle
@onready var debug_info: Label = $HUDRoot/DebugInfo
@onready var player: CharacterBody2D = get_parent().get_node("PlayerShip")
@onready var inventory_button: Button = $HUDRoot/ShipEquipmentPanel/Contents/InventoryButton
@onready var inventory_panel: Control = $HUDRoot/ShipInventoryPanel
var _window_manager: Node
var _energy_bank_button: Button
var _debug_expanded := false
var _ability_buttons: Dictionary = {}
var _ability_bar: HBoxContainer
var _passive_skills: GridContainer
var _passive_captain_panel: PanelContainer
var _passive_ship_panel: PanelContainer
var _passive_ship_icons: GridContainer
var _passive_ship_buttons: Dictionary = {}
var _ship_passive_reserved_height := 0.0
var _inventory_clip: Control
var _sidebar: PanelContainer
var _sidebar_toggle: Button
var _sidebar_open := false
var _sidebar_tween: Tween
const SIDEBAR_WIDTH := 286.0
const EQUIPMENT_UI_SCALE := 0.8
var _debug_scroll: ScrollContainer
var _debug_actions: VBoxContainer
var _debug_item_button: Button
var _debug_item_status: Label
var _captain_panel: PanelContainer
var _cockpit: Control
var _captain_skills_ui: CanvasLayer
func _create_navigation() -> void:
var navigation := HBoxContainer.new()
navigation.name = "TopNavigation"
$HUDRoot.add_child(navigation)
navigation.set_anchors_and_offsets_preset(Control.PRESET_CENTER_TOP)
navigation.offset_left = -32
navigation.offset_right = 32
navigation.offset_top = 12
navigation.offset_bottom = 92
navigation.add_theme_constant_override("separation", 10)
_captain_skills_ui = CanvasLayer.new()
_captain_skills_ui.set_script(preload("res://scripts/ui/captain_skills_ui.gd"))
_captain_skills_ui.set("player", player)
add_child(_captain_skills_ui)
var button := Button.new()
button.name = "OpenCaptainSkills"
button.tooltip_text = "Umiejętności kapitana"
button.set_script(preload("res://scripts/ui/navigation_button.gd"))
button.configure_navigation(load("res://assets/icons/ui/captain_skills_art.png"),Color("b9a0ef"),"KAPITAN")
navigation.add_child(button)
button.pressed.connect(func(): _captain_skills_ui.open_management())
func _ready() -> void:
layer = RENDER_LAYERS.HUD
var cursor := Node.new()
cursor.name = "FlightCursor"
cursor.set_script(preload("res://scripts/ui/flight_cursor.gd"))
cursor.set("player", player)
add_child(cursor)
_sidebar_open = bool(GameState.hud_panel_state.get("ship_open", false))
_debug_expanded = bool(GameState.hud_panel_state.get("debug_expanded", false))
debug_info.visible = _debug_expanded
var energy_indicator := Node2D.new()
energy_indicator.name = "EnergyIndicator"
energy_indicator.set_script(preload("res://scripts/game/ship_energy_indicator.gd"))
energy_indicator.set("player", player)
player.add_child(energy_indicator)
var feedback := Control.new()
feedback.name = "CombatFeedback"
feedback.set_script(preload("res://scripts/ui/combat_feedback.gd"))
feedback.set("player", player)
$HUDRoot.add_child(feedback)
debug_info.add_theme_font_size_override("font_size", 10)
# The display font has unusually tall vertical metrics; keep debug rows compact.
debug_info.add_theme_constant_override("line_spacing", mini(0, 13 - ceili(debug_info.get_theme_font("font").get_height(10))))
_window_manager = Node.new()
_window_manager.name = "FloatingWindows"
_window_manager.set_script(preload("res://scripts/ui/floating_window_manager.gd"))
$HUDRoot.add_child(_window_manager)
_window_manager.connect("interaction_started", player.get_node("WeaponController").call.bind("block_ui_mouse_input"))
_create_sidebar()
_inventory_clip = Control.new()
_inventory_clip.name = "InventoryDrawer"
_inventory_clip.clip_contents = false
_inventory_clip.mouse_filter = Control.MOUSE_FILTER_IGNORE
$HUDRoot.add_child(_inventory_clip)
inventory_panel.reparent(_inventory_clip, false)
inventory_panel.set("layout_mode", 0)
inventory_panel.set_anchors_and_offsets_preset(Control.PRESET_TOP_LEFT)
inventory_panel.size = Vector2(560, inventory_panel.get_combined_minimum_size().y)
inventory_panel.scale = Vector2.ONE * EQUIPMENT_UI_SCALE
inventory_panel.set("drawer_width", inventory_panel.size.x * EQUIPMENT_UI_SCALE)
_window_manager.call("register_window", _inventory_clip, inventory_panel, inventory_panel.get_node("Contents/Header"))
$HUDRoot.resized.connect(func() -> void: _layout_sidebar.call_deferred())
_create_ability_bar()
var objectives := PanelContainer.new()
objectives.name = "MissionObjectives"
objectives.set_script(preload("res://scripts/ui/mission_objectives.gd"))
objectives.set("game", get_parent())
$HUDRoot.add_child(objectives)
debug_toggle.pressed.connect(_toggle_debug)
inventory_button.pressed.connect(_toggle_inventory)
_update_debug_toggle()
_layout_sidebar.call_deferred()
if _sidebar_open and bool(GameState.hud_panel_state.get("inventory_open", false)):
inventory_panel.call("_set_drawer_open", true)
func _create_sidebar() -> void:
_captain_panel = $HUDRoot/CaptainPanel
_captain_panel.set_anchors_and_offsets_preset(Control.PRESET_TOP_LEFT)
_captain_panel.position = Vector2(12, 12)
_captain_panel.size = Vector2(244, _captain_panel.get_combined_minimum_size().y)
_captain_panel.resized.connect(_layout_debug)
var captain_gear := PanelContainer.new()
captain_gear.name = "CaptainEquipment"
captain_gear.set_script(preload("res://scripts/ui/captain_equipment_panel.gd"))
$HUDRoot.add_child(captain_gear)
_captain_panel.equipment_requested.connect(captain_gear._toggle_wardrobe)
_passive_captain_panel = _create_passive_panel("PassiveCaptainPanel", "KAPITAN · PASYWNE")
_passive_skills = _passive_captain_panel.get_node("Contents/Icons") as GridContainer
_passive_skills.name = "PassiveCaptainSkills"
_passive_ship_panel = _create_passive_panel("PassiveShipPanel", "STATEK · PASYWNE")
_passive_ship_icons = _passive_ship_panel.get_node("Contents/Icons") as GridContainer
_passive_ship_panel.hide()
GameState.captain.changed.connect(_refresh_passive_skills)
_refresh_passive_skills()
_debug_actions = VBoxContainer.new()
_debug_actions.name = "DebugActions"
_debug_actions.add_theme_constant_override("separation", 6)
$HUDRoot.add_child(_debug_actions)
_debug_item_button = Button.new()
_debug_item_button.name = "GenerateItem"
_debug_item_button.custom_minimum_size.y = 36
preload("res://scripts/ui/hud_button_style.gd").apply(_debug_item_button, Color("a9ef83"))
_debug_item_button.pressed.connect(_give_debug_item)
_debug_actions.add_child(_debug_item_button)
var ammunition_button := Button.new()
ammunition_button.name = "AddAmmunition"
ammunition_button.text = "Dodaj amunicję"
ammunition_button.tooltip_text = "+10 zwykłej amunicji, +10 radiacyjnej amunicji i +10 rakiet"
ammunition_button.custom_minimum_size.y = 36
preload("res://scripts/ui/hud_button_style.gd").apply(ammunition_button, Color("efb568"))
ammunition_button.pressed.connect(_give_debug_ammunition)
_debug_actions.add_child(ammunition_button)
_debug_item_status = Label.new()
_debug_item_status.add_theme_font_size_override("font_size", 10)
_debug_item_status.add_theme_color_override("font_color", Color("a9ef83"))
_debug_item_status.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART
_debug_item_status.hide()
_debug_actions.add_child(_debug_item_status)
_debug_actions.minimum_size_changed.connect(func() -> void: _layout_debug.call_deferred())
_debug_scroll = ScrollContainer.new()
_debug_scroll.name = "DebugScroll"
_debug_scroll.horizontal_scroll_mode = ScrollContainer.SCROLL_MODE_DISABLED
$HUDRoot.add_child(_debug_scroll)
debug_info.reparent(_debug_scroll, false)
debug_info.set_anchors_and_offsets_preset(Control.PRESET_TOP_LEFT)
debug_info.size_flags_horizontal = Control.SIZE_EXPAND_FILL
debug_info.mouse_filter = Control.MOUSE_FILTER_IGNORE
_sidebar = PanelContainer.new()
_sidebar.name = "ShipDrawer"
var style := StyleBoxFlat.new()
style.bg_color = Color(0.025, 0.042, 0.064, 1.0)
style.border_color = Color("376779")
style.set_border_width_all(1)
style.set_corner_radius_all(8)
style.set_content_margin_all(8)
_sidebar.add_theme_stylebox_override("panel", style)
$HUDRoot.add_child(_sidebar)
var scroll := ScrollContainer.new()
scroll.name = "Scroll"
scroll.horizontal_scroll_mode = ScrollContainer.SCROLL_MODE_DISABLED
_sidebar.add_child(scroll)
var contents := VBoxContainer.new()
contents.name = "Contents"
contents.size_flags_horizontal = Control.SIZE_EXPAND_FILL
scroll.add_child(contents)
var equipment := $HUDRoot/ShipEquipmentPanel as PanelContainer
equipment.set_anchors_and_offsets_preset(Control.PRESET_TOP_LEFT)
equipment.reparent(contents, false)
equipment.size_flags_horizontal = Control.SIZE_EXPAND_FILL
equipment.add_theme_stylebox_override("panel", StyleBoxEmpty.new())
contents.minimum_size_changed.connect(func() -> void: _layout_sidebar.call_deferred())
_sidebar_toggle = Button.new()
_sidebar_toggle.set_script(preload("res://scripts/ui/ship_profile.gd"))
_sidebar_toggle.set("player", player)
_sidebar_toggle.name = "ShipToggle"
_sidebar_toggle.tooltip_text = "Zamknij okno statku" if _sidebar_open else "Otwórz statek i sloty wyposażenia"
_sidebar_toggle.add_theme_font_size_override("font_size", 12)
preload("res://scripts/ui/hud_button_style.gd").apply(_sidebar_toggle)
preload("res://scripts/ui/hud_button_style.gd").apply(inventory_button, Color("b9a0ef"))
$HUDRoot.add_child(_sidebar_toggle)
_sidebar_toggle.set_anchors_and_offsets_preset(Control.PRESET_TOP_RIGHT)
_sidebar_toggle.offset_left = -352
_sidebar_toggle.offset_right = -12
_sidebar_toggle.offset_top = 12
_sidebar_toggle.offset_bottom = 122
_sidebar_toggle.pressed.connect(_toggle_sidebar)
_cockpit = Control.new()
_cockpit.name = "Cockpit"
_cockpit.set_script(preload("res://scripts/ui/flight_cockpit.gd"))
_cockpit.set("player", player)
_cockpit.set("game", get_parent())
$HUDRoot.add_child(_cockpit)
_window_manager.call("register_window", _sidebar, _sidebar, equipment.get_node("Contents/Title"))
_create_navigation()
_layout_debug()
func _create_passive_panel(node_name: String, caption: String) -> PanelContainer:
var panel := PanelContainer.new()
panel.name = node_name
panel.set_script(preload("res://scripts/ui/passive_status_panel.gd"))
panel.set("caption", caption)
$HUDRoot.add_child(panel)
return panel
func _layout_passive_panels() -> void:
if not is_instance_valid(_cockpit):
return
var width := clampf(_cockpit.position.x - 24.0, 180.0, 260.0)
for panel in [_passive_captain_panel, _passive_ship_panel]:
if not is_instance_valid(panel):
continue
var grid: GridContainer = _passive_skills if panel == _passive_captain_panel else _passive_ship_icons
grid.columns = maxi(1, floori((width - 14.0) / 42.0))
panel.size = Vector2(width, panel.get_combined_minimum_size().y)
var x: float = 12.0 if panel == _passive_captain_panel else $HUDRoot.size.x - width - 12.0
panel.position = Vector2(x, $HUDRoot.size.y - panel.size.y - 12.0)
var reserved := _passive_ship_panel.size.y + 12.0 if _passive_ship_panel.visible else 0.0
if not is_equal_approx(reserved, _ship_passive_reserved_height):
_ship_passive_reserved_height = reserved
_layout_sidebar.call_deferred()
func _layout_debug() -> void:
if not is_instance_valid(_debug_scroll) or not is_instance_valid(_captain_panel):
return
var top := _captain_panel.position.y + _captain_panel.size.y + 6.0
var objectives := $HUDRoot.get_node_or_null("MissionObjectives") as Control
if is_instance_valid(objectives):
top = maxf(top, objectives.position.y + objectives.size.y + 8.0)
debug_toggle.position = Vector2(12, top)
_debug_actions.position = Vector2(18, top + 30)
_debug_actions.size = Vector2(310, _debug_actions.get_combined_minimum_size().y)
_debug_actions.visible = _debug_expanded
var scroll_top := _debug_actions.position.y + _debug_actions.size.y + 8.0
_debug_scroll.position = Vector2(18, scroll_top)
_debug_scroll.size = Vector2(310, maxf(40, (_passive_captain_panel.position.y - 8.0 if _passive_captain_panel.visible else $HUDRoot.size.y - 12.0) - scroll_top))
_debug_scroll.visible = _debug_expanded
func _toggle_sidebar() -> void:
_sidebar_open = not _sidebar_open
GameState.hud_panel_state["ship_open"] = _sidebar_open
if _sidebar_tween != null and _sidebar_tween.is_running():
_sidebar_tween.kill()
_sidebar_toggle.tooltip_text = "Zamknij okno statku" if _sidebar_open else "Otwórz statek i sloty wyposażenia"
if _sidebar_open:
_sidebar.show()
else:
close_inventory()
_sidebar.visible = _sidebar_open
if _sidebar_open:
_window_manager.call("focus_window", _sidebar)
_layout_sidebar()
func _layout_sidebar() -> void:
if not is_instance_valid(_sidebar) or not is_instance_valid(_cockpit):
return
if _sidebar_tween != null and _sidebar_tween.is_running():
_sidebar_tween.kill()
var scroll := _sidebar.get_node("Scroll") as ScrollContainer
scroll.vertical_scroll_mode = ScrollContainer.SCROLL_MODE_DISABLED
var content_height: float = scroll.get_node("Contents").get_combined_minimum_size().y + 16.0
var available_height := maxf(100.0, $HUDRoot.size.y - 148.0 - _ship_passive_reserved_height)
var panel_scale := minf(EQUIPMENT_UI_SCALE, available_height / content_height)
_sidebar.scale = Vector2.ONE * panel_scale
_sidebar.size = Vector2(maxf(SIDEBAR_WIDTH, _sidebar.get_combined_minimum_size().x), content_height)
_cockpit.scale = Vector2.ONE * 0.85
_cockpit.size = Vector2(minf(850.0, ($HUDRoot.size.x - 24) / 0.85), 120)
_cockpit.position = Vector2(($HUDRoot.size.x - _cockpit.size.x * 0.85) * 0.5, $HUDRoot.size.y - _cockpit.size.y * 0.85 - 12)
if _ability_bar != null:
var abilities := _ability_bar.get_parent() as Control
abilities.set_anchors_and_offsets_preset(Control.PRESET_TOP_LEFT)
abilities.position = Vector2(_cockpit.position.x + _cockpit.size.x * _cockpit.scale.x - 204.0, _cockpit.position.y - 40.0)
abilities.size = Vector2(204, 36)
if is_instance_valid(_captain_skills_ui):
_captain_skills_ui.call_deferred("_layout")
_layout_debug()
if not _sidebar.has_meta("floating_window_dragged"):
_sidebar.position = Vector2($HUDRoot.size.x - _sidebar.size.x * _sidebar.scale.x - 8, 136)
else:
_window_manager.call("clamp_window", _sidebar)
_sidebar.visible = _sidebar_open
_inventory_clip.size = inventory_panel.size * EQUIPMENT_UI_SCALE
_layout_inventory()
func _layout_inventory() -> void:
if not is_instance_valid(_inventory_clip) or not is_instance_valid(_sidebar):
return
if _inventory_clip.has_meta("floating_window_dragged"):
_window_manager.call("clamp_window", _inventory_clip)
return
var equipment := _sidebar.get_node("Scroll/Contents/ShipEquipmentPanel") as Control
_inventory_clip.position = Vector2(maxf(12.0, _sidebar.position.x - _inventory_clip.size.x - 8), minf(equipment.global_position.y, maxf(8.0, $HUDRoot.size.y - inventory_panel.size.y * EQUIPMENT_UI_SCALE - 8)))
func _update_energy_bank_button() -> void:
if _energy_bank_button == null:
_energy_bank_button = Button.new()
_energy_bank_button.name = "EnergyBankButton"
_energy_bank_button.set_script(preload("res://scripts/ui/captain_skill_button.gd"))
_energy_bank_button.call("configure", preload("res://assets/icons/resources/energy_bank.svg"), Color("70f5df"))
_energy_bank_button.custom_minimum_size = Vector2(48, 48)
_energy_bank_button.size = Vector2(48, 48)
$HUDRoot.add_child(_energy_bank_button)
var key := Label.new()
key.text = "R"
key.mouse_filter = Control.MOUSE_FILTER_IGNORE
key.horizontal_alignment = HORIZONTAL_ALIGNMENT_RIGHT
key.vertical_alignment = VERTICAL_ALIGNMENT_TOP
key.add_theme_font_size_override("font_size", 11)
key.add_theme_color_override("font_color", Color.WHITE)
key.add_theme_color_override("font_outline_color", Color("07141e"))
key.add_theme_constant_override("outline_size", 7)
_energy_bank_button.add_child(key)
key.set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT)
key.offset_right = -5
key.offset_top = 2
var amount := Label.new()
amount.name = "Amount"
amount.mouse_filter = Control.MOUSE_FILTER_IGNORE
amount.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
amount.vertical_alignment = VERTICAL_ALIGNMENT_CENTER
amount.add_theme_font_size_override("font_size", 22)
amount.add_theme_color_override("font_color", Color.WHITE)
amount.add_theme_color_override("font_outline_color", Color("07141e"))
amount.add_theme_constant_override("outline_size", 7)
_energy_bank_button.add_child(amount)
amount.set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT)
_energy_bank_button.pressed.connect(func() -> void: player.call("use_energy_bank"))
_energy_bank_button.position = Vector2(_cockpit.position.x + _cockpit.size.x * _cockpit.scale.x * 0.5 - 24.0, _cockpit.position.y - 56.0)
var inventory := player.get_node("ShipInventory") as ShipInventory
var count := inventory.get_energy_bank_count()
(_energy_bank_button.get_node("Amount") as Label).text = str(count)
_energy_bank_button.tooltip_text = "Bank energii: %d\nR • Przywraca %d%% maksymalnej energii" % [count, roundi(GameState.captain.get_energy_bank_fraction() * 100.0)]
_energy_bank_button.disabled = count == 0 or float(player.get("energy")) >= float(player.get("max_energy")) or bool(player.get("_is_destroyed")) or bool(player.get("is_docked"))
_energy_bank_button.call("set_visual_state", 0.0, false, _energy_bank_button.disabled)
func _process(_delta: float) -> void:
_update_energy_bank_button()
_layout_inventory()
_update_ability_bar()
_layout_passive_panels()
_layout_debug()
if not _debug_expanded:
return
var inventory := player.get_node("ShipInventory") as ShipInventory
_debug_item_button.text = "LOSUJ PRZEDMIOT · POZ. %d" % GameState.system_level
_debug_item_button.disabled = inventory.get_cargo_used() >= inventory.get_cargo_capacity()
_debug_item_button.tooltip_text = "Magazyn jest pełny — zwolnij miejsce." if _debug_item_button.disabled else "Losuje przedmiot i addony dla poziomu aktualnego układu."
var game := get_parent()
debug_info.text = """POZIOM UKŁADU: %d
WROGOWIE: %d
PRĘDKOŚĆ: %.1f px/s
AKTUALNA REGENERACJA
Energia: %.1f pkt/s
Tarcze: %.1f pkt/s
%s""".replace("\r", "") % [
GameState.system_level,
int(game.call("get_remaining_enemies")),
player.velocity.length(),
float(player.call("get_energy_regeneration")),
float(player.get("shield_regeneration")),
_get_bonus_summary(),
]
func _toggle_debug() -> void:
_debug_expanded = not _debug_expanded
GameState.hud_panel_state["debug_expanded"] = _debug_expanded
debug_info.visible = _debug_expanded
_debug_scroll.visible = _debug_expanded
_debug_actions.visible = _debug_expanded
_update_debug_toggle()
_layout_debug()
func _give_debug_ammunition() -> void:
var inventory := player.get_node("ShipInventory") as ShipInventory
inventory.ammunition += 10
inventory.irradiated_ammunition += 10
inventory.missile_ammunition += 10
inventory.ammunition_changed.emit()
inventory.inventory_changed.emit()
func _give_debug_item() -> bool:
var inventory := player.get_node("ShipInventory") as ShipInventory
_debug_item_status.show()
if inventory.get_cargo_used() >= inventory.get_cargo_capacity():
_debug_item_status.text = "Magazyn pełny — zwolnij miejsce."
_debug_item_status.add_theme_color_override("font_color", Color("ff8989"))
_layout_debug.call_deferred()
return false
var item := preload("res://scripts/items/item_generator.gd").generate(GameState.system_level)
if not inventory.add_item(item):
return false
_debug_item_status.text = "Dodano: %s · Poz. %d" % [item.definition.display_name, item.item_level]
_debug_item_status.add_theme_color_override("font_color", Color("a9ef83"))
_layout_debug.call_deferred()
return true
func _update_debug_toggle() -> void:
debug_toggle.text = "DEBUG [−]" if _debug_expanded else "DEBUG [+]"
func _toggle_inventory() -> void:
if not _sidebar_open:
_toggle_sidebar()
inventory_panel.call("toggle_drawer")
func close_inventory() -> void:
inventory_panel.call("close_drawer", true)
func _get_bonus_summary() -> String:
var cooldown_bonus := 0.0
var inventory := player.get_node("ShipInventory") as ShipInventory
for item in inventory.weapon_slots + inventory.module_slots:
if item != null:
cooldown_bonus += item.get_stat_total("missile_cooldown_reduction")
return """BONUSY (ADDONY + KAPITAN)
Obrażenia broni: %+.1f%%
Szansa na krytyk: %+.1f%%
Obrażenia krytyczne: %+.1f%%
Szansa na unik: %+.1f%%
Redukcja obrażeń: %+.1f%%
Odzysk tarcz z obrażeń: %.1f%%
Regeneracja energii: %+.1f pkt/s
Regeneracja tarcz: %+.1f pkt/s
Kadłub: %+.1f pkt
Tarcze: %+.1f pkt
Energia: %+.1f pkt
Prędkość maks.: %+.1f%%
Skrócenie cooldownu rakiet: %.2f s
Doświadczenie: %+.1f%%
Kredyty: %+.1f%%
Szczęście: %.1f%% / 60%%""".replace("\r", "") % [
(float(player.call("get_weapon_damage_multiplier")) - 1.0) * 100.0,
float(player.call("get_critical_chance")) * 100.0,
float(player.get("critical_damage_bonus")) * 100.0,
float(player.call("get_evasion_chance")) * 100.0,
float(player.call("get_damage_reduction")) * 100.0,
float(player.get("shield_on_damage_percent")),
float(player.get("energy_regeneration")) - float(player.get("base_energy_regeneration")),
float(player.get("shield_regeneration")) - float(player.get("base_shield_regeneration")),
float(player.get("max_hull")) - float(player.get("base_max_hull")),
float(player.get("max_shields")) - float(player.get("base_max_shields")),
float(player.get("max_energy")) - float(player.get("base_max_energy")),
(float(player.get("max_speed")) / float(player.get("base_max_speed")) - 1.0) * 100.0,
cooldown_bonus,
(float(player.get("experience_multiplier")) - 1.0) * 100.0,
(float(player.get("credits_multiplier")) - 1.0) * 100.0,
float(player.call("get_luck_chance")) * 100.0,
]
func _create_ability_bar() -> void:
var panel := PanelContainer.new()
panel.name = "ActiveAbilities"
$HUDRoot.add_child(panel)
panel.set_anchors_and_offsets_preset(Control.PRESET_CENTER_BOTTOM)
panel.offset_left = -120.0
panel.offset_right = 120.0
panel.offset_top = -220.0
panel.offset_bottom = -176.0
panel.add_theme_stylebox_override("panel", StyleBoxEmpty.new())
_ability_bar = HBoxContainer.new()
_ability_bar.name = "AbilityButtons"
_ability_bar.alignment = BoxContainer.ALIGNMENT_END
_ability_bar.add_theme_constant_override("separation", 6)
panel.add_child(_ability_bar)
for index in ShipInventory.EXTENSION_SLOT_COUNT:
var button := Button.new()
button.set_script(preload("res://scripts/ui/captain_skill_button.gd"))
button.name = "Ability%d" % (index + 1)
button.call("configure", null, Color("91dbea"))
var shortcut := Label.new()
shortcut.name = "Shortcut"
shortcut.text = str(index + 1)
shortcut.position = Vector2(4, 2)
shortcut.mouse_filter = Control.MOUSE_FILTER_IGNORE
shortcut.add_theme_font_size_override("font_size", 9)
shortcut.add_theme_font_override("font", ThemeDB.fallback_font)
shortcut.add_theme_color_override("font_outline_color", Color("030810"))
shortcut.add_theme_constant_override("outline_size", 4)
button.add_child(shortcut)
button.add_theme_font_size_override("font_size", 11)
button.pressed.connect(func() -> void: player.call("activate_ability", index))
var timer := Label.new()
timer.name = "Cooldown"
timer.mouse_filter = Control.MOUSE_FILTER_IGNORE
timer.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
timer.vertical_alignment = VERTICAL_ALIGNMENT_CENTER
timer.add_theme_font_size_override("font_size", 13)
timer.add_theme_font_override("font", ThemeDB.fallback_font)
timer.add_theme_color_override("font_outline_color", Color("030810"))
timer.add_theme_constant_override("outline_size", 4)
button.add_child(timer)
timer.set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT)
_ability_bar.add_child(button)
_ability_buttons[index] = button
var passive := Button.new()
passive.name = "PassiveSlot%d" % (index + 1)
passive.set_script(preload("res://scripts/ui/captain_skill_button.gd"))
passive.call("configure", null, Color("85e5b6"))
passive.disabled = true
passive.mouse_default_cursor_shape = Control.CURSOR_HELP
_passive_ship_icons.add_child(passive)
_passive_ship_buttons[index] = passive
_update_ability_bar()
func _update_ability_bar() -> void:
var any_equipped := false
var any_passive := false
for index in _ability_buttons:
var button: Button = _ability_buttons[index]
var equipped: ItemInstance = player.get_node("ShipInventory").get_item("extension", index)
var passive: Button = _passive_ship_buttons[index]
passive.visible = equipped != null and equipped.is_passive_extension()
if passive.visible:
any_passive = true
button.hide()
passive.call("configure", equipped.definition.icon, Color("85e5b6"))
passive.call("set_visual_state", 0.0, false, false)
passive.tooltip_text = equipped.get_tooltip_text()
continue
(button.get_node("Shortcut") as Label).text = str(index + 1)
var ability: ActiveAbility = player.call("get_active_ability", index)
button.visible = ability != null
if ability == null:
continue
any_equipped = true
var reason: String = player.call("ability_unavailable_reason", index)
button.disabled = not reason.is_empty()
var item: ItemInstance = player.get_node("ShipInventory").get_item("extension", index)
button.call("configure", item.definition.icon, Color("91dbea"))
var cooldown := float(player.call("get_ability_cooldown", index))
button.call("set_visual_state", cooldown / maxf(0.01, ability.cooldown), false, not reason.is_empty())
(button.get_node("Cooldown") as Label).text = str(ceili(cooldown)) if cooldown > 0.0 else ""
button.tooltip_text = "[%d] %s\n" % [index + 1, ability.display_name] + ability.description + ("\n" + reason if not reason.is_empty() else "\nGotowe")
_ability_bar.get_parent().visible = any_equipped
_passive_ship_panel.visible = any_passive
func _refresh_passive_skills() -> void:
if not is_instance_valid(_passive_skills):
return
for child in _passive_skills.get_children():
_passive_skills.remove_child(child)
child.queue_free()
var catalog := preload("res://scripts/captain/captain_skills.gd")
for skill in catalog.IDS:
var rank := GameState.captain.get_skill_rank(skill)
if rank <= 0 or bool(catalog.DATA[skill]["active"]):
continue
var icon := Button.new()
icon.name = skill
icon.set_script(preload("res://scripts/ui/captain_skill_button.gd"))
icon.call("configure", catalog.icon(skill), Color(catalog.DATA[skill]["color"]))
icon.disabled = true
icon.mouse_default_cursor_shape = Control.CURSOR_HELP
icon.tooltip_text = "%s · poziom %d / 3\n%s" % [catalog.DATA[skill]["name"], rank, catalog.description(skill, rank)]
_passive_skills.add_child(icon)
_passive_captain_panel.visible = _passive_skills.get_child_count() > 0
_layout_passive_panels.call_deferred()
_layout_debug.call_deferred()