Encounter / Assets / Scripts / InventoryManagement / Inventory.cs
Inventory.cs
Raw
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices;
using UnityEditor.Playables;
using UnityEngine;
using static EntityStats;
using static UnityEngine.EventSystems.EventTrigger;

public class Inventory
{
    public Dictionary<Item, int> Items { get; private set; }
    public Dictionary<Consumable, int> Consumables { get; private set; }
    public Dictionary<Relic, int> Relics { get; private set; }
    public Dictionary<Weapon, int> Weapons { get; private set; }
    public Dictionary<Apparel, int> Apparel { get; private set; }
    public List<Ability> Abilities { get; private set; }
    public List<Spell> Spells { get; set; }
    public List<PartyMember> PartyMembers { get; private set; }
    public List<PartyMember> CurrentPartyMembers { get; set; }
    public EntityStats EntityStatLink { get; private set; }
    public Entity AttachedEntity { get; private set; }

    public Dictionary<int, bool> Flaglist = new Dictionary<int, bool>();

    private const short PartyMemberCount = 3;
    private const int StartingGold = 250;
    private const int StartingInvenLimit = 20;

    private Weapon fistWeapon;

    private Weapon activeWeapon;
    private Weapon secondActiveWeapon;
    private WeaponSO.Type activeWeaponType;
    private Dictionary<ApparelSO.Location, Apparel> activeApparel;
    
    public List<Spell> limitedSpells;
    public List<Ability> limitedAbilities;
    private Relic activeRelic;

    private int invenCountLimit;
    private int currentInvenCount;

    private List<Modifier> modifiersToAddToPlayer = new List<Modifier>();
    private int goldCount;

