198 lines
6.9 KiB
C#
198 lines
6.9 KiB
C#
using UnityEngine;
|
|
using UnityEngine.UI;
|
|
using UnityEngine.EventSystems;
|
|
using TMPro;
|
|
using System;
|
|
|
|
namespace Ashwild.Inventory
|
|
{
|
|
public class SlotUI : MonoBehaviour, IBeginDragHandler, IDragHandler, IEndDragHandler, IDropHandler, IPointerClickHandler, IPointerEnterHandler, IPointerExitHandler
|
|
{
|
|
[Header("References")]
|
|
[SerializeField] private Image iconImage;
|
|
[SerializeField] private TextMeshProUGUI quantityText;
|
|
[SerializeField] private Image highlightImage;
|
|
|
|
[Header("Uses Bar")]
|
|
[Tooltip("Root object of the uses/durability bar — shown only for items that track uses.")]
|
|
[SerializeField] private GameObject usageBarRoot;
|
|
[Tooltip("Filled image whose fillAmount maps to the remaining uses (Image Type = Filled).")]
|
|
[SerializeField] private Image usageBarFill;
|
|
[Tooltip("Icon tint applied when the item still has uses left.")]
|
|
[SerializeField] private Color normalTint = Color.white;
|
|
[Tooltip("Icon (and bar) tint applied when the item is depleted — a broken repairable tool / empty container.")]
|
|
[SerializeField] private Color depletedTint = Color.red;
|
|
|
|
private int slotIndex;
|
|
private Action<int, int> onSwapRequested;
|
|
private Action<int, bool> onClicked;
|
|
private Action<int> onHoverEnter;
|
|
private Action onHoverExit;
|
|
|
|
public int SlotIndex => slotIndex;
|
|
|
|
// Static drag state shared across all slots
|
|
private static SlotUI draggedSlot;
|
|
private static GameObject ghostObject;
|
|
private static Image ghostIcon;
|
|
private static TextMeshProUGUI ghostQuantity;
|
|
|
|
public static void SetupGhost(GameObject ghost, Image icon, TextMeshProUGUI qty)
|
|
{
|
|
ghostObject = ghost;
|
|
ghostIcon = icon;
|
|
ghostQuantity = qty;
|
|
ghostObject.SetActive(false);
|
|
}
|
|
|
|
public void Initialize(int index, Action<int, int> swapCallback, Action<int, bool> clickCallback,
|
|
Action<int> hoverEnterCallback = null, Action hoverExitCallback = null)
|
|
{
|
|
slotIndex = index;
|
|
onSwapRequested = swapCallback;
|
|
onClicked = clickCallback;
|
|
onHoverEnter = hoverEnterCallback;
|
|
onHoverExit = hoverExitCallback;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Redraws the slot: icon, quantity, and the uses bar. Uses-tracked items (tools, multi-bite
|
|
/// food) show a fill bar for their remaining uses and turn red once depleted.
|
|
/// </summary>
|
|
public void UpdateVisual(InventorySlot slot)
|
|
{
|
|
if (slot == null || slot.IsEmpty)
|
|
{
|
|
iconImage.gameObject.SetActive(false);
|
|
quantityText.gameObject.SetActive(false);
|
|
if (usageBarRoot != null) usageBarRoot.SetActive(false);
|
|
}
|
|
else
|
|
{
|
|
iconImage.gameObject.SetActive(true);
|
|
iconImage.sprite = slot.ItemData.Icon;
|
|
bool showQty = slot.Quantity > 1;
|
|
quantityText.gameObject.SetActive(showQty);
|
|
if (showQty)
|
|
quantityText.text = slot.Quantity.ToString();
|
|
|
|
UpdateUsageBar(slot);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Shows the uses bar and tints the icon red when the item is depleted; hides the bar entirely
|
|
/// for items that do not track uses. Preserves the current icon alpha so a mid-drag fade stays.
|
|
/// </summary>
|
|
private void UpdateUsageBar(InventorySlot slot)
|
|
{
|
|
bool hasUses = slot.ItemData.HasUses;
|
|
|
|
if (usageBarRoot != null)
|
|
usageBarRoot.SetActive(hasUses);
|
|
|
|
Color tint = (hasUses && slot.IsDepleted) ? depletedTint : normalTint;
|
|
tint.a = iconImage.color.a;
|
|
iconImage.color = tint;
|
|
|
|
if (hasUses && usageBarFill != null)
|
|
usageBarFill.fillAmount = (float)slot.CurrentUses / slot.ItemData.MaxUses;
|
|
}
|
|
|
|
public void SetSelected(bool selected)
|
|
{
|
|
if (highlightImage != null)
|
|
highlightImage.gameObject.SetActive(selected);
|
|
}
|
|
|
|
// Drag & Drop
|
|
|
|
public void OnBeginDrag(PointerEventData eventData)
|
|
{
|
|
if (eventData.button != PointerEventData.InputButton.Left) return;
|
|
|
|
InventorySlot slot = PlayerInventory.Instance.GetSlot(slotIndex);
|
|
if (slot == null || slot.IsEmpty) return;
|
|
|
|
draggedSlot = this;
|
|
|
|
// Show ghost
|
|
if (ghostObject != null)
|
|
{
|
|
ghostObject.SetActive(true);
|
|
ghostIcon.sprite = slot.ItemData.Icon;
|
|
ghostIcon.gameObject.SetActive(true);
|
|
|
|
bool showQty = slot.Quantity > 1;
|
|
ghostQuantity.gameObject.SetActive(showQty);
|
|
if (showQty)
|
|
ghostQuantity.text = slot.Quantity.ToString();
|
|
|
|
ghostObject.transform.position = eventData.position;
|
|
}
|
|
|
|
// Make source icon semi-transparent
|
|
Color c = iconImage.color;
|
|
c.a = 0.4f;
|
|
iconImage.color = c;
|
|
}
|
|
|
|
public void OnDrag(PointerEventData eventData)
|
|
{
|
|
if (draggedSlot != this) return;
|
|
|
|
if (ghostObject != null)
|
|
ghostObject.transform.position = eventData.position;
|
|
}
|
|
|
|
public void OnEndDrag(PointerEventData eventData)
|
|
{
|
|
if (draggedSlot != this) return;
|
|
|
|
// Hide ghost
|
|
if (ghostObject != null)
|
|
ghostObject.SetActive(false);
|
|
|
|
// Restore icon opacity
|
|
Color c = iconImage.color;
|
|
c.a = 1f;
|
|
iconImage.color = c;
|
|
|
|
draggedSlot = null;
|
|
}
|
|
|
|
public void OnDrop(PointerEventData eventData)
|
|
{
|
|
if (draggedSlot == null || draggedSlot == this) return;
|
|
|
|
onSwapRequested?.Invoke(draggedSlot.SlotIndex, slotIndex);
|
|
}
|
|
|
|
public void OnPointerClick(PointerEventData eventData)
|
|
{
|
|
if (eventData.dragging) return;
|
|
|
|
if (eventData.button == PointerEventData.InputButton.Right)
|
|
onClicked?.Invoke(slotIndex, true);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Reports the hovered slot index so the manager can show its description panel. Suppressed
|
|
/// while a drag is in progress, where the panel would only get in the way.
|
|
/// </summary>
|
|
public void OnPointerEnter(PointerEventData eventData)
|
|
{
|
|
if (draggedSlot != null) return;
|
|
onHoverEnter?.Invoke(slotIndex);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Reports that the pointer left the slot so the manager can hide the description panel.
|
|
/// </summary>
|
|
public void OnPointerExit(PointerEventData eventData)
|
|
{
|
|
onHoverExit?.Invoke();
|
|
}
|
|
}
|
|
}
|