Randoloot/scripts/game/flight_hud.gd
2026-10-12 22:16:09 +02:00

297 lines
12 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
@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 _debug_expanded := true
var _ability_buttons: Dictionary = {}
var _ability_bar: HBoxContainer
var _ability_ready_style: StyleBoxFlat
var _ability_blocked_style: StyleBoxFlat
var _inventory_clip: Control
var _sidebar: PanelContainer
var _sidebar_toggle: Button
var _sidebar_open := true
var _sidebar_tween: Tween
const SIDEBAR_WIDTH := 306.0
var _debug_scroll: ScrollContainer
var _captain_panel: PanelContainer
var _cockpit: Control
func _ready() -> void:
_sidebar_open = bool(GameState.hud_panel_state.get("ship_open", true))
_debug_expanded = bool(GameState.hud_panel_state.get("debug_expanded", true))
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))))
_create_sidebar()
_inventory_clip = Control.new()
_inventory_clip.name = "InventoryDrawer"
_inventory_clip.clip_contents = true
_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)
$HUDRoot.resized.connect(func() -> void: _layout_sidebar.call_deferred())
_create_ability_bar()
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(320, _captain_panel.get_combined_minimum_size().y)
_captain_panel.resized.connect(_layout_debug)
_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, 0.97)
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())
var crafting := PanelContainer.new()
crafting.name = "CraftingPanel"
crafting.set_script(preload("res://scripts/ui/ship_crafting_panel.gd"))
equipment.get_node("Contents").add_child(crafting)
contents.minimum_size_changed.connect(func() -> void: _layout_sidebar.call_deferred())
_sidebar_toggle = Button.new()
_sidebar_toggle.name = "ShipToggle"
_sidebar_toggle.text = "STATEK ▾" if _sidebar_open else "STATEK ◀"
_sidebar_toggle.add_theme_font_size_override("font_size", 12)
_sidebar_toggle.focus_mode = Control.FOCUS_NONE
$HUDRoot.add_child(_sidebar_toggle)
_sidebar_toggle.set_anchors_and_offsets_preset(Control.PRESET_TOP_RIGHT)
_sidebar_toggle.offset_left = -180
_sidebar_toggle.offset_right = -12
_sidebar_toggle.offset_top = 12
_sidebar_toggle.offset_bottom = 40
_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)
_layout_debug()
func _layout_debug() -> void:
if _debug_scroll == null:
return
var top := _captain_panel.position.y + _captain_panel.size.y + 6.0
debug_toggle.position = Vector2(12, top)
_debug_scroll.position = Vector2(18, top + 30)
_debug_scroll.size = Vector2(310, maxf(40, $HUDRoot.size.y - top - 42))
_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.text = "STATEK ▾" if _sidebar_open else "STATEK ◀"
if _sidebar_open:
_sidebar.show()
else:
close_inventory()
_sidebar_tween = create_tween()
_sidebar_tween.tween_property(_sidebar, "position:x", $HUDRoot.size.x - _sidebar.size.x - 8 if _sidebar_open else $HUDRoot.size.x, 0.25).set_trans(Tween.TRANS_CUBIC).set_ease(Tween.EASE_OUT if _sidebar_open else Tween.EASE_IN)
if not _sidebar_open:
_sidebar_tween.tween_callback(_sidebar.hide)
func _layout_sidebar() -> void:
if _sidebar_tween != null and _sidebar_tween.is_running():
_sidebar_tween.kill()
_sidebar.size = Vector2(maxf(SIDEBAR_WIDTH, _sidebar.get_combined_minimum_size().x), minf(_sidebar.get_node("Scroll/Contents").get_combined_minimum_size().y + 16.0, maxf(100.0, $HUDRoot.size.y - 64.0)))
_cockpit.scale = Vector2.ONE * 0.85
_cockpit.size = Vector2(minf(640.0, ($HUDRoot.size.x - 24) / 0.85), 126)
_cockpit.position = Vector2(($HUDRoot.size.x - _cockpit.size.x * 0.85) * 0.5, $HUDRoot.size.y - _cockpit.size.y * 0.85 - 12)
_layout_debug()
_sidebar.position = Vector2($HUDRoot.size.x - _sidebar.size.x - 8 if _sidebar_open else $HUDRoot.size.x, 44)
_sidebar.visible = _sidebar_open
_inventory_clip.size = inventory_panel.size
_layout_inventory()
func _layout_inventory() -> void:
if _inventory_clip == null:
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 - 8)))
func _process(_delta: float) -> void:
_layout_inventory()
_update_ability_bar()
if not _debug_expanded:
return
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.get("energy_regeneration")) + float(player.call("get_solar_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
_update_debug_toggle()
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%%""".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,
]
func _create_ability_bar() -> void:
_ability_ready_style = _make_ability_style(true)
_ability_blocked_style = _make_ability_style(false)
var panel := PanelContainer.new()
panel.name = "ActiveAbilities"
$HUDRoot.add_child(panel)
panel.set_anchors_and_offsets_preset(Control.PRESET_CENTER_BOTTOM)
panel.offset_left = -300.0
panel.offset_right = 300.0
panel.offset_top = -188.0
panel.offset_bottom = -146.0
_ability_bar = HBoxContainer.new()
_ability_bar.add_theme_constant_override("separation", 4)
panel.add_child(_ability_bar)
for index in ShipInventory.EXTENSION_SLOT_COUNT:
var button := Button.new()
button.name = "Ability%d" % (index + 1)
button.custom_minimum_size = Vector2(110, 36)
button.add_theme_font_size_override("font_size", 11)
button.pressed.connect(func() -> void: player.call("activate_ability", index))
_ability_bar.add_child(button)
_ability_buttons[index] = button
_update_ability_bar()
func _update_ability_bar() -> void:
var any_equipped := false
for index in _ability_buttons:
var button: Button = _ability_buttons[index]
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()
button.text = "[%d] %s\n%s" % [index + 1, ability.display_name, "GOTOWE" if reason.is_empty() else reason]
var style := _ability_ready_style if reason.is_empty() else _ability_blocked_style
button.add_theme_stylebox_override("normal", style)
button.add_theme_stylebox_override("disabled", style)
button.add_theme_stylebox_override("hover", style)
button.add_theme_color_override("font_color", Color("a5ffda"))
button.add_theme_color_override("font_disabled_color", Color("a3aebb"))
button.tooltip_text = ability.description + ("\n" + reason if not reason.is_empty() else "\nGotowe")
_ability_bar.get_parent().visible = any_equipped
func _make_ability_style(ready: bool) -> StyleBoxFlat:
var style := StyleBoxFlat.new()
style.bg_color = Color("174237") if ready else Color("202731")
style.border_color = Color("77e8bc") if ready else Color("526071")
style.set_border_width_all(2 if ready else 1)
style.set_content_margin_all(6)
return style