Files
unknown 087db550f1 bloak
2026-04-16 18:19:23 +05:00

272 lines
7.5 KiB
C#
Raw Permalink 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.
using UnityEngine;
using UnityEngine.UI;
using TMPro;
/// <summary>
/// Слот инвентаря - отображает предмет и его количество
/// </summary>
public class Slot : MonoBehaviour
{
public int slotIndex;
public ItemData item;
public int amount;
[Header("UI References")]
public Image iconImage;
public TextMeshProUGUI amountText;
public GameObject amountPanel;
public Image slotBackground;
[Header("Visual Settings")]
[SerializeField] private Color emptySlotColor = new Color(0.2f, 0.2f, 0.2f, 0.5f);
[SerializeField] private Color filledSlotColor = new Color(0.3f, 0.3f, 0.3f, 0.9f);
[SerializeField] private Color hoverColor = new Color(0.5f, 0.5f, 0.5f, 1f);
[SerializeField] private Color selectedColor = new Color(0.4f, 0.6f, 0.9f, 1f);
[Header("Drag & Drop")]
[SerializeField] private bool allowDrag = true;
public bool IsEmpty => item == null || amount <= 0;
public bool HasItem => !IsEmpty;
// События для внешних подписчиков
public System.Action<Slot> OnSlotClicked;
public System.Action<Slot> OnSlotRightClicked;
public System.Action<Slot> OnSlotHovered;
public System.Action<Slot> OnSlotDragStart;
private bool _isSelected;
void Awake()
{
// Автоматическое получение компонентов если не назначены
if (iconImage == null)
iconImage = transform.Find("Icon")?.GetComponent<Image>();
if (amountText == null)
amountText = transform.Find("AmountPanel/Text")?.GetComponent<TextMeshProUGUI>();
if (amountPanel == null)
amountPanel = transform.Find("AmountPanel")?.gameObject;
if (slotBackground == null)
slotBackground = GetComponent<Image>();
}
void Start()
{
UpdateSlotUI();
}
/// <summary>
/// Обновить визуальное отображение слота
/// </summary>
public void UpdateSlotUI()
{
if (IsEmpty)
{
ClearVisuals();
return;
}
// Иконка
if (item.icon != null)
{
iconImage.sprite = item.icon;
iconImage.enabled = true;
}
else
{
iconImage.enabled = false;
}
// Количество
if (amount > 1)
{
amountText.text = amount.ToString();
amountPanel.SetActive(true);
}
else
{
amountPanel.SetActive(false);
}
// Цвет фона
if (slotBackground != null)
slotBackground.color = filledSlotColor;
}
private void ClearVisuals()
{
iconImage.sprite = null;
iconImage.enabled = false;
amountPanel?.SetActive(false);
if (slotBackground != null)
slotBackground.color = emptySlotColor;
}
/// <summary>
/// Очистить слот
/// </summary>
public void Clear()
{
item = null;
amount = 0;
UpdateSlotUI();
// Уведомляем менеджер
if (InventoryManager.Instance != null)
{
InventoryManager.Instance.OnSlotCleared(slotIndex);
}
// Вызываем событие
InventoryEvents.Instance?.InvokeSlotChanged(slotIndex, null);
}
/// <summary>
/// Установить предмет в слот
/// </summary>
public void SetItem(ItemData newItem, int newAmount)
{
item = newItem;
amount = newAmount;
UpdateSlotUI();
// Вызываем событие изменения
InventoryEvents.Instance?.InvokeSlotChanged(slotIndex, item?.id);
}
/// <summary>
/// Добавить предметы в слот
/// </summary>
/// <returns>Количество не поместившихся предметов</returns>
public int AddItems(ItemData newItem, int addAmount)
{
if (item == null)
{
// Пустой слот - просто кладём
item = newItem;
amount = Mathf.Min(addAmount, newItem.maxStack);
UpdateSlotUI();
// Событие добавления
InventoryEvents.Instance?.InvokeItemAdded(item.id, amount);
InventoryEvents.Instance?.InvokeSlotChanged(slotIndex, item.id);
return addAmount - amount;
}
if (item.id != newItem.id)
{
// Другой предмет - нельзя добавить
return addAmount;
}
// Тот же предмет - пытаемся добавить в стек
int space = item.maxStack - amount;
if (space <= 0) return addAmount;
int toAdd = Mathf.Min(space, addAmount);
amount += toAdd;
UpdateSlotUI();
// Событие изменения
InventoryEvents.Instance?.InvokeItemCountChanged(item.id, amount);
InventoryEvents.Instance?.InvokeSlotChanged(slotIndex, item.id);
return addAmount - toAdd;
}
/// <summary>
/// Взять часть предметов из слота
/// </summary>
/// <returns>(предмет, взятое количество)</returns>
public (ItemData, int) TakeItems(int takeAmount)
{
if (IsEmpty) return (null, 0);
int actualTake = Mathf.Min(takeAmount, amount);
amount -= actualTake;
ItemData resultItem = item;
if (amount <= 0)
{
Clear();
}
else
{
UpdateSlotUI();
// Событие изменения количества
InventoryEvents.Instance?.InvokeItemCountChanged(item.id, amount);
}
// Событие удаления
InventoryEvents.Instance?.InvokeItemRemoved(resultItem.id, actualTake);
return (resultItem, actualTake);
}
/// <summary>
/// Взять все предметы из слота
/// </summary>
public (ItemData, int) TakeAll()
{
return TakeItems(amount);
}
// ==================== UI Events ====================
void OnMouseDown()
{
if (Input.GetMouseButton(0))
{
OnSlotClicked?.Invoke(this);
if (allowDrag)
{
OnSlotDragStart?.Invoke(this);
}
}
else if (Input.GetMouseButton(1))
{
OnSlotRightClicked?.Invoke(this);
}
}
/// <summary>
/// Установить состояние выделения слота
/// </summary>
public void SetSelected(bool selected)
{
_isSelected = selected;
if (slotBackground != null)
{
slotBackground.color = selected ? selectedColor :
(IsEmpty ? emptySlotColor : filledSlotColor);
}
}
/// <summary>
/// Поменять содержимое с другим слотом
/// </summary>
public void SwapWith(Slot other)
{
if (other == null || other == this) return;
var tempItem = this.item;
var tempAmount = this.amount;
this.SetItem(other.item, other.amount);
other.SetItem(tempItem, tempAmount);
}
// ==================== Getters ====================
public ItemData GetItem() => item;
public int GetAmount() => amount;
public string GetItemId() => item?.id;
public bool IsSelected() => _isSelected;
}