Newer
Older
TheVengeance-Project-IADE-Unity2D / Assets / Scripts / Player / Inventory / Inventory.cs
using System;
using System.Collections.Generic;
using UnityEngine;

[Serializable]
public class Inventory
{
    [SerializeField] private List<InventorySlot> items;
    private GameObject gameObject;
    public GameObject GameObject => gameObject;
    public int Count => items.Count;
    public int Capacity => items.Capacity;

    // Event triggered when inventory changes
    public event Action InventoryChanged;

    //Constructor
    public Inventory(int capacity, GameObject gameObject)
    {
        items = new List<InventorySlot>(capacity);
        this.gameObject = gameObject;
    }

    //Adds an item to the inventory
    public void AddItem(Item item, int amount = 1)
    {
        //Checks if the item already exists on the inventory slots
        InventorySlot existentSlot = FindSlotByItem(item);

        //If a slot is available increment the number of the item on that slot
        if (existentSlot != null)
        {
            int totalAmount = existentSlot.Amount + amount;

            if (totalAmount > existentSlot.MaxAmount)
            {
                int possibleAmountToAdd = existentSlot.MaxAmount - existentSlot.Amount;
                existentSlot.Amount += possibleAmountToAdd;

                //Creates a new slot if possible with the rest of the amount
                if (!IsFull())
                {
                    InventorySlot slot = new InventorySlot(item, amount - possibleAmountToAdd);
                    items.Add(slot);
                }
            }

            else
            {
                existentSlot.Amount += amount;
            }

            Debug.Log($"Added item: {item.ItemName}");
            InventoryChanged?.Invoke();
            return;
        }

        //Checks if the inventory is not full
        if (!IsFull())
        {
            Debug.Log($"Added item: {item.ItemName}");
            //If there are no items of that reference on the inventory
            //Creates a new slot with that item reference
            InventorySlot slot = new InventorySlot(item, amount);
            items.Add(slot);
            InventoryChanged?.Invoke();
            return;
        }

        Debug.LogWarning("Inventory is full!");
    }

    //Removes an item from a slot
    public void RemoveItem(int index)
    {
        if (items[index] != null)
        {
            items.RemoveAt(index);
            InventoryChanged?.Invoke();
        }
    }

    private void RemoveItem(int index, int amount)
    {
        if (items[index] != null)
        {
            int targetAmountLeft = items[index].Amount - amount;

            if (targetAmountLeft == 0)
            {
                items.RemoveAt(index);
            }

            else
            {
                items[index].Amount -= amount;
            }

            InventoryChanged?.Invoke();

        }
    }

    //Swaps items to another slot
    public void SwapItemSlot(int index, int swapIndex)
    {
        InventorySlot slot = items[index];
        items[index] = items[swapIndex];
        items[swapIndex] = slot;
        InventoryChanged?.Invoke();
    }

    public void SplitSlot(int index)
    {
        if (!IsFull())
        {
            if (CanSplitItemSlot(index, out InventorySlot slot))
            {
                int amountToTransfer = CalculateStackDivision(slot.Amount);
                slot.Amount = amountToTransfer;

                // Creates a new slot with the split amount and adds it to inventory
                InventorySlot newSlot = new InventorySlot(slot.Item, amountToTransfer);
                items.Add(newSlot);

                InventoryChanged?.Invoke();
                return;
            }

            Debug.Log("Slot is not stackable or doesn't have enough items to split the stack");
            return;
        }

        Debug.Log("Inventory is Full");
    }

    //Check if the item is stackable
    //Returns true if the item is stackable
    //And also returns the slot of the item
    private bool CanSplitItemSlot(int index, out InventorySlot slot)
    {
        Item item = items[index].Item;
        slot = items[index];
        return item != null && item.IsStackable && slot.Amount > 1;
    }

    //Gets an item
    public Item GetItem(int index) => items[index].Item;

    public InventorySlot InventorySlot(int index) => items[index];

    //Calculates the division of the stack
    private int CalculateStackDivision(int amount) => Mathf.CeilToInt(amount / 2f);

    //Checks if a slot exists with same item
    private InventorySlot FindSlotByItem(Item item)
    {
        for (int i = 0; i < items.Count; i++)
        {
            if (items[i] != null && items[i].Item != null)
            {
                if (items[i].Item.Equals(item) && !items[i].IsSlotFull())
                {
                    return items[i];
                }

                Debug.Log("The item is not the same or the slot is FULL");
            }
        }
        return null;
    }



    public void DropItem(int index, int amount)
    {
        Item item = GetItem(index);
        GameObject go = GameManager.Instance.itemStack;

        if (go != null)
        {
            Vector3 targePos = new Vector3(gameObject.transform.position.x, gameObject.transform.position.y, 0);
            GameObject obj = UnityEngine.Object.Instantiate(go, targePos, Quaternion.identity);
            ItemStack stack = obj.GetComponent<ItemStack>();
            stack.ItemStackInit(item, amount);
            RemoveItem(index, amount);
            return;
        }

        else
        {
            Debug.LogError($"Item stack is Null");
        }
    }

    public InventorySlot GetSlot(int index) => items[index];

    //Checks if the inventory is full
    public bool IsFull() => items.Count >= items.Capacity;
}

[Serializable]
public class InventorySlot
{
    //Variables
    [SerializeField] private Item item;
    [SerializeField] private int amount;
    [SerializeField] private int maxAmount;

    //Properties
    public Item Item => item;
    public int MaxAmount => maxAmount;
    public int Amount
    {
        get => amount;
        set => amount = value;
    }

    //Constructor
    public InventorySlot(Item item = null, int amount = 0)
    {
        this.item = item;
        this.amount = amount;
        maxAmount = item.StackAmount;
    }

    //Checks id the slot is full
    public bool IsSlotFull() => amount == maxAmount;

    public bool IsEmpty() => item == null;
}