    private Dictionary<WeaponSO.Type, bool> HoldTwoHandedInOffHand = new Dictionary<WeaponSO.Type, bool>()
    {
        { WeaponSO.Type.Blunt, false },
        { WeaponSO.Type.Sharp, false },
        { WeaponSO.Type.Ranged, false },
        { WeaponSO.Type.Magic, false },
        { WeaponSO.Type.Extended, false },
        { WeaponSO.Type.Firearm, false },
    };
    /// <summary>
    /// Signals a trigger in the inventories dictionary to allow holding a two handed type weapon in the off handed slot
    /// </summary>
    /// <param name="weaponType"></param>
    public void SignalOffHandedChange(WeaponSO.Type weaponType)
    {
        HoldTwoHandedInOffHand[weaponType] = !HoldTwoHandedInOffHand[weaponType];

        SwitchWeaponValues(weaponType);
    }
    private void SwitchWeaponValues(WeaponSO.Type weaponType)
    {
        switch (weaponType)
        {
            case WeaponSO.Type.Sharp:
                foreach (KeyValuePair<Weapon, int> weapon in this.Weapons)
                {
                    if (weapon.Key.WeaponIsTwoHanded && weapon.Key.WeaponType is WeaponSO.Type.Sharp)
                        weapon.Key.ModifyTwoHanded(false);
                }
                break;
            case WeaponSO.Type.Blunt:
                foreach (KeyValuePair<Weapon, int> weapon in this.Weapons)
                {
                    if (weapon.Key.WeaponIsTwoHanded && weapon.Key.WeaponType is WeaponSO.Type.Blunt)
                        weapon.Key.ModifyTwoHanded(false);
                }
                break;
            case WeaponSO.Type.Ranged:
                foreach (KeyValuePair<Weapon, int> weapon in this.Weapons)
                {
                    if (weapon.Key.WeaponIsTwoHanded && weapon.Key.WeaponType is WeaponSO.Type.Ranged)
                        weapon.Key.ModifyTwoHanded(false);
                }
                break;
            case WeaponSO.Type.Magic:
                foreach (KeyValuePair<Weapon, int> weapon in this.Weapons)
                {
                    if (weapon.Key.WeaponIsTwoHanded && weapon.Key.WeaponType is WeaponSO.Type.Magic)
                        weapon.Key.ModifyTwoHanded(false);
                }
                break;
            case WeaponSO.Type.Firearm:
                foreach (KeyValuePair<Weapon, int> weapon in this.Weapons)
                {
                    if (weapon.Key.WeaponIsTwoHanded && weapon.Key.WeaponType is WeaponSO.Type.Firearm)
                        weapon.Key.ModifyTwoHanded(false);
                }
                break;
            case WeaponSO.Type.Extended:
                foreach (KeyValuePair<Weapon, int> weapon in this.Weapons)
                {
                    if (weapon.Key.WeaponIsTwoHanded && weapon.Key.WeaponType is WeaponSO.Type.Extended)
                        weapon.Key.ModifyTwoHanded(false);
                }
                break;
        }
    }
    public Dictionary<WeaponSO.Type, bool> GetTwoHandedInOffHandData()
        => HoldTwoHandedInOffHand;
    public void InjectAttachedPlayer(Player player)
    {
        this.AttachedEntity = player;
        this.EntityStatLink = player.GatherStats();
    }
    /// <summary>
    /// Retrieves the gold count from the player's inventory
    /// </summary>
    /// <returns></returns>
    public int GetGold() 
        => goldCount;
    /// <summary>
    /// Adds an amount of gold to the player's inventory
    /// </summary>
    /// <param name="gold">The amount of gold to add to the player's current stash</param>
    public void AddGold(int gold) 
        => goldCount += gold;
    /// <summary>
    /// Attempts to remove the necessary count of gold from the player's inventory
    /// </summary>
    /// <param name="gold">The gold to remove from the player's current value</param>
    /// <exception cref="InvalidOperationException">Thrown if the player's gold dips below 0</exception>
    public void RemoveGold(int gold)
      => goldCount = goldCount - gold >= 0 ? goldCount - gold : throw new InvalidOperationException();
    // For player creation draft and enemies
    public Inventory()
    {
        this.Items                   = new();
        this.Consumables             = new();
        this.Weapons                 = new();
        this.Apparel                 = new();
        this.Spells                  = new();
        this.Relics                  = new();
        this.Abilities               = new();
        this.limitedAbilities        = new();
        this.limitedSpells           = new();

        this.invenCountLimit       = StartingInvenLimit;
        this.goldCount             = StartingGold;

        // Initialize a naked character
        this.activeApparel = new Dictionary<ApparelSO.Location, Apparel>()
        {
            { ApparelSO.Location.Head, null },
            { ApparelSO.Location.Chest, null },
            { ApparelSO.Location.Leggings, null },
            { ApparelSO.Location.Relic, null },
            { ApparelSO.Location.Neck, null },
            { ApparelSO.Location.RingLocOne, null },
            { ApparelSO.Location.RingLocTwo, null }
        };

        this.fistWeapon = Globals.TurnWeaponFromObject(Resources.Load<WeaponSO>("Weapons/53_Fist"));
    }
    public Inventory(Enemy enemy)
    {
        this.Items                  = new();
        this.Consumables            = new();
        this.Weapons                = new();
        this.Apparel                = new();
        this.Relics                 = new();

        this.Spells                 = new();
        foreach (SpellSO spell in enemy.GetEnemySpells())
            this.Spells.Add(Globals.TurnSpellFromObject(spell));

        this.Abilities              = new();
        foreach (AbilitySO ability in enemy.GetEnemyAbilities())
            this.Abilities.Add(Globals.TurnAbilityFromObject(ability));

        this.limitedAbilities       = new();
        this.limitedSpells          = new();

        this.activeWeaponType = enemy.GetDamageType();
        this.EntityStatLink = enemy.GatherStats();
        this.AttachedEntity = enemy;

        DecipherResistsAndWeaknesses(enemy);

        this.invenCountLimit    = StartingInvenLimit;
        this.goldCount          = StartingGold;

        // Initialize a naked character
        this.activeApparel = new Dictionary<ApparelSO.Location, Apparel>()
        {
            { ApparelSO.Location.Head, null },
            { ApparelSO.Location.Chest, null },
            { ApparelSO.Location.Leggings, null },
            { ApparelSO.Location.Relic, null },
            { ApparelSO.Location.Neck, null },
            { ApparelSO.Location.RingLocOne, null },
            { ApparelSO.Location.RingLocTwo, null }
        };

        foreach (KeyValuePair<Apparel, int> pair in this.Apparel)
        {
            if (this.activeApparel[pair.Key.ApparelLocation] == null)
                activeApparel[pair.Key.ApparelLocation] = pair.Key;
        }

        this.fistWeapon = Globals.TurnWeaponFromObject(Resources.Load<WeaponSO>("Weapons/53_Fist"));
    }
    // For ally inventory creations
    public Inventory(Ally ally)
    {
        this.EntityStatLink = ally.GatherStats();
        this.AttachedEntity = ally;

        this.Items = new Dictionary<Item, int>();
        ally.GetItems().ForEach(i =>
        {
            if (!Items.ContainsKey(i))
                this.Items.Add(i, 1);
            else
                this.Items[i]++;
        });

        this.Consumables = new Dictionary<Consumable, int>();
        ally.GetConsumables().ForEach(i =>
        {
            if (!Consumables.ContainsKey(i))
                this.Consumables.Add(i, 1);
            else
                this.Consumables[i]++;
        });

        this.Relics = new Dictionary<Relic, int>();
        ally.GetRelics().ForEach(i =>
        {
            if (!Relics.ContainsKey(i))
                this.Relics.Add(i, 1);
            else
                this.Relics[i]++;
        });

        this.Weapons = new Dictionary<Weapon, int>();
        ally.GetWeapons().ForEach(w =>
        {
            if (!Weapons.ContainsKey(w))
                this.Weapons.Add(w, 1);
            else
                this.Weapons[w]++;
        });

        this.Apparel = new Dictionary<Apparel, int>();
        ally.GetApparel().ForEach(apparel =>
        {
            if (!Apparel.ContainsKey(apparel))
                this.Apparel.Add(apparel, 1);
            else
                this.Apparel[apparel]++;
        });

        this.Abilities = new List<Ability>(ally.GetAbilities());
        this.Spells = new List<Spell>(ally.GetSpells());
        this.limitedAbilities = new();
        this.limitedSpells = new();

        DecipherResistsAndWeaknesses(ally);

        this.invenCountLimit = StartingInvenLimit;
        this.currentInvenCount = 0;

        GameManager.Instance.GetPlayerObject().GetComponent<Player>().GetInventory().AddGold(UnityEngine.Random.Range(0, StartingGold + 1));

        SetPrimaryActiveWeapon(this.Weapons.FirstOrDefault().Key);

        // Initialize a naked character
        this.activeApparel = new Dictionary<ApparelSO.Location, Apparel>()
        {
            { ApparelSO.Location.Head, null },
            { ApparelSO.Location.Chest, null },
            { ApparelSO.Location.Leggings, null },
            { ApparelSO.Location.Relic, null },
            { ApparelSO.Location.Neck, null },
            { ApparelSO.Location.RingLocOne, null },
            { ApparelSO.Location.RingLocTwo, null }
        };

        foreach (KeyValuePair<Apparel, int> pair in this.Apparel)
        {
            if (this.activeApparel[pair.Key.ApparelLocation] == null)
                activeApparel[pair.Key.ApparelLocation] = pair.Key;
        }

        this.fistWeapon = Globals.TurnWeaponFromObject(Resources.Load<WeaponSO>("Weapons/53_Fist"));
    }
    // For player creation
    public Inventory(List<Weapon> weapons, List<Apparel> apparel, List<Ability> abilities, List<Spell> spells)
    {
        this.Items                  = new Dictionary<Item, int>();
        this.Consumables            = new Dictionary<Consumable, int>();
        this.Relics                 = new Dictionary<Relic, int>();
        this.Weapons                = new Dictionary<Weapon, int>();
        this.Apparel                = new Dictionary<Apparel, int>();
        this.Abilities              = new List<Ability>(abilities);
        this.Spells                 = new List<Spell>(spells);
        this.limitedAbilities       = new();
        this.limitedSpells          = new();

        weapons.ForEach(weap =>
        {
            if (!this.Weapons.ContainsKey(weap))
                this.Weapons.Add(weap, 1);
            else
                this.Weapons[weap]++;
        });
        apparel.ForEach(app =>
        {
            if (!this.Apparel.ContainsKey(app))
                this.Apparel.Add(app, 1);
            else
                this.Apparel[app]++;
        });

        // Initialize a naked character
        this.activeApparel = new Dictionary<ApparelSO.Location, Apparel>()
        {
            { ApparelSO.Location.Head, null },
            { ApparelSO.Location.Chest, null },
            { ApparelSO.Location.Leggings, null },
            { ApparelSO.Location.Relic, null },
            { ApparelSO.Location.Neck, null },
            { ApparelSO.Location.RingLocOne, null },
            { ApparelSO.Location.RingLocTwo, null }
        };

        foreach (KeyValuePair<Apparel, int> pair in this.Apparel)
        {
            if (this.activeApparel[pair.Key.ApparelLocation] == null)
                activeApparel[pair.Key.ApparelLocation] = pair.Key;
        }

        this.activeWeapon = this.Weapons.FirstOrDefault().Key;
        if (this.activeWeapon.WeaponIsTwoHanded)
            this.secondActiveWeapon = this.activeWeapon;

        this.invenCountLimit      = StartingInvenLimit;
        this.currentInvenCount    = this.Items.Count + this.Weapons.Count + this.Apparel.Count;

        this.goldCount = StartingGold;

        // If money cheat is turned on
        if (Globals.InfiniteMoneyCheat)
            this.goldCount += 999999;

        this.PartyMembers           = new List<PartyMember>();
        this.CurrentPartyMembers    = new List<PartyMember>();

        Add(partyMember: new PartyMember("Phyll"));
        this.fistWeapon = Globals.TurnWeaponFromObject(Resources.Load<WeaponSO>("Weapons/53_Fist"));
    }
    /// <summary>
    /// Indicator if there is room within the inventory
    /// </summary>
    /// <returns>True if there is room, false if there is not room</returns>
    public bool HaveRoom() 
        => currentInvenCount < invenCountLimit;
    /// <summary>
    /// Increases the inventory room limit by the parameter passed
    /// </summary>
    /// <param name="increaseAmount">Increase max inventory limit value</param>
    public void IncreaseRoom(int increaseAmount) 
        => invenCountLimit += increaseAmount;
    /// <summary>
    /// Adds a general item to the player's inventory
    /// </summary>
    /// <param name="item">The Item to potentially be added</param>
    /// <param name="amount">The amount of the item to add</param>
    public void Add(Item item, int amount)
    {
        // If the inventory is full simply return
        if (currentInvenCount >= invenCountLimit)
            return;

        // Adds the item and increments the inventory counter by one
        if (!Items.ContainsKey(item))
        {
            this.Items.Add(item, amount);
            this.currentInvenCount++;
        }
        else
            this.Items[item] += amount;
        
    }
    /// <summary>
    /// Adds the consumable to the inventory stash
    /// </summary>
    /// <param name="consumable">The consumable to add to the inventory</param>
    /// <param name="amount">The amount of the consumable to add to the inventory</param>
    public void Add(Consumable consumable, int amount)
    {
        // If the inventory is full simply return
        if (currentInvenCount >= invenCountLimit)
            return;

        // Adds the consumable and increments the inventory counter by one
        if (!Consumables.ContainsKey(consumable))
        {
            this.Consumables.Add(consumable, amount);
            this.currentInvenCount++;
        }
        else
            this.Consumables[consumable] += amount;
    }
    /// <summary>
    /// Adds the weapon into the inventory weapon list
    /// </summary>
    /// <param name="weapon">Weapon to be added</param>
    /// <param name="amount">The amount of the weapon to add</param>
    public void Add(Weapon weapon, int amount)
    {
        // If the inventory is already full, simply return
        if (currentInvenCount >= invenCountLimit)
            return;

        // Adds the weapon and increments the inventory counter by one
        if (!Weapons.ContainsKey(weapon))
        {
            if (weapon.WeaponIsTwoHanded && HoldTwoHandedInOffHand[weapon.WeaponType])
                weapon.ModifyTwoHanded(false);

            this.Weapons.Add(weapon, amount);
            this.currentInvenCount++;

            if (weapon.ModifiersToAdd != null)
            {
                for (int i = 0;i < weapon.ModifiersToAdd.Count; i++)
                {
                    if (AttachedEntity != null)
                        AttachedEntity.AddModToList(weapon.ModifiersToAdd[i]);
                    else
                        modifiersToAddToPlayer.Add(weapon.ModifiersToAdd[i]);
                }
            }
        }
        else
            this.Weapons[weapon] += amount;
    }
    /// <summary>
    /// Adds Apparel into the inventory's Apparel list
    /// </summary>
    /// <param name="apparel">Apparel to be added</param>
    /// <param name="amount">The amount of the apparel to be added</param>
    public void Add(Apparel apparel, int amount)
    {
        // If the inventory is full then simply return
        if (currentInvenCount >= invenCountLimit)
            return;

        // Adds the Apparel and increments the inventory counter by one
        if (!Apparel.ContainsKey(apparel))
        {
            this.Apparel.Add(apparel, amount);
            this.currentInvenCount++;
        }
        else
            this.Apparel[apparel] += amount;
    }
    /// <summary>
    /// Adds an ability into the inventory ability list
    /// </summary>
    /// <param name="ability">The ability to add</param>
    public void Add(Ability ability)
    {
        if (this.Abilities.Contains(ability))
            return;

        this.Abilities.Add(ability);
        if (limitedAbilities.Contains(ability))
            limitedAbilities.Remove(ability);
    }
    /// <summary>
    /// Adds a spell to the inventory spell list
    /// </summary>
    /// <param name="spell">The spell to add</param>
    public void Add(Spell spell)
    {
        if (this.Spells.Contains(spell))
            return;

        this.Spells.Add(spell);
        if (limitedSpells.Contains(spell))
            limitedSpells.Remove(spell);
    }
    /// <summary>
    /// Adds a party member to the player's inventory
    /// </summary>
    /// <param name="partyMember">The member to add</param>
    public void Add(PartyMember partyMember)
    {
        this.PartyMembers.Add(partyMember);
        if (this.PartyMembers.Count < PartyMemberCount)
            this.CurrentPartyMembers.Add(partyMember);
    }
    public void Add(Relic relic, int amount)
    {
        if (currentInvenCount >= invenCountLimit)
            return;

        if (this.Relics.ContainsKey(relic))
        {
            this.Relics.Add(relic, amount);
            this.currentInvenCount++;
        }
        else
            this.Relics[relic] = amount;
    }
    /// <summary>
    /// Removes the paramerterized item from the inventory, also decrements inventory counter
    /// </summary>
    /// <param name="item">Item to remove</param>
    /// <param name="amount">The amount to remove from the inventory</param>
    /// <exception cref="ArgumentOutOfRangeException">Thrown if the amount to remove is greater than the amount in the inventory</exception>
    public void Remove(Item item, int amount)
    {
        if (amount > this.Items[item])
            throw new ArgumentOutOfRangeException();

        if (amount < this.Items[item])
            this.Items[item] -= amount;
        else
        {
            this.Items.Remove(item);
            this.currentInvenCount--;
        }
    }
    /// <summary>
    /// Removes the designated consumable from the inventory
    /// </summary>
    /// <param name="consumable">The consumable to remove from the inventory</param>
    /// <param name="amount">The amount of the consumable to remove from the inventory</param>
    /// <exception cref="ArgumentOutOfRangeException">Thrown if the amount to remove is greater than the amount in the inventory</exception>
    public void Remove(Consumable consumable, int amount)
    {
        if (amount > this.Consumables[consumable])
            throw new ArgumentOutOfRangeException();

        if (amount < this.Consumables[consumable])
            this.Consumables[consumable] -= amount;
        else
        {
            this.Consumables.Remove(consumable);
            this.currentInvenCount--;
        }
    }
    /// <summary>
    /// Removes the paramerterized weapon from the inventory, also decrements inventory counter
    /// </summary>
    /// <param name="weapon">Weapon to remove</param>
    /// <param name="amount">The amount to remove from the inventory</param>
    /// <exception cref="ArgumentOutOfRangeException">Thrown if the amount to remove is greater than the amount in the inventory</exception>
    public void Remove(Weapon weapon, int amount)
    {
        if (amount > this.Weapons[weapon])
            throw new ArgumentOutOfRangeException();

        if (amount < this.Weapons[weapon])
            this.Weapons[weapon] -= amount;
        else
        {
            this.Weapons.Remove(weapon);
            this.currentInvenCount--;
        }
    }
    /// <summary>
    /// Removes the paramerterized apparel from the inventory, also decrements inventory counter
    /// </summary>
    /// <param name="apparel">Apparel to remove</param>
    /// <param name="amount">The amount to remove from the inventory</param>
    /// <exception cref="ArgumentOutOfRangeException">Thrown if the amount to remove is greater than the amount in the inventory</exception>
    public void Remove(Apparel apparel, int amount)
    {
        if (amount > this.Apparel[apparel])
            throw new ArgumentOutOfRangeException();

        if (amount < this.Apparel[apparel])
            this.Apparel[apparel] -= amount;
        else
        {
            this.Apparel.Remove(apparel);
            this.currentInvenCount--;
        }
    }
    /// <summary>
    /// Removes the paramerterized ability from the inventory
    /// </summary>
    /// <param name="ability">Ability to remove</param>
    public void Remove(Ability ability)
    {
        this.Abilities.Remove(ability);
    }
    /// <summary>
    /// Removes the paramerterized spell from the inventory
    /// </summary>
    /// <param name="spell">Spell to remove</param>
    public void Remove(Spell spell)
    {
        this.Spells.Remove(spell);
    }
    /// <summary>
    /// Removes a party member from the player's inventory
    /// </summary>
    /// <param name="partyMember">The party member to remove</param>
    public void Remove(PartyMember partyMember)
    {
        this.PartyMembers.Remove(partyMember);
    }
    public void Remove(Relic relic, int amount)
    {
        if (amount > this.Relics[relic])
            throw new ArgumentOutOfRangeException();

        if (amount < this.Relics[relic])
            this.Relics[relic] -= amount;
        else
        {
            this.Relics.Remove(relic);
            this.currentInvenCount--;
        }
    }
    public Dictionary<Item, int> GetAllItems()
    {
        Dictionary<Item, int> itemList = new Dictionary<Item, int>();

        foreach (var item in this.Items)
            itemList.Add(item.Key, item.Value);
        foreach (var con in this.Consumables)
            itemList.Add(con.Key, con.Value);
        foreach (var weapon in this.Weapons)
            itemList.Add(weapon.Key, weapon.Value);
        foreach (var apparel in this.Apparel)
            itemList.Add(apparel.Key, apparel.Value);
        foreach (var relic in this.Relics)
            itemList.Add(relic.Key, relic.Value);

        return itemList;
    }
    /// <summary>
    /// Gets the currently active weapon
    /// </summary>
    /// <returns>Current active weapon</returns>
    public Weapon GetPrimaryActiveWeapon()
        => activeWeapon;
    /// <summary>
    /// Sets the primary active weapon to the necessary variable
    /// Also checks if the weapon is two handed and automatically sets it 
    /// </summary>
    /// <param name="weapon"></param>
    public bool SetPrimaryActiveWeapon(Weapon weapon)
    {
        // Null Check
        if (weapon == null)
        {
            if (activeWeapon is not null)
            {
                if (activeWeapon.WeaponIsTwoHanded)
                    secondActiveWeapon = null;

                if (secondActiveWeapon != activeWeapon)
                {
                    RemoveLimitedAbilities(activeWeapon);
                    RemoveLimitedSpells(activeWeapon);
                }
            }

            activeWeapon = null;

            if (activeWeapon == null && secondActiveWeapon == null)
                activeWeapon = fistWeapon;

            return true;
        }

        // General Two Handed check
        if (weapon.WeaponIsTwoHanded)
        {
            RemoveLimitedSpells(activeWeapon);
            RemoveLimitedAbilities(activeWeapon);

            try
            {
                if (!secondActiveWeapon.WeaponIsTwoHanded)
                {
                    RemoveLimitedSpells(secondActiveWeapon);
                    RemoveLimitedAbilities(secondActiveWeapon);
                }
            }
            catch { }

            secondActiveWeapon = weapon;
            activeWeaponType = weapon.WeaponType;
            activeWeapon = weapon;

            AddLimitedSpells(weapon);
            AddLimitedAbilities(weapon);

            return false;
        }

        // Switch out limited attributes
        if (weapon != activeWeapon)
        {
            RemoveLimitedSpells(activeWeapon);
            RemoveLimitedAbilities(activeWeapon);
            AddLimitedSpells(weapon);
            AddLimitedAbilities(weapon);
        }

        // Set the new weapon
        activeWeapon = weapon;
        activeWeaponType = weapon.WeaponType;
        return true;
    }
    private void AddLimitedSpells(Item item)
    {
        if (item is Weapon weapon)
        {
            try
            {
                if (weapon.SpellsToAdd.Count > 0)
                {
                    foreach (Spell spell in weapon.SpellsToAdd)
                    {
                        if (!limitedSpells.Contains(spell) && !Spells.Contains(spell))
                            limitedSpells.Add(spell);
                    }
                }
            }
            catch { }
        }
        else if (item is Apparel apparel)
        {
            try
            {
                if (apparel.SpellsToAdd.Count > 0)
                {
                    foreach (Spell spell in apparel.SpellsToAdd)
                    {
                        if (!limitedSpells.Contains(spell) && !Spells.Contains(spell))
                            limitedSpells.Add(spell);
                    }
                }
            }
            catch { }
        }
    }
    private void RemoveLimitedSpells(Item item)
    {
        if (item is Weapon weapon)
        {
            try
            {
                if (weapon.SpellsToAdd.Count > 0)
                {
                    foreach (Spell spell in weapon.SpellsToAdd)
                    {
                        if (limitedSpells.Contains(spell))
                            limitedSpells.Remove(spell);
                    }
                }
            }
            catch { }
        }
        else if (item is Apparel apparel)
        {
            try
            {
                if (apparel.SpellsToAdd.Count > 0)
                {
                    foreach (Spell spell in apparel.SpellsToAdd)
                    {
                        if (limitedSpells.Contains(spell))
                            limitedSpells.Remove(spell);
                    }
                }
            }
            catch { }
        }
    }
    private void AddLimitedAbilities(Item item)
    {
        if (item is Weapon weapon)
        {
            try
            {
                if (weapon.AbilitiesToAdd.Count > 0)
                {
                    foreach (Ability ability in weapon.AbilitiesToAdd)
                    {
                        if (!limitedAbilities.Contains(ability) || !Abilities.Contains(ability))
                            limitedAbilities.Add(ability);
                    }
                }
            }
            catch { }
        }
        else if (item is Apparel apparel)
        {
            try
            {
                if (apparel.AbilitiesToAdd.Count > 0)
                {
                    foreach (Ability ability in apparel.AbilitiesToAdd)
                    {
                        if (!limitedAbilities.Contains(ability) || !Abilities.Contains(ability))
                            limitedAbilities.Add(ability);
                    }
                }
            }
            catch { }
        }
    }
    private void RemoveLimitedAbilities(Item item)
    {
        if (item is Weapon weapon)
        {
            try
            {
                foreach (Ability ability in weapon.AbilitiesToAdd)
                {
                    if (limitedAbilities.Contains(ability))
                        limitedAbilities.Remove(ability);
                }
            }
            catch { }
        }
        else if (item is Apparel apparel)
        {
            try
            {
                foreach (Ability ability in apparel.AbilitiesToAdd)
                {
                    if (limitedAbilities.Contains(ability))
                        limitedAbilities.Remove(ability);
                }
            }
            catch { }
        }
    }
    /// <summary>
    /// Retrieves the secondary active weapon
    /// </summary>
    /// <returns>The weapon marked as the secondary active weapon</returns>
    public Weapon GetSecondaryActiveWeapon()
        => secondActiveWeapon;
    /// <summary>
    /// Sets the secondary aspect of the weapons in the player's hands after checking
    /// specific variables and qualifications
    /// </summary>
    /// <param name="weapon">The weapon to set to the secondary aspect</param>
    public void SetSecondaryActiveWeapon(Weapon weapon)
    {
        // Resetting spot back to null
        if (weapon is null)
        {
            if (secondActiveWeapon != null)
            {
                if (!secondActiveWeapon.WeaponIsTwoHanded && secondActiveWeapon != activeWeapon)
                {
                    RemoveLimitedSpells(secondActiveWeapon);
                    RemoveLimitedAbilities(secondActiveWeapon);
                }
            }
            
            secondActiveWeapon = null;

            if (activeWeapon == null && secondActiveWeapon == null)
                activeWeapon = fistWeapon;

            return;
        }

        // Check if new weapon being inserted into specific slot is a two handed
        if (weapon.WeaponIsTwoHanded)
        {   
            SetPrimaryActiveWeapon(weapon);
            return;
        }

        // Null Check
        if (secondActiveWeapon != null)
        {
            RemoveLimitedSpells(secondActiveWeapon);
            RemoveLimitedAbilities(secondActiveWeapon);
        }
        
        secondActiveWeapon = weapon;
        if (secondActiveWeapon != activeWeapon)
        {
            AddLimitedSpells(secondActiveWeapon);
            AddLimitedAbilities(secondActiveWeapon);
        }
    }
    /// <summary>
    /// Retrieves all of the apparel that is marked as active in the inventory
    /// </summary>
    /// <returns>The map of the active apparel currently on the player</returns>
    public Dictionary<ApparelSO.Location, Apparel> GetActiveApparelLocations()
        => activeApparel;
    /// <summary>
    /// Sets the ring based on logic for the already active rings
    /// </summary>
    /// <param name="apparel">The ring to input into the location</param>
    /// <param name="location">Which ring location the user wants</param>
    /// <returns></returns>
    public void SetRing(Apparel apparel, ApparelSO.Location location = ApparelSO.Location.RingLocOne)
    {
        Item check1 = activeApparel[ApparelSO.Location.RingLocOne];
        Item check2 = activeApparel[ApparelSO.Location.RingLocTwo];

        if (check1 == null && location is ApparelSO.Location.RingLocOne)
            SetActiveApparelAtLocation(apparel, location);
        else if (check1 != null && check2 == null && location is ApparelSO.Location.RingLocOne)
            SetRing(apparel, location + 1);
        else if (check2 == null && location is ApparelSO.Location.RingLocTwo)
            SetActiveApparelAtLocation(apparel, location);
        else if (check1 == null && check2 != null && location is ApparelSO.Location.RingLocTwo)
            SetRing(apparel, location - 1);
        else if (check1 != null && check2 != null)
            SetActiveApparelAtLocation(apparel, location);
    }
    public void RefreshApparel(bool enteringGame = false)
    {
        bool ringOneAreaChecked = false;
        if (!enteringGame)
        {
            Apparel[] refreshApparel = activeApparel.Values.ToArray();
            for (int i = 0; i < refreshApparel.Length; i++)
            {
                // Try-Catch used in case the apparel location is not able to be retrieved, simply skips over the iteration
                try
                {
                    ApparelSO.Location areaLocation = refreshApparel[i].ApparelLocation;
                    if (ringOneAreaChecked is true && areaLocation is ApparelSO.Location.RingLocOne)
                        areaLocation = ApparelSO.Location.RingLocTwo;

                    SetActiveApparelAtLocation(null, areaLocation);

                    if (areaLocation is ApparelSO.Location.RingLocOne && ringOneAreaChecked is false)
                        ringOneAreaChecked = true;

                    SetActiveApparelAtLocation(refreshApparel[i], areaLocation, true);
                }
                catch { }
            }
        }

        CalculateCollectiveApparelBonuses();
    }
    public void SetActiveApparelAtLocation(Apparel apparel, ApparelSO.Location location, bool isCollectiveRefresh = false)
    {
        if (apparel == null)
        {
            Apparel appToRemove = activeApparel[location];
            
            if (appToRemove != null)
                RemoveApparelBonus(appToRemove);

            activeApparel[location] = null;
        }
        else if (apparel != null && activeApparel[location] == null)
        {
            if (!isCollectiveRefresh)
                CalculateSingleApparelBonus(apparel);

            activeApparel[location] = apparel;
            AddLimitedSpells(apparel);
            AddLimitedAbilities(apparel);
        }
        else if (activeApparel[location] != null && apparel != null)
        {
            Apparel apparelToRemove = activeApparel[location];
            RemoveApparelBonus(apparelToRemove);
            activeApparel[location] = apparel;
            AddLimitedAbilities(apparel);
            AddLimitedSpells(apparel);
        }
    }
    private void RemoveApparelBonus(Apparel appToRemove)
    {
        try
        {
            if (!appToRemove.RequiredWeather.Contains(ClimateManager.Instance.GetWeather()))
                return;
        }
        catch { }

        foreach (ApparelSO.ApparelEffect effect in appToRemove.ApparelEffects)
        {
            switch (effect)
            {
                case ApparelSO.ApparelEffect.Defense:
                    this.EntityStatLink.RemoveModifierToStat(Stat.Armor, (int)appToRemove.DefenseModifier);
                    break;
                case ApparelSO.ApparelEffect.Resistances:
                    foreach (SpellSO.Element resist in appToRemove.ElementResistances)
                        this.EntityStatLink.RemoveElementalResistance(resist);
                    foreach (WeaponSO.Type resist in appToRemove.TypeResistances)
                        this.EntityStatLink.RemoveTypeResistance(resist);

                    break;
                case ApparelSO.ApparelEffect.HealthRegen:
                    this.EntityStatLink.RemoveModifierToStat(Stat.HPRegen, (int)appToRemove.HealthRegenPercentage);
                    break;
                case ApparelSO.ApparelEffect.ManaRegen:
                    this.EntityStatLink.RemoveModifierToStat(Stat.MPRegen, (int)appToRemove.ManaRegenPercentage);
                    break;
                case ApparelSO.ApparelEffect.DamageModifier:
                    Debug.Log($"Damage Modifier was removed : {(int)appToRemove.DamageModifier}");
                    this.EntityStatLink.RemoveModifierToStat(Stat.Damage, (int)appToRemove.DamageModifier);
                    break;
                case ApparelSO.ApparelEffect.ToHitModifier:
                    this.EntityStatLink.RemoveModifierToStat(Stat.ToHit, (int)appToRemove.ToHitModifier);
                    break;
                case ApparelSO.ApparelEffect.GiveSpell:
                    foreach (Spell spell in appToRemove.AvailableSpells)
                    {
                        try
                        {
                            // This is a try since adding a spell permanently that is within limited spells will cause the limited spells part to be removed already
                            limitedSpells.Remove(spell);
                        }
                        catch { continue; }
                    }
                    break;
                case ApparelSO.ApparelEffect.GiveAbility:
                    foreach (Ability ability in appToRemove.AvailableAbilities)
                    {
                        try
                        {
                            // This is a try since adding a ability permanently that is within limited abilities will cause the limited abilities part to be removed already
                            limitedAbilities.Remove(ability);
                        }
                        catch { continue; }
                    }
                    break;
                case ApparelSO.ApparelEffect.Stats:
                    foreach (Vector2Int stat in appToRemove.StatModifiers)
                    {
                        switch (stat.x)
                        {
                            case 0: // STR
                                this.EntityStatLink.RemoveModifierToStat(Stat.Strength, stat.y);
                                break;
                            case 1: // INT
                                this.EntityStatLink.RemoveModifierToStat(Stat.Intelligence, stat.y);
                                break;
                            case 2: // CON
                                this.EntityStatLink.RemoveModifierToStat(Stat.Constitution, stat.y);
                                break;
                            case 3: // DEX
                                this.EntityStatLink.RemoveModifierToStat(Stat.Dexterity, stat.y);
                                break;
                            case 4: // CHA
                                this.EntityStatLink.RemoveModifierToStat(Stat.Charisma, stat.y);
                                break;
                            case 5: // WIS
                                this.EntityStatLink.RemoveModifierToStat(Stat.Wisdom, stat.y);
                                break;
                            case 6: // LCK
                                this.EntityStatLink.RemoveModifierToStat(Stat.Luck, stat.y);
                                break;
                        }
                    }
                    break;
                case ApparelSO.ApparelEffect.MoreMana:
                    this.AttachedEntity.IncreaseMaxMana((int)appToRemove.ExtraMana * -1);
                    this.AttachedEntity.DecreaseMana((int)appToRemove.ExtraMana);
                    this.AttachedEntity.StatusChanged();
                    break;
                case ApparelSO.ApparelEffect.MoreHealth:
                    this.AttachedEntity.IncreaseMaxHealth((int)appToRemove.ExtraHealth * -1);
                    this.AttachedEntity.DecreaseHealth((int)appToRemove.ExtraHealth, true);
                    this.AttachedEntity.StatusChanged();
                    break;
                case ApparelSO.ApparelEffect.Other:
                    FindFlagValue(appToRemove.FlagValue, false);
                    break;
            }
        } 
    }
    public void CalculateCollectiveApparelBonuses()
    {
        foreach (Apparel app in activeApparel.Values)
            CalculateSingleApparelBonus(app);
    }
    public void CalculateSingleApparelBonus(Apparel apparel)
    {
        // Guard check
        if (apparel is null)
            return;

        try
        {
            if (!apparel.RequiredWeather.Contains(ClimateManager.Instance.GetWeather()))
                return;
        }
        catch { }

        foreach (ApparelSO.ApparelEffect effect in apparel.ApparelEffects)
        {
            switch (effect)
            {
                case ApparelSO.ApparelEffect.Defense:
                    this.EntityStatLink.SetModifierToStat(Stat.Armor, (int)apparel.DefenseModifier);
                    break;
                case ApparelSO.ApparelEffect.Resistances:
                    foreach (SpellSO.Element resist in apparel.ElementResistances)
                        this.EntityStatLink.AddElementalResistance(resist);
                    foreach (WeaponSO.Type resist in apparel.TypeResistances)
                        this.EntityStatLink.AddTypeResistance(resist);

                    break;
                case ApparelSO.ApparelEffect.HealthRegen:
                    this.EntityStatLink.SetModifierToStat(Stat.HPRegen, (int)apparel.HealthRegenPercentage);
                    break;
                case ApparelSO.ApparelEffect.ManaRegen:
                    this.EntityStatLink.SetModifierToStat(Stat.MPRegen, (int)apparel.ManaRegenPercentage);
                    break;
                case ApparelSO.ApparelEffect.DamageModifier:
                    Debug.Log($"Damage Modifier was added : {(int)apparel.DamageModifier}");
                    this.EntityStatLink.SetModifierToStat(Stat.Damage, (int)apparel.DamageModifier);
                    break;
                case ApparelSO.ApparelEffect.ToHitModifier:
                    this.EntityStatLink.SetModifierToStat(Stat.ToHit, (int)apparel.ToHitModifier);
                    break;
                case ApparelSO.ApparelEffect.GiveSpell:
                    limitedSpells ??= new List<Spell>();
                    foreach (Spell spell in apparel.AvailableSpells)
                    {
                        if (!limitedSpells.Contains(spell))
                            limitedSpells.Add(spell);
                    }
                    break;
                case ApparelSO.ApparelEffect.GiveAbility:
                    limitedAbilities ??= new List<Ability>();
                    foreach (Ability ability in apparel.AvailableAbilities)
                    {
                        if (!limitedAbilities.Contains(ability))
                            limitedAbilities.Add(ability);
                    } 
                    break;
                case ApparelSO.ApparelEffect.Stats:
                    foreach (Vector2Int stat in apparel.StatModifiers)
                    {
                        switch (stat.x)
                        {
                            case 0: // STR
                                this.EntityStatLink.SetModifierToStat(Stat.Strength, stat.y);
                                break;
                            case 1: // INT
                                this.EntityStatLink.SetModifierToStat(Stat.Intelligence, stat.y);
                                break;
                            case 2: // CON
                                this.EntityStatLink.SetModifierToStat(Stat.Constitution, stat.y);
                                break;
                            case 3: // DEX
                                this.EntityStatLink.SetModifierToStat(Stat.Dexterity, stat.y);
                                break;
                            case 4: // CHA
                                this.EntityStatLink.SetModifierToStat(Stat.Charisma, stat.y);
                                break;
                            case 5: // WIS
                                this.EntityStatLink.SetModifierToStat(Stat.Wisdom, stat.y);
                                break;
                            case 6: // LCK
                                this.EntityStatLink.SetModifierToStat(Stat.Luck, stat.y);
                                break;
                        }
                    }
                    break;
                case ApparelSO.ApparelEffect.MoreMana:
                    if (this.AttachedEntity is Player player1)
                    {
                        player1.IncreaseMaxMana((int)apparel.ExtraMana);
                        player1.IncreaseMana((int)apparel.ExtraMana);
                        player1.StatusChanged();
                    }
                    else if (this.AttachedEntity is Ally ally1)
                    {
                        ally1.IncreaseMaxMana((int)apparel.ExtraMana);
                        ally1.IncreaseMana((int)apparel.ExtraMana);
                        ally1.StatusChanged();
                    }
                    break;
                case ApparelSO.ApparelEffect.MoreHealth:
                    this.AttachedEntity.IncreaseMaxHealth((int)apparel.ExtraHealth);
                    this.AttachedEntity.IncreaseHealth((int)apparel.ExtraHealth);
                    if (this.AttachedEntity is Player player2)
                        player2.StatusChanged();
                    else if (this.AttachedEntity is Ally ally2)
                        ally2.StatusChanged();
                    break;
                case ApparelSO.ApparelEffect.Other:
                    FindFlagValue(apparel.FlagValue, true);
                    break;
            }
        }
    }
    private void FindFlagValue(int? flagValue, bool stateToSet)
    {
        if (flagValue is null)
            return;

        this.Flaglist ??= new Dictionary<int, bool>();
        switch (flagValue)
        {
            case 0: // Delicate Hat: Increase CHA more when worn with Business Wear
                Apparel hatBusinessCheck = activeApparel[ApparelSO.Location.Chest];

                if (hatBusinessCheck == null)
                    break;

                if (hatBusinessCheck.ItemId is 3)
                {
                    if (stateToSet)
                        this.EntityStatLink.SetModifierToStat(Stat.Charisma, 1);
                    else
                        this.EntityStatLink.RemoveModifierToStat(Stat.Charisma, 1);
                }

                if (Flaglist.ContainsKey(0))
                    Flaglist[0] = stateToSet;
                else
                    Flaglist.Add(0, stateToSet);

                Globals.SetFlag(0, stateToSet);
                break;
            case 1: // Improved Iron Helmet: -3 damage when critically striked
                if (Flaglist.ContainsKey(1))
                    Flaglist[1] = stateToSet;
                else
                    Flaglist.Add(1, stateToSet);
                Globals.SetFlag(1, stateToSet);
                break;
            case 2: // Immutable Star Ring: Gain Mana when attacked
                if (Flaglist.ContainsKey(2))
                    Flaglist[2] = stateToSet;
                else
                    Flaglist.Add(2, stateToSet);
                Globals.SetFlag(2, stateToSet);
                break;
            case 3: // Ring of Rage
                if (Flaglist.ContainsKey(3))
                    Flaglist[3] = stateToSet;
                else
                    Flaglist.Add(3, stateToSet);
                Globals.SetFlag(3, stateToSet);
                break;
            case 4: // Stylish Shoes
                Apparel shoesBusinessCheck = activeApparel[ApparelSO.Location.Chest];

                if (shoesBusinessCheck == null)
                    break;

                if (shoesBusinessCheck.ItemId is 3)
                {
                    if (stateToSet)
                        this.EntityStatLink.SetModifierToStat(Stat.Charisma, 1);
                    else
                        this.EntityStatLink.RemoveModifierToStat(Stat.Charisma, 1);
                }

                if (Flaglist.ContainsKey(4))
                    Flaglist[4] = stateToSet;
                else
                    Flaglist.Add(4, stateToSet);

                Globals.SetFlag(4, stateToSet);
                break;
        }
    }
    public Relic GetActiveRelic()
        => activeRelic;
    public void SetActiveRelic(Relic relic)
    {
        if (activeRelic != null)
            Globals.ToggleRelicFlag(activeRelic.ItemId, false);

        activeRelic = relic;
        
        if (relic != null)
            Globals.ToggleRelicFlag(relic.ItemId, true);
    }
    /// <summary>
    /// Retrieves all of the active party members within the player's settings
    /// </summary>
    /// <returns>The active party member objects</returns>
    public GameObject[] RetrievePartyMemberObjects()
    {
        GameObject[] output = new GameObject[this.CurrentPartyMembers.Count];

        int counter = 0;
        foreach (PartyMember partyMemberObject in CurrentPartyMembers)
            output[counter++] = partyMemberObject.Ally_Object;
        
        return output;
    }
    /// <summary>
    /// Retrieves the count of all of the unique objects in this inventory
    /// </summary>
    /// <returns>Number of unique items</returns>
    public int GetInvenCount() 
        => GetAllItems().Count;
    /// <summary>
    /// Retrieves the maximum amount of unique items that can be present in this inventory
    /// </summary>
    /// <returns>Max amount of unique items</returns>
    public int GetInvenLimit() 
        => invenCountLimit;
    /// <summary>
    /// Upon initialization, the entities resists and weaknesses indicated in their properties in the editor are recorded
    /// </summary>
    /// <param name="entity">The entity that is attached to this inventory</param>
    private void DecipherResistsAndWeaknesses(Entity entity)
    {
        (List<SpellSO.Element> elementWeaknesses, List<SpellSO.Element> elementResists) = entity.RetrieveStartingElementalTypes();
        (List<WeaponSO.Type> weaponWeaknesses, List<WeaponSO.Type> weaponResists) = entity.RetrieveStartingWeaponTypes();

        if (elementWeaknesses != null)
        {
            foreach (SpellSO.Element elementWeakness in elementWeaknesses)
                this.EntityStatLink.AddElementalWeakness(elementWeakness);
        }

        if (elementResists != null)
        {
            foreach (SpellSO.Element elementResist in elementResists)
                this.EntityStatLink.AddElementalResistance(elementResist);
        }

        if (weaponWeaknesses != null)
        {
            foreach (WeaponSO.Type weaponWeakness in weaponWeaknesses)
                this.EntityStatLink.AddTypeWeakness(weaponWeakness);
        }

        if (weaponResists != null)
        {
            foreach (WeaponSO.Type weaponResist in weaponResists)
                this.EntityStatLink.AddTypeResistance(weaponResist);
        }
    }

    public void ReplaceSpell(Spell moddedSpell)
    {
        // Replaces the existing spell with a spell that is modified
        Spells.Remove(moddedSpell);
        Spells.Add(moddedSpell);
    }

    public void ReplaceLimitedSpell(Spell moddedSpell)
    {
        // Replaces the existing spell with a spell that is modified
        limitedSpells.Remove(moddedSpell);
        limitedSpells.Add(moddedSpell);
    }
}