Randoloot/scripts/game/flight_hud.gd
2026-10-11 17:16:45 +02:00

214 lines
8.9 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
func _ready() -> void:
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", 9)
# Establish anchor layout before applying offsets; absolute layout resets anchors.
var equipment := $HUDRoot/ShipEquipmentPanel as Control
equipment.set("layout_mode", 1)
equipment.set_anchors_and_offsets_preset(Control.PRESET_TOP_RIGHT)
equipment.offset_left = -330.0
equipment.offset_right = -10.0
_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(780, 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()
$HUDRoot/CaptainPanel.resized.connect(func() -> void: _layout_sidebar.call_deferred())
_layout_sidebar.call_deferred()
func _layout_sidebar() -> void:
var captain_panel := $HUDRoot/CaptainPanel as Control
var equipment_panel := $HUDRoot/ShipEquipmentPanel as Control
captain_panel.grow_vertical = Control.GROW_DIRECTION_END
equipment_panel.grow_vertical = Control.GROW_DIRECTION_END
equipment_panel.position.y = captain_panel.position.y + captain_panel.size.y + 6.0
equipment_panel.size.y = equipment_panel.get_combined_minimum_size().y
_inventory_clip.size = inventory_panel.size
_inventory_clip.position = Vector2(equipment_panel.position.x - _inventory_clip.size.x - 8, equipment_panel.position.y)
func _process(_delta: float) -> void:
_update_ability_bar()
if not _debug_expanded:
return
var ship_position := player.global_position
var ship_velocity := player.velocity
var angular_speed := float(player.get("angular_velocity"))
var game := get_parent()
var enemy_count: int = game.call("get_remaining_enemies")
var goal: Node2D = game.get("protected_planet")
var to_planet := goal.global_position - player.global_position
debug_info.text = """STEROWANIE
W: ciąg S: hamulec / wsteczny
Tab: mini boost (+100%% prędkości, 20 energii/s)
Q / E: strafe A / D: obrót
LPM / PPM: broń 1 / broń 2
1–6: aktywne rozszerzenia
UKŁAD: %d · PLANETY: %d
WROGOWIE: %d
CEL: %s
PLANETA RASY: %.0f px · %.0f°
STATEK
KADŁUB: %d / %d
TARCZE: %d / %d
ENERGIA: %d / %d
REGEN E / T: %.1f / %.1f /s
RUCH
PRĘDKOŚĆ: %.1f px/s
WEKTOR: [%.1f, %.1f] px/s
POZYCJA: [%.1f, %.1f]
KIERUNEK: %.1f°
OBRÓT: %.2f rad/s""" % [
GameState.system_level, int(game.get("system_data")["planets"].size()), enemy_count,
"Odwiedź chronioną rasę" if bool(game.get("system_cleared")) else "Oczyść układ",
to_planet.length(), wrapf(rad_to_deg(to_planet.angle()) + 90.0, 0.0, 360.0),
roundi(float(player.get("hull"))), roundi(float(player.get("max_hull"))),
roundi(float(player.get("shields"))), roundi(float(player.get("max_shields"))),
roundi(float(player.get("energy"))), roundi(float(player.get("max_energy"))),
float(player.get("energy_regeneration")) + float(player.call("get_solar_regeneration")),
float(player.get("shield_regeneration")),
ship_velocity.length(), ship_velocity.x, ship_velocity.y,
ship_position.x, ship_position.y, rad_to_deg(player.rotation), angular_speed,
]
debug_info.text += "\n\n" + _get_bonus_summary()
func _toggle_debug() -> void:
_debug_expanded = not _debug_expanded
debug_info.visible = _debug_expanded
_update_debug_toggle()
func _update_debug_toggle() -> void:
debug_toggle.text = "DEBUG [−]" if _debug_expanded else "DEBUG [+]"
func _toggle_inventory() -> void:
inventory_panel.call("toggle_drawer")
func close_inventory() -> void:
inventory_panel.call("close_drawer", true)
func _get_bonus_summary() -> String:
# Read final ship values so gear and captain multipliers match actual combat.
return """BONUSY ŁĄCZNE (MODUŁY + KAPITAN)
Obrażenia broni: %+.1f%% (×%.3f)
Szansa na krytyk: %.1f%%
Obrażenia krytyczne: ×%.2f (%+.1f%% bonusu)
Szansa na unik: %.1f%%
Redukcja obrażeń: %.1f%%
Regeneracja energii: %.1f pkt/s (%+.1f)
Ładowanie solarne: +%.1f pkt/s
Regeneracja tarcz: %.1f pkt/s (%+.1f)
Maks. kadłub: %.1f (%+.1f pkt)
Maks. tarcze: %.1f (%+.1f pkt)
Maks. energia: %.1f (%+.1f pkt)
Maks. prędkość: %.1f px/s (%+.1f%%)
Zdobywane XP: %+.1f%%
Zdobywane kredyty: %+.1f%%""" % [
(float(player.call("get_weapon_damage_multiplier")) - 1.0) * 100.0,
float(player.call("get_weapon_damage_multiplier")),
float(player.call("get_critical_chance")) * 100.0,
float(player.call("get_critical_multiplier")),
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("energy_regeneration")),
float(player.get("energy_regeneration")) - float(player.get("base_energy_regeneration")),
float(player.call("get_solar_regeneration")),
float(player.get("shield_regeneration")),
float(player.get("shield_regeneration")) - float(player.get("base_shield_regeneration")),
float(player.get("max_hull")), float(player.get("max_hull")) - float(player.get("base_max_hull")),
float(player.get("max_shields")), float(player.get("max_shields")) - float(player.get("base_max_shields")),
float(player.get("max_energy")), float(player.get("max_energy")) - float(player.get("base_max_energy")),
float(player.get("max_speed")), (float(player.get("max_speed")) / float(player.get("base_max_speed")) - 1.0) * 100.0,
(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_BOTTOM_LEFT)
panel.offset_left = 12.0
panel.offset_right = 12.0
panel.offset_top = -54.0
panel.offset_bottom = -12.0
_ability_bar = HBoxContainer.new()
_ability_bar.add_theme_constant_override("separation", 4)
panel.add_child(_ability_bar)
for index in 6:
var button := Button.new()
button.name = "Ability%d" % (index + 1)
button.custom_minimum_size = Vector2(120, 40)
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