DungeonCrawler/inventory_panel.gd
Andre d029a37e7f Drag & Drop Aktionsleiste und Fähigkeiten-Panel
- Alle Aktionsleisten-Slots frei belegbar (Skills + Consumables)
- Drag & Drop: Items/Skills zwischen Slots verschieben oder rausziehen
- Gelber Highlight-Rand beim Hover über Slots während Drag
- Drag-Icon auf eigener CanvasLayer (Layer 200) für korrektes Z-Order
- Fähigkeiten-Panel (P-Taste): Listet alle Skills, per Drag auf Leiste ziehen
- Skills als Strings in action_bar_items gespeichert (generisches System)
- Cooldown-Anzeige generisch für alle Slot-Typen
- Bugfix: theme_override_constants und Tooltip-Typen in LootWindow

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-15 21:03:34 +01:00

246 lines
7.7 KiB
GDScript

# InventoryPanel.gd
# UI für das Spieler-Inventar (Equipment + Consumables)
extends CanvasLayer
signal item_selected(item, index: int)
var panel_visible = false
var player = null
# Drag & Drop
var dragging = false
var drag_item: Consumable = null
var drag_icon: TextureRect = null
@onready var panel = $Panel
@onready var gold_label = $Panel/VBoxContainer/Header/GoldLabel
@onready var item_grid = $Panel/VBoxContainer/ScrollContainer/ItemGrid
const SLOT_SIZE = 50
func _ready():
panel.visible = false
func setup(p):
player = p
if player and player.inventory:
player.inventory.inventory_changed.connect(_on_inventory_changed)
player.inventory.gold_changed.connect(_on_gold_changed)
_refresh_inventory()
func toggle():
panel_visible = !panel_visible
panel.visible = panel_visible
if panel_visible:
_refresh_inventory()
func _on_inventory_changed():
if panel_visible:
_refresh_inventory()
func _on_gold_changed(new_amount: int):
gold_label.text = str(new_amount) + " Gold"
func _refresh_inventory():
if player == null or player.inventory == null:
return
# Gold aktualisieren
gold_label.text = str(player.inventory.gold) + " Gold"
# Alte Slots entfernen
for child in item_grid.get_children():
child.queue_free()
# Slots erstellen (immer MAX_SLOTS anzeigen)
for i in range(Inventory.MAX_SLOTS):
var slot = _create_slot(i)
item_grid.add_child(slot)
func _create_slot(index: int) -> Panel:
var slot = Panel.new()
slot.custom_minimum_size = Vector2(SLOT_SIZE, SLOT_SIZE)
# Slot-Hintergrund stylen
var style = StyleBoxFlat.new()
style.bg_color = Color(0.15, 0.15, 0.15)
style.border_color = Color(0.3, 0.3, 0.3)
style.set_border_width_all(1)
slot.add_theme_stylebox_override("panel", style)
# Item vorhanden?
if player.inventory and index < player.inventory.item_count():
var item = player.inventory.get_item(index)
if item:
var item_icon = null
if item is Consumable:
item_icon = item.icon
elif item is Equipment:
item_icon = item.icon
if item_icon:
var icon = TextureRect.new()
icon.texture = item_icon
icon.expand_mode = TextureRect.EXPAND_FIT_WIDTH_PROPORTIONAL
icon.stretch_mode = TextureRect.STRETCH_KEEP_ASPECT_CENTERED
icon.custom_minimum_size = Vector2(SLOT_SIZE - 4, SLOT_SIZE - 4)
icon.position = Vector2(2, 2)
slot.add_child(icon)
else:
# Fallback: Text
var label = Label.new()
label.text = item.item_name.substr(0, 3)
label.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
label.vertical_alignment = VERTICAL_ALIGNMENT_CENTER
label.add_theme_font_size_override("font_size", 10)
if item is Equipment:
label.modulate = Equipment.get_rarity_color(item.rarity)
label.anchors_preset = Control.PRESET_FULL_RECT
slot.add_child(label)
# Stack-Count für Consumables
if item is Consumable and item.stack_size > 1:
var stack_label = Label.new()
stack_label.text = str(item.stack_size)
stack_label.horizontal_alignment = HORIZONTAL_ALIGNMENT_RIGHT
stack_label.vertical_alignment = VERTICAL_ALIGNMENT_BOTTOM
stack_label.add_theme_font_size_override("font_size", 11)
stack_label.size = Vector2(SLOT_SIZE - 4, SLOT_SIZE - 4)
stack_label.position = Vector2(0, 0)
slot.add_child(stack_label)
# Rahmen
if item is Equipment:
style.border_color = Equipment.get_rarity_color(item.rarity)
elif item is Consumable:
style.border_color = Color(0.3, 0.7, 0.3) # Grüner Rand für Consumables
style.set_border_width_all(2)
# Klick-Handler
slot.gui_input.connect(_on_slot_clicked.bind(index, item))
# Tooltip
slot.tooltip_text = _get_item_tooltip(item)
return slot
func _on_slot_clicked(event: InputEvent, index: int, item):
if event is InputEventMouseButton and event.pressed:
if item is Equipment:
if event.button_index == MOUSE_BUTTON_RIGHT:
# Rechtsklick auf Equipment: Anlegen
if player:
var old_item = player.equip_item(item)
player.inventory.remove_item(item)
if old_item:
player.inventory.add_item(old_item)
_refresh_inventory()
elif item is Consumable:
if event.button_index == MOUSE_BUTTON_RIGHT:
# Rechtsklick auf Consumable: Direkt benutzen
if player:
if player.use_consumable(item):
if item.stack_size <= 0:
player.inventory.remove_item(item)
_refresh_inventory()
player._update_action_bar_stacks()
elif event.button_index == MOUSE_BUTTON_LEFT:
# Linksklick: Drag starten
_start_drag(item)
# Drag & Drop System
func _start_drag(item: Consumable):
dragging = true
drag_item = item
# Icon am Mauszeiger erstellen
drag_icon = TextureRect.new()
drag_icon.texture = item.icon
drag_icon.custom_minimum_size = Vector2(40, 40)
drag_icon.size = Vector2(40, 40)
drag_icon.expand_mode = TextureRect.EXPAND_FIT_WIDTH_PROPORTIONAL
drag_icon.stretch_mode = TextureRect.STRETCH_KEEP_ASPECT_CENTERED
drag_icon.mouse_filter = Control.MOUSE_FILTER_IGNORE
# Eigene CanvasLayer damit Icon über allem anderen liegt
var drag_layer = CanvasLayer.new()
drag_layer.name = "DragLayer"
drag_layer.layer = 200
drag_layer.add_child(drag_icon)
get_tree().root.add_child(drag_layer)
drag_icon.position = get_viewport().get_mouse_position() - Vector2(20, 20)
# Highlight auf HUD aktivieren
if player and player.hud:
player.hud.set_drag_active(true)
func _process(_delta):
if dragging and drag_icon:
drag_icon.position = get_viewport().get_mouse_position() - Vector2(20, 20)
# HUD Slots highlighten
if player and player.hud:
player.hud.update_drag_hover(get_viewport().get_mouse_position())
func _input(event):
if not dragging:
return
if event is InputEventMouseButton and event.button_index == MOUSE_BUTTON_LEFT and not event.pressed:
# Maus losgelassen - Drop prüfen
_end_drag()
func _end_drag():
if not dragging:
return
# Prüfen ob über einem Action-Slot
if player and player.hud:
var slot_index = player.hud.get_slot_at_position(get_viewport().get_mouse_position())
if slot_index >= 2 and slot_index <= 8 and drag_item:
player.assign_to_action_bar(slot_index, drag_item)
print(drag_item.item_name + " auf Slot " + str(slot_index + 1) + " gelegt")
player.hud.set_drag_active(false)
# Aufräumen
if drag_icon:
var drag_layer = drag_icon.get_parent()
drag_layer.queue_free() # Entfernt DragLayer + Icon
drag_icon = null
dragging = false
drag_item = null
func _get_item_tooltip(item) -> String:
if item is Consumable:
return _get_consumable_tooltip(item)
elif item is Equipment:
return _get_equipment_tooltip(item)
return item.item_name
func _get_consumable_tooltip(item: Consumable) -> String:
var tooltip = item.item_name + "\n"
tooltip += "Verbrauchbar\n"
tooltip += "---\n"
tooltip += item.get_effect_text() + "\n"
tooltip += "Cooldown: " + str(item.cooldown) + "s\n"
tooltip += "Anzahl: " + str(item.stack_size) + "/" + str(item.max_stack) + "\n"
tooltip += "\n[Rechtsklick: Benutzen]\n[Shift+Linksklick: Auf Leiste legen]"
return tooltip
func _get_equipment_tooltip(item: Equipment) -> String:
var tooltip = item.item_name + "\n"
tooltip += Equipment.get_slot_name(item.slot) + "\n"
tooltip += "---\n"
if item.slot == Equipment.Slot.WEAPON:
tooltip += "Schaden: " + str(item.min_damage) + "-" + str(item.max_damage) + "\n"
tooltip += "Tempo: " + str(item.attack_speed) + "s\n"
if item.armor > 0:
tooltip += "Rüstung: +" + str(item.armor) + "\n"
if item.strength > 0:
tooltip += "Stärke: +" + str(item.strength) + "\n"
if item.agility > 0:
tooltip += "Beweglichkeit: +" + str(item.agility) + "\n"
if item.intelligence > 0:
tooltip += "Intelligenz: +" + str(item.intelligence) + "\n"
if item.stamina > 0:
tooltip += "Ausdauer: +" + str(item.stamina) + "\n"
if item.haste > 0:
tooltip += "Tempo: +" + str(int(item.haste * 100)) + "%\n"
tooltip += "\n[Rechtsklick zum Anlegen]"
return tooltip