You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
Babushka/scripts/CSharp/Common/Inventory/InventoryInstance.cs

196 lines
5.7 KiB

#nullable enable
using System;
using Godot;
using System.Collections.Generic;
using System.Linq;
using Babushka.scripts.CSharp.Common.Savegame;
namespace Babushka.scripts.CSharp.Common.Inventory;
public partial class InventoryInstance
{
private readonly List<InventorySlot> _slots;
public IReadOnlyList<InventorySlot> Slots => _slots;
public event Action? SlotAmountChanged;
public event Action? InventoryContentsChanged;
/// <summary>
/// The total amount of InventorySlots in the inventory (empty and occupied).
/// </summary>
[Export]
public int SlotAmount
{
get => _slots.Count;
set
{
if (value < _slots.Count)
{
_slots.RemoveRange(value, _slots.Count - value);
}
else if (value > _slots.Count)
{
for (var i = _slots.Count; i < value; i++)
{
_slots.Add(new InventorySlot());
}
}
SlotAmountChanged?.Invoke();
}
}
public InventoryInstance(int slotCount)
{
_slots = new();
SlotAmount = slotCount;
}
public InventoryActionResult AddItem(ItemInstance newItem)
{
var result = AddItemAndStackRecursive(newItem, 0);
InventoryContentsChanged?.Invoke();
return result;
}
private InventoryActionResult AddItemAndStackRecursive(ItemInstance newItem, int slotSearch)
{
if (newItem.blueprint == null || newItem.amount == 0)
return InventoryActionResult.SourceDoesNotExist;
var slotIndex = -1;
// find stackable slot
for (var i = slotSearch; i < _slots.Count; i++)
{
if (_slots[i].itemInstance?.blueprint == newItem.blueprint)
{
slotIndex = i;
break;
}
}
if (slotIndex < 0)
{
// find empty slot
for (var i = slotSearch; i < _slots.Count; i++)
{
if (_slots[i].IsEmpty())
{
slotIndex = i;
break;
}
}
}
if (slotIndex < 0)
{
return InventoryActionResult.DestinationFull;
}
var itemInstance = _slots[slotIndex].itemInstance ??
new ItemInstance { blueprint = newItem.blueprint, amount = 0 };
var maxStack = itemInstance!.blueprint.maxStack;
var freeOnStack = maxStack - itemInstance.amount;
var moveAmount = Math.Min(freeOnStack, newItem.amount);
itemInstance.amount += moveAmount;
newItem.amount -= moveAmount;
_slots[slotIndex].itemInstance = itemInstance;
return newItem.amount <= 0
? InventoryActionResult.Success
: AddItemAndStackRecursive(newItem, slotIndex + 1);
}
public InventoryActionResult RemoveItem(int inventorySlot, out ItemInstance? itemInstance)
{
if (inventorySlot < 0 || inventorySlot >= _slots.Count)
{
itemInstance = null;
return InventoryActionResult.SourceDoesNotExist;
}
if (_slots[inventorySlot].IsEmpty())
{
itemInstance = null;
return InventoryActionResult.SourceIsEmpty;
}
itemInstance = _slots[inventorySlot].itemInstance;
if (itemInstance == null)
return InventoryActionResult.SourceDoesNotExist;
itemInstance.amount -= 1;
if (itemInstance.amount == 0)
_slots[inventorySlot].itemInstance = null;
InventoryContentsChanged?.Invoke();
return InventoryActionResult.Success;
}
public InventoryActionResult RemoveItem(int inventorySlot)
{
return RemoveItem(inventorySlot, out _);
}
public InventoryActionResult TryRemoveAllItems(ItemInstance items)
{
var hasItemsCount = TotalItemsOfBlueprint(items.blueprint);
if (hasItemsCount < items.amount)
return InventoryActionResult.SourceDoesNotExist;
var amountToRemove = items.amount;
foreach (var s in _slots)
{
if (s.IsEmpty() || s.itemInstance!.blueprint != items.blueprint)
continue;
var slotItem = s.itemInstance!;
if (slotItem.amount <= amountToRemove)
{
amountToRemove -= slotItem.amount;
s.itemInstance = null;
}
else
{
slotItem.amount -= amountToRemove;
amountToRemove = 0;
}
if (amountToRemove == 0)
break;
}
InventoryContentsChanged?.Invoke();
return InventoryActionResult.Success;
}
public InventoryActionResult AddItemToSlot(ItemInstance itemInstance, int destinationSlot)
{
if (destinationSlot < 0 || destinationSlot >= _slots.Count)
return InventoryActionResult.DestinationDoesNotExist;
if (!_slots[destinationSlot].IsEmpty())
return InventoryActionResult.DestinationFull;
_slots[destinationSlot].itemInstance = itemInstance;
InventoryContentsChanged?.Invoke();
return InventoryActionResult.Success;
}
public int TotalItemsOfBlueprint(ItemResource blueprint)
{
return _slots
.Where(i => !i.IsEmpty() && i.itemInstance!.blueprint == blueprint)
.Sum(i => i.itemInstance!.amount);
}
public bool HasItems(ItemInstance item)
{
return TotalItemsOfBlueprint(item.blueprint) >= item.amount;
}
public bool HasItems(IEnumerable<ItemInstance> items)
{
return items.All(HasItems);
}
}