2025-11-16 23:11:51 +00:00
|
|
|
extends Control
|
|
|
|
|
class_name WeaponSlot
|
|
|
|
|
## Weapon slot that displays weapon icon and shows tooltip on hover
|
|
|
|
|
|
|
|
|
|
# References
|
|
|
|
|
@onready var icon_rect: TextureRect = $SlotPanel/MarginContainer/IconRect
|
|
|
|
|
var tooltip: PanelContainer = null
|
2026-07-01 23:37:56 +01:00
|
|
|
# Fallback name display for weapons without an icon texture
|
|
|
|
|
var _name_label: Label = null
|
2025-11-16 23:11:51 +00:00
|
|
|
|
|
|
|
|
# Weapon data
|
|
|
|
|
var weapon_data: WeaponData = null
|
|
|
|
|
var slot_name: String = "Main Hand"
|
|
|
|
|
|
|
|
|
|
func _ready():
|
|
|
|
|
# Create tooltip as a top-level CanvasLayer child so it's not clipped
|
|
|
|
|
_create_tooltip()
|
|
|
|
|
|
|
|
|
|
# Connect mouse events
|
|
|
|
|
mouse_entered.connect(_on_mouse_entered)
|
|
|
|
|
mouse_exited.connect(_on_mouse_exited)
|
|
|
|
|
|
|
|
|
|
## Create tooltip as a top-level node to avoid clipping
|
|
|
|
|
func _create_tooltip():
|
|
|
|
|
# Load tooltip scene template
|
|
|
|
|
var tooltip_scene = load("res://level/ui/scenes/weapon_tooltip.tscn")
|
|
|
|
|
if tooltip_scene:
|
|
|
|
|
tooltip = tooltip_scene.instantiate()
|
|
|
|
|
# Add to the root CanvasLayer (HUD) so it's not clipped
|
|
|
|
|
var hud = get_node_or_null("/root/HUD")
|
|
|
|
|
if hud:
|
|
|
|
|
hud.add_child(tooltip)
|
|
|
|
|
tooltip.hide()
|
|
|
|
|
else:
|
|
|
|
|
push_error("[WeaponSlot] Could not find HUD node")
|
|
|
|
|
else:
|
|
|
|
|
push_error("[WeaponSlot] Failed to load weapon_tooltip.tscn")
|
|
|
|
|
|
|
|
|
|
## Set weapon data and update display
|
|
|
|
|
func set_weapon(data: WeaponData, name: String = "Main Hand"):
|
|
|
|
|
weapon_data = data
|
|
|
|
|
slot_name = name
|
|
|
|
|
_update_display()
|
|
|
|
|
|
|
|
|
|
## Clear the weapon slot
|
|
|
|
|
func clear_weapon():
|
|
|
|
|
weapon_data = null
|
|
|
|
|
_update_display()
|
|
|
|
|
|
|
|
|
|
## Update the icon display
|
|
|
|
|
func _update_display():
|
|
|
|
|
if not icon_rect:
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
if weapon_data and weapon_data.icon:
|
|
|
|
|
icon_rect.texture = weapon_data.icon
|
|
|
|
|
icon_rect.modulate = Color.WHITE
|
2026-07-01 23:37:56 +01:00
|
|
|
_set_name_fallback("")
|
|
|
|
|
elif weapon_data:
|
|
|
|
|
# No icon on this weapon - show its name in the slot instead
|
|
|
|
|
icon_rect.texture = null
|
|
|
|
|
icon_rect.modulate = Color.WHITE
|
|
|
|
|
_set_name_fallback(weapon_data.weapon_name)
|
2025-11-16 23:11:51 +00:00
|
|
|
else:
|
|
|
|
|
icon_rect.texture = null
|
|
|
|
|
icon_rect.modulate = Color(0.3, 0.3, 0.3, 0.5) # Dim empty slot
|
2026-07-01 23:37:56 +01:00
|
|
|
_set_name_fallback("")
|
|
|
|
|
|
|
|
|
|
## Show/hide the fallback name label ("" hides it)
|
|
|
|
|
func _set_name_fallback(text: String):
|
|
|
|
|
if text == "":
|
|
|
|
|
if _name_label:
|
|
|
|
|
_name_label.hide()
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
if not _name_label:
|
|
|
|
|
_name_label = Label.new()
|
|
|
|
|
_name_label.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
|
|
|
|
|
_name_label.vertical_alignment = VERTICAL_ALIGNMENT_CENTER
|
|
|
|
|
_name_label.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART
|
|
|
|
|
_name_label.add_theme_font_size_override("font_size", 12)
|
|
|
|
|
_name_label.add_theme_color_override("font_color", Color(1.0, 0.85, 0.4))
|
|
|
|
|
_name_label.add_theme_color_override("font_outline_color", Color.BLACK)
|
|
|
|
|
_name_label.add_theme_constant_override("outline_size", 2)
|
|
|
|
|
_name_label.set_anchors_preset(Control.PRESET_FULL_RECT)
|
|
|
|
|
_name_label.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
|
|
|
|
var container = get_node_or_null("SlotPanel/MarginContainer")
|
|
|
|
|
if container:
|
|
|
|
|
container.add_child(_name_label)
|
|
|
|
|
else:
|
|
|
|
|
add_child(_name_label)
|
|
|
|
|
|
|
|
|
|
_name_label.text = text
|
|
|
|
|
_name_label.show()
|
2025-11-16 23:11:51 +00:00
|
|
|
|
|
|
|
|
## Show tooltip on mouse enter
|
|
|
|
|
func _on_mouse_entered():
|
|
|
|
|
if weapon_data and tooltip:
|
|
|
|
|
_update_tooltip()
|
|
|
|
|
# Position tooltip to the right of the slot
|
|
|
|
|
var global_pos = global_position
|
|
|
|
|
tooltip.position = Vector2(global_pos.x + size.x + 10, global_pos.y)
|
|
|
|
|
tooltip.show()
|
|
|
|
|
|
|
|
|
|
## Hide tooltip on mouse exit
|
|
|
|
|
func _on_mouse_exited():
|
|
|
|
|
if tooltip:
|
|
|
|
|
tooltip.hide()
|
|
|
|
|
|
|
|
|
|
## Update tooltip content
|
|
|
|
|
func _update_tooltip():
|
|
|
|
|
if not tooltip or not weapon_data:
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
var tooltip_label = tooltip.get_node_or_null("MarginContainer/VBoxContainer/StatsLabel")
|
|
|
|
|
if not tooltip_label:
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
var text = ""
|
|
|
|
|
text += slot_name.to_upper() + "\n"
|
|
|
|
|
text += weapon_data.weapon_name + "\n"
|
|
|
|
|
text += "---\n"
|
|
|
|
|
text += "Damage: " + str(weapon_data.damage) + "\n"
|
|
|
|
|
text += "Range: " + str(weapon_data.attack_range) + "\n"
|
|
|
|
|
text += "Cooldown: " + str(weapon_data.attack_cooldown) + "s\n"
|
|
|
|
|
text += "Knockback: " + str(weapon_data.knockback_force) + "\n"
|
|
|
|
|
|
|
|
|
|
if weapon_data.can_block:
|
|
|
|
|
text += "Block: " + str(int(weapon_data.block_reduction * 100)) + "%\n"
|
|
|
|
|
|
|
|
|
|
if weapon_data.description:
|
|
|
|
|
text += "\n" + weapon_data.description
|
|
|
|
|
|
|
|
|
|
tooltip_label.text = text
|