Files
Gen_Hack-and-Slash-Roguelite/Client/Assets/Scripts/Entity/Inventory.cs

168 lines
5.7 KiB
C#

using System.Collections.Generic;
using System.Linq;
using UnityEngine;
namespace Entity
{
public class Inventory
{
public Entity From { get; private set; }
private readonly List<InventorySlot> _slots;
public int Capacity { get; private set; }
public event System.Action<Item.ItemResource, int> OnItemAdded;
public event System.Action<Item.ItemResource, int> OnItemRemoved;
public event System.Action OnInventoryChanged;
public Inventory(Entity owner, int capacity = 20)
{
From = owner;
Capacity = Mathf.Max(1, capacity);
_slots = new List<InventorySlot>(Capacity);
}
public int AddItem(Item.ItemResource itemResource, int quantity)
{
if (itemResource == null || quantity <= 0)
{
Debug.LogWarning(
$"Inventory for {From?.ToString() ?? "Unknown"}: Attempted to add null item or zero/negative quantity.");
return quantity;
}
var remainingQuantity = quantity;
var addedTotal = 0;
// 1. 尝试堆叠到现有槽位 (使用 DefName 进行比较)
if (itemResource.MaxStack > 1)
{
foreach (var slot in _slots.Where(s =>
s.Item != null && s.Item.DefName == itemResource.DefName && !s.IsFull))
{
var addedToSlot = slot.AddQuantity(remainingQuantity);
remainingQuantity -= addedToSlot;
addedTotal += addedToSlot;
if (remainingQuantity <= 0) break;
}
}
// 2. 如果还有剩余,尝试添加到新槽位
while (remainingQuantity > 0 && _slots.Count < Capacity)
{
var quantityToAdd = Mathf.Min(remainingQuantity, itemResource.MaxStack);
var newSlot = new InventorySlot(itemResource, quantityToAdd);
_slots.Add(newSlot);
remainingQuantity -= quantityToAdd;
addedTotal += quantityToAdd;
}
if (addedTotal > 0)
{
OnItemAdded?.Invoke(itemResource, addedTotal);
OnInventoryChanged?.Invoke();
}
if (remainingQuantity > 0)
{
Debug.LogWarning(
$"Inventory for {From?.ToString() ?? "Unknown"} is full or cannot stack. {remainingQuantity} of {itemResource.Name} (DefName: {itemResource.DefName}) could not be added.");
}
return remainingQuantity;
}
public int RemoveItem(Item.ItemResource itemResource, int quantity)
{
if (itemResource == null || quantity <= 0)
{
Debug.LogWarning(
$"Inventory for {From?.ToString() ?? "Unknown"}: Attempted to remove null item or zero/negative quantity.");
return quantity;
}
var remainingQuantity = quantity;
var removedTotal = 0;
var slotsToClean = new List<InventorySlot>();
// 从后往前遍历,以便安全地移除空槽位 (使用 DefName 进行比较)
for (var i = _slots.Count - 1; i >= 0; i--)
{
var slot = _slots[i];
if (slot.Item != null && slot.Item.DefName == itemResource.DefName)
{
var removedFromSlot = slot.RemoveQuantity(remainingQuantity);
remainingQuantity -= removedFromSlot;
removedTotal += removedFromSlot;
if (slot.IsEmpty)
{
slotsToClean.Add(slot);
}
if (remainingQuantity <= 0) break;
}
}
foreach (var slot in slotsToClean)
{
_slots.Remove(slot);
}
if (removedTotal > 0)
{
OnItemRemoved?.Invoke(itemResource, removedTotal);
OnInventoryChanged?.Invoke();
}
if (remainingQuantity > 0)
{
Debug.LogWarning(
$"Inventory for {From?.ToString() ?? "Unknown"}: Not enough {itemResource.Name} (DefName: {itemResource.DefName}). {remainingQuantity} could not be removed.");
}
return remainingQuantity;
}
public bool HasItem(Item.ItemResource itemResource, int quantity = 1)
{
if (itemResource == null || quantity <= 0) return false;
return GetItemCount(itemResource) >= quantity;
}
public int GetItemCount(Item.ItemResource itemResource)
{
if (itemResource == null) return 0;
// 使用 DefName 进行计数
return _slots.Where(s => s.Item != null && s.Item.DefName == itemResource.DefName)
.Sum(s => s.Quantity);
}
public IReadOnlyList<InventorySlot> GetSlots()
{
return _slots.AsReadOnly();
}
public InventorySlot GetSlot(Item.ItemResource itemResource)
{
if (itemResource == null) return null;
foreach (var slot in _slots)
{
if (slot.Item != null && slot.Item.DefName == itemResource.DefName)
{
return slot;
}
}
return null;
}
public InventorySlot GetSlot(int i)
{
if (i < 0 || i >= OccupiedSlotsCount)
return null;
return _slots[i];
}
public int OccupiedSlotsCount => _slots.Count;
public int AvailableSlotsCount => Capacity - _slots.Count;
}
}