Encounter / Assets / Scripts / BattleLogic / BattleHandler.cs
BattleHandler.cs
Raw
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using UnityEngine;
using UnityEngine.SceneManagement;
using static SpellSO;
using static SpellManagement;
using Unity.VisualScripting;
using UnityEditor.Experimental.GraphView;

/// <summary>
/// Primary logic and handler for battles
/// </summary>
public class BattleHandler : MonoBehaviour
{
    public static BattleHandler Instance;               // Will be apart of the singleton object with the Game Manager

    private EnemyUI uiHandler;                          // Reference to the EnemyUI that is currently active within the scene
    private PositionHandler pHandler;                   // Reference to the position handler within the scene
    private SpellManagement spellManager;               // Reference to the spell manager that is within the same object as the battle handler
    private ConsumableManagement consumableManager;     // Reference to the consumable manager that is within the same object as the battle handler

    private GameObject playerObject;                         // Container for the player game object
    private Player playerComponent;
    private GameObject[] allyObjects;                     // Container for the ally game objects
    private GameObject[] enemyObjects;                    // Container for the enemy game objects
    private Enemy[] enemyComps;                         // Containers for the enemy components within the game objects above
    private Ally[] allyComps;                           // Containers for the ally components within the game objects above

    private Ally[] allyMinionComps;
    private GameObject[] allyMinionObjects;
    private Enemy[] enemyMinionComps;
    private GameObject[] enemyMinionObjects;

    private OrderOfCombat combatOrder;                  // Reference to the Combat Order creator
    private List<Entity> order;                         // Order of entities for battling
    private Entity currentEntity;
    private List<Entity> deadEntities;                  // Collection of all of the dead entities
    private Entity previousEntity;                      // Reference to the previous entity in the turn order
    private int activeEntity;                           // Current entity reference that is battling
    private bool stillBattling;                         // Condition indicator for if the battle is still occurring
    private int TurnCounter;                            // Counter for how many turns have passed for the battle
    private Task entityDestruction;

    private bool? bountyEnabled;
    private int currentAttack;

    private const short DoubleDice = 2;                 // Double value for when double dice is called for when critting
    private const short CriticalHit = 20;               // The base crit value that indicates when a critical hit has been struck

    /// <summary>
    /// Retrieval for the EnemyUI Handler
    /// </summary>
    /// <returns></returns>
    public EnemyUI GetUIHandler()
        => uiHandler;
    /// <summary>
    /// Retrieves the value of the turn counter
    /// </summary>
    /// <returns>Turn Counter Value</returns>
    public int GetTurnCounter()
        => TurnCounter;
    /// <summary>
    /// Sets the EnemyUI once the EnemyUI is enabled within the game scene
    /// </summary>
    /// <param name="handler">The currently active EnemyUI</param>
    public void SetHandler(EnemyUI handler) 
        => uiHandler = handler;
    /// <summary>
    /// Call to set the battling status of the current encounter 
    /// </summary>
    /// <param name="trigger">Set trigger</param>
    public void SetBattlingStatus(bool trigger) 
        => stillBattling = trigger;
    public bool GetBattlingStatus()
        => stillBattling;
    /// <summary>
    /// Retrieves the enemy components from the handler
    /// </summary>
    /// <returns>The current enemy components that are not destroyed</returns>
    public Enemy[] RetrieveEnemyStates() 
        => enemyComps;
    /// <summary>
    /// Gather components
    /// </summary>
    private void Awake()
    {
        Instance                    = this;
        spellManager                = GetComponent<SpellManagement>();
        consumableManager           = GetComponent<ConsumableManagement>();
        pHandler                    = PositionHandler.Instance;
        entityDestruction           = Task.CompletedTask;
    }
    /// <summary>
    /// Sets the positions of all entities in the scene in the position handler and acquires the game objects
    /// for the enemies, allies, and player in the process
    /// </summary>
    /// <param name="player">The player to instantiate and set</param>
    /// <param name="enemies">The enemies to instantiate and set</param>
    /// <param name="allies">The allies to be instantiated and set</param>
    /// <returns>Array of the enemy and ally object components that were instantiated</returns>
    public Enemy[] CallForEntityPositioning(GameObject[] enemies, bool isBoss)
    {
        playerObject = GameManager.Instance.GetPlayerObject();
        playerComponent = playerObject.GetComponent<Player>();
        playerComponent.ReactivateVisually();

        (enemyObjects, enemyComps) = pHandler.PositionEnemies(enemies, this, isBoss);
        
        allyObjects = GameManager.Instance.GetAllyObjects();

        if (allyObjects != null)
        {
            foreach (GameObject allyObject in allyObjects)
                allyObject.GetComponent<Ally>().ReactivateVisually();

            allyComps = allyObjects.Select(ally => ally.GetComponent<Ally>()).ToArray();
            PhyllSurpriseCheck();
        }

        allyComps ??= new Ally[0];

        return enemyComps;

        void PhyllSurpriseCheck()
        {
            if (allyComps.Any(ally => ally.GetName().Equals("Phyll")))
            {
                Ally phyllComp = allyComps.Where(ally => ally.GetName().Equals("Phyll")).FirstOrDefault();
                if (phyllComp.GetInventory().Abilities.Contains(AbilityBrain.GetAbilityList()[57]))
                {
                    Ability abRef = phyllComp.GetInventory().Abilities.Where(ability => ability.AbilityID is 57).FirstOrDefault();
                    phyllComp.HideEntity();
                    abRef.active = true;
                }
            }
        }
    }
    /// <summary>
    /// Calculates the rolling to hit for the attacker
    /// </summary>
    /// <param name="entityPosition">The position of the component arrays</param>
    /// <param name="attacker">The attacking entity</param>
    /// <param name="isHostileAttack">Trigger for if the enemy component array needs to be searched or the ally component array</param>
    /// <returns></returns>
    public async void RollToHit(int entityPosition, Entity attacker, bool isHostileAttack, int attackPerformed)
    {
        currentAttack = attackPerformed;

        SortedDictionary<int, (int, Dice)> ToHitRolls = new SortedDictionary<int, (int, Dice)>();
        SortedDictionary<int, (int, Dice)> DamageRolls = new SortedDictionary<int, (int, Dice)>();

        // Determines if the enemy target is a minion or a true enemy
        Entity target;
        if (entityPosition is -1)
            target = playerComponent;
        else if (isHostileAttack)
        {
            try
            {
                target = allyComps[entityPosition];
            }
            catch
            {
                target = allyMinionComps[entityPosition - allyComps.Length];
            }
        }
        else
        {
            try
            {
                target = enemyComps[entityPosition];
            }
            catch
            {
                target = enemyMinionComps[entityPosition - enemyObjects.Length];
            }
        }

        ExtractAllAvailableEntities(out Ally[] allyAbilityChecks, out Enemy[] enemyAbilityChecks);
        (bool isDisadvantaged, bool isAdvantaged, bool autoHit) = AbilityBrain.PreToHitRollCheck(attacker, target, allyAbilityChecks, enemyAbilityChecks);

        if (!autoHit)
        {
            int critRange = CriticalHit - attacker.GatherStats().GetStat(EntityStats.Stat.ToCritMod);

            int toHitValue = DiceRoller.RollDice(new DTwenty());
            ToHitRolls.Add(0, (toHitValue, new DTwenty()));
            if (isDisadvantaged && !isAdvantaged)
            {
                int newToHitRoll = DiceRoller.RollDice(new DTwenty());
                ToHitRolls.Add(1, (newToHitRoll, new DTwenty()));

                if (newToHitRoll < toHitValue)
                    toHitValue = newToHitRoll;
            }
            else if (isAdvantaged && !isDisadvantaged)
            {
                int newToHitRoll = DiceRoller.RollDice(new DTwenty());
                ToHitRolls.Add(1, (newToHitRoll, new DTwenty()));

                if (newToHitRoll > toHitValue)
                    toHitValue = newToHitRoll;
            }

            bool hasCrit = false;

            if (toHitValue >= critRange || target.GatherModList().SmartModCheck("Sleeping") || target.GatherModList().SmartModCheck("Paralyzed"))
                hasCrit = true;
            else
                toHitValue += attacker.GatherStats().GetStat(EntityStats.Stat.Dexterity);

            // Abilities activate at the beginning of the turn
            Dictionary<string, (List<string>, List<object>)> triggers = AbilityBrain.PreTurnCompletionCheck(order[activeEntity], target, playerObject.activeSelf ? playerComponent : null,
                                                                                                        allyAbilityChecks, enemyAbilityChecks, ToHitRolls, DamageRolls, ref hasCrit);

            if (attacker.GatherStats().GetStat(EntityStats.Stat.ToHit) is not 0)
            {
                int toHitMod = attacker.GatherStats().GetStat(EntityStats.Stat.ToHit);

                if (triggers.ContainsKey("ToHitAdd"))
                {
                    triggers["ToHitAdd"].Item1.Add("To Hit Modifier");
                    triggers["ToHitAdd"].Item2.Add(toHitMod);
                }
                else
                    triggers.Add("ToHitAdd", (new List<string> { "To Hit Modifier" }, new List<object> { toHitMod }));
            }

            // Plays player attack animation
            if (attacker is Player player)
            {
                toHitValue += player.ParseToHitClassModifiers(target, triggers, ToHitRolls);
                player.InitiateAttack();
            }

            // If the attacking entity is exhausted, decrease the to hit value by a roll of a four dice
            if (attacker.GatherModList().SmartModCheck("Exhausted"))
            {
                int rolledValue = UtilityHandler.RollValue(Dice.DiceR.Four);
                toHitValue -= rolledValue;

                int currentDice = ToHitRolls.Last().Key;
                ToHitRolls.Add(++currentDice, (-rolledValue, new DFour()));
            }

            int armorValue = target.GatherStats().GetStat(EntityStats.Stat.Armor, target.RetrieveArmor());
            ArmorTriggerSearch(triggers, ref armorValue, ref toHitValue);

            uiHandler.ResetUI();
            if (toHitValue >= armorValue || hasCrit)
            {
                if (attacker.GetInventory().Abilities.Contains(AbilityBrain.GetAbilityList()[42]))
                {
                    if (DamageRolls.Count > 0)
                    {
                        int currentDice = DamageRolls.Last().Key;
                        DamageRolls.Add(++currentDice, (UtilityHandler.RollValue(Dice.DiceR.Six), new DSix()));
                    }
                    else
                        DamageRolls.Add(0, (UtilityHandler.RollValue(Dice.DiceR.Six), new DSix()));
                }
                
                GeneralUI.Instance.RollToHit(true, hasCrit, ToHitRolls, attacker, target, toHitValue, armorValue, DamageRolls, triggers, attackPerformed == attacker.AttackCount - 1);
            }
            else
            {
                Dictionary<int, Ability> abilityList = AbilityBrain.GetAbilityList();
                
                // Roulette Ability Check
                if (attacker.GetInventory().Abilities.Contains(abilityList[130]))
                {
                    Ability abRef = attacker.GetInventory().Abilities.Where(ability => ability.AbilityID is 130).FirstOrDefault();

                    abRef.active = true;
                }

                // Unstoppable Force
                if (attacker.GetInventory().Abilities.Contains(abilityList[42]))
                    DamageEntity(attacker, attacker, UtilityHandler.RollValue(Dice.DiceR.Four), false, false);

                GeneralUI.Instance.RollToHit(false, hasCrit, ToHitRolls, attacker, target, toHitValue, armorValue, DamageRolls, triggers, attackPerformed == attacker.AttackCount - 1);

                // Temper Tantrum
                if (attacker.GetInventory().Abilities.Contains(abilityList[144]))
                {
                    int rollValue = UtilityHandler.RollValue(Dice.DiceR.Ten);

                    if (rollValue is 1)
                    {
                        int turnValue = UtilityHandler.RollValue(Dice.DiceR.Four);
                        attacker.AddModToList(abilityList[144].Mod, 0, turnValue);
                    }
                }
            }
        }
        else
        {
            Inventory attackerInven = attacker.GetInventory();
            List<Ability> attackerAbilities = new List<Ability>(attackerInven.Abilities);
            attackerAbilities.AddRange(attackerInven.limitedAbilities);

            if (attackerAbilities.Contains(AbilityBrain.GetAbilityList()[78])) 
            {
                uiHandler.RetrieveActionText().UpdateActionTextUnique(17, -1, target, attacker);
                uiHandler.ResetUI();
                await uiHandler.RetrieveActionText().GetTextShownStatus();

                if (target is Enemy enemy)
                    DamageEnemy(enemy, 999, false, attackPerformed == attacker.AttackCount - 1);
                else if (target is Ally ally)
                    DamageAlly(ally, 999, false);
                else
                    DamagePlayer(999, false);
            }
        }
    }
    /// <summary>
    /// Attacks the designated entity 
    /// </summary>
    /// <param name="attacker">The attacking entity</param>
    /// <param name="target">The target entity of the attacker</param>
    /// <param name="toHitValue">The value of the to hit rolls</param>
    /// <param name="armorValue">The value of the target's total armor</param>
    /// <param name="damageRolls">The collection of dice that need to be visually rolled</param>
    /// <param name="triggers">The collection of triggers for the damage trigger searches</param>
    public async void CalculateDamage(bool wasCrit, bool? wasHit, Entity attacker, Entity target, int toHitValue, int armorValue, SortedDictionary<int, (int, Dice)> damageRolls, Dictionary<string, (List<string>, List<object>)> triggers, bool isFinalAttack)
    {
        // If the to hit was a miss than simply return from calculating the damage
        if (wasHit is null)
        {
            EnemyUI.Instance.SwitchMemberTurnText(true);
            return;
        }

        if ((bool)wasHit is false || attacker.ForcedMiss)          // Missing Conditional
        {
            attacker.ForcedMiss = false;

            uiHandler.RetrieveActionText()
                .UpdateActionTextBasic(attacker.GetName(), target.GetName(), ActionTextBox.ActionType.Misses);

            uiHandler.ResetUI();
            await uiHandler.RetrieveActionText().GetTextShownStatus();

            EnemyUI.Instance.SwitchMemberTurnText(true);
            DisablePlayerTurn();
            return;
        }

        int damage = 0;

        Dictionary<int, (List<Element>, List<WeaponSO.Type>)> usedTypeModifiers = new Dictionary<int, (List<Element>, List<WeaponSO.Type>)>();

        Weapon attackerWeapon = attacker.GetInventory().GetPrimaryActiveWeapon() ?? null;

        // If the value rolled was not a critical the to hit modifier is added, otherwise the critical hit will always hit 
        // which doubles the dice used for damage
        WeaponSO.Type damageType = attackerWeapon != null ? attackerWeapon.WeaponType : ((Ally)attacker).attackType;

        if (wasCrit)
        {
            // Rumbling Onslaught companion side
            if (attacker.GetInventory().Abilities.Contains(AbilityBrain.GetAbilityList()[118]))
            {
                int aliveCount = enemyComps.Where(enemy => enemy.HasDied is false).Count() + enemyMinionComps.Where(enemy => enemy.HasDied is false).Count();

                if (aliveCount > 1)
                {
                    Entity secondaryTarget;

                    do
                    {
                        int posValue = UnityEngine.Random.Range(-1, enemyComps.Length);
                        secondaryTarget = enemyComps[posValue];

                    } while (secondaryTarget.GetUniqueID() == target.GetUniqueID() || secondaryTarget.HasDied);

                    DamageEnemy(secondaryTarget as Enemy, damage / 2, wasCrit, false);
                }
            }

            // Dirty Tactics
            if (target.GetInventory().Abilities.Contains(AbilityBrain.GetAbilityList()[103]))
                attacker.ForcedMiss = true;

            int baseDamage = 0;
            for (int i = 0; i < DoubleDice; ++i)
            {
                Dice.DiceR[] damageDice = attackerWeapon is not null ? attackerWeapon.WeaponDamage.ToArray() : (attacker as Ally).damageDice.ToArray();
                int totalDamage = DecipherDiceRolls(damageRolls, damageDice);
                baseDamage += totalDamage;
                damage += totalDamage;
            }

            // Modify damage based on other factors
            damage = DamageTriggerSearch(target, attacker, triggers, damage, true);
            damage += UtilityHandler.DetermineModifierAndCalculate(damageType, attacker);
            damage = UtilityHandler.WeaponTypeChecks(damage, attacker, target, usedTypeModifiers);
            damage = UtilityHandler.ElementTypeChecks(damage, attacker, target, usedTypeModifiers, damageRolls);
            damage = attacker.GatherStats().GetStat(EntityStats.Stat.Damage, damage);
            damage = Mathf.Clamp(damage, 0, int.MaxValue);

            if (attacker.GetInventory().GetSecondaryActiveWeapon() != null)
            {
                Weapon secondaryWeapon = attacker.GetInventory().GetSecondaryActiveWeapon();
                // Secondary weapon potential
                if (!secondaryWeapon.WeaponIsTwoHanded)
                {
                    // 60% of the damage is applied of the weapons stats

                    int baseDmg = 0;

                    for (int i = 0; i < DoubleDice; ++i)
                    {
                        int rolledDmg = DecipherDiceRolls(damageRolls, secondaryWeapon.WeaponDamage.ToArray());
                        baseDamage += rolledDmg;
                        baseDmg += rolledDmg;
                    }

                    int addedDamage;
                    if (triggers.ContainsKey("FullOffHandSignal"))
                        addedDamage = baseDmg;
                    else
                        addedDamage = (int)Math.Ceiling(baseDmg * .6f);

                    addedDamage = DamageTriggerSearch(target, attacker, triggers, addedDamage, true);
                    addedDamage += UtilityHandler.DetermineModifierAndCalculate(damageType, attacker) / 2;
                    addedDamage = UtilityHandler.WeaponTypeChecks(addedDamage, attacker, target, usedTypeModifiers, true);
                    addedDamage = UtilityHandler.ElementTypeChecks(addedDamage, attacker, target, usedTypeModifiers, damageRolls, true);
                    addedDamage = Mathf.Clamp(addedDamage, 0, int.MaxValue);
                    damage += addedDamage;
                }
            }

            // Check for unique Life Contract trigger
            if (attacker.GatherModList().SmartModCheck("Life Contract") && damage > 0)
                attacker.GatherModList().IndicateModification("Life Contract", damage);

            if (attacker is Player player)
                damage += player.ParseClassDamageModifiers(target, triggers, damageRolls);

            // Check for Tracked Target Modifier
            damage = SharpTrackerModCheck(attacker, target, triggers, damage);

            uiHandler.ResetUI();

            if (damageRolls is not null)
                await GeneralUI.Instance.RollForDamage(damageRolls, baseDamage, damage, usedTypeModifiers);

            ActuateDamageText(attacker, target, damage, damageType, wasCrit, isFinalAttack);
        }

        // If the value rolled is greater than or equal to the armor value of the enemy with its armor mod than they will be damaged
        // otherwise the current attacking entity will have missed
        if (toHitValue >= armorValue && wasCrit is false)
        {
            int baseDamage;
            damage += DecipherDiceRolls(damageRolls, attackerWeapon != null ? attackerWeapon.WeaponDamage.ToArray() : ((Ally)attacker).damageDice.ToArray());
            baseDamage = damage;

            // Modify damage based on other factors
            damage = DamageTriggerSearch(target, attacker, triggers, damage, false);
            damage += UtilityHandler.DetermineModifierAndCalculate(damageType, attacker);
            damage = UtilityHandler.WeaponTypeChecks(damage, attacker, target, usedTypeModifiers);
            damage = UtilityHandler.ElementTypeChecks(damage, attacker, target, usedTypeModifiers, damageRolls);
            damage = attacker.GatherStats().GetStat(EntityStats.Stat.Damage, damage);
            damage = Mathf.Clamp(damage, 0, int.MaxValue);

            if (attacker.GetInventory().GetSecondaryActiveWeapon() is not null)
            {
                Weapon secondaryWeapon = attacker.GetInventory().GetSecondaryActiveWeapon();
                if (!secondaryWeapon.WeaponIsTwoHanded)
                {
                    // 60% of the damage is applied of the weapons stats for a secondary weapon
                    int baseDmg = DecipherDiceRolls(damageRolls, secondaryWeapon.WeaponDamage.ToArray());

                    int addedDamage;
                    if (triggers.ContainsKey("FullOffHandSignal"))
                        addedDamage = baseDmg;
                    else
                        addedDamage = (int)Math.Ceiling(baseDmg * .6f);

                    addedDamage = DamageTriggerSearch(target, attacker, triggers, addedDamage, false);
                    addedDamage += UtilityHandler.DetermineModifierAndCalculate(damageType, attacker);
                    addedDamage = UtilityHandler.WeaponTypeChecks(addedDamage, attacker, target, usedTypeModifiers, true);
                    addedDamage = UtilityHandler.ElementTypeChecks(addedDamage, attacker, target, usedTypeModifiers, damageRolls, true);
                    damage = Mathf.Clamp(addedDamage, 0, int.MaxValue);

                    damage += addedDamage;
                }
            }

            // Check for unique Life Contract trigger
            if (attacker.GatherModList().SmartModCheck("Life Contract") && damage > 0)
                attacker.GatherModList().IndicateModification("Life Contract", damage);

            if (attacker is Player player)
                damage += player.ParseClassDamageModifiers(target, triggers, damageRolls);

            // Check for Tracked Target Modifier
            damage = SharpTrackerModCheck(attacker, target, triggers, damage);

            uiHandler.ResetUI();

            if (damageRolls is not null)
                await GeneralUI.Instance.RollForDamage(damageRolls, baseDamage, damage, usedTypeModifiers);

            ActuateDamageText(attacker, target, damage, damageType, wasCrit, isFinalAttack);
        }
    }

    private static int SharpTrackerModCheck(Entity attacker, Entity target, Dictionary<string, (List<string>, List<object>)> triggers, int damage)
    {
        if (target.GatherModList().SmartModCheck("Tracked Target"))
        {
            Modifier targetMod = target.GatherModList().GatherModifier("Tracked Target");
            if (targetMod.RetentionObject is Player playerRetentionData && playerRetentionData.GetUniqueID() == attacker.GetUniqueID())
            {
                int addedDamage = (int)(damage * .25f);
                damage += addedDamage;

                if (triggers.ContainsKey("AddDamageValue"))
                {
                    triggers["AddDamageValue"].Item1.Add("Sharp Tracker");
                    triggers["AddDamageValue"].Item2.Add(addedDamage);
                    triggers["AddDamageType"].Item2.Add(Element.Normal);
                }
                else
                {
                    triggers.Add("AddDamageValue", (new List<string> { "Sharp Tracker" }, new List<object> { addedDamage }));
                    triggers.Add("AddDamageType", (new List<string>(), new List<object> { Element.Normal }));
                }
            }
            else if (targetMod.RetentionObject is Ally allyRetentionData && allyRetentionData.GetUniqueID() == attacker.GetUniqueID())
            {
                int addedDamage = (int)(damage * .25f);
                damage += addedDamage;

                if (triggers.ContainsKey("AddDamageValue"))
                {
                    triggers["AddDamageValue"].Item1.Add("Sharp Tracker");
                    triggers["AddDamageValue"].Item2.Add(addedDamage);
                    triggers["AddDamageType"].Item2.Add(Element.Normal);
                }
                else
                {
                    triggers.Add("AddDamageValue", (new List<string> { "Sharp Tracker" }, new List<object> { addedDamage }));
                    triggers.Add("AddDamageType", (new List<string>(), new List<object> { Element.Normal }));
                }
            }
        }

        return damage;
    }

    /// <summary>
    /// Gathers the dice to be rolled and rolls each of them while setting the rolls actual values connection to each dice
    /// </summary>
    /// <param name="DamageRolls">Collection of visual dice to be rolled correlated with their rolled values in this function</param>
    /// <param name="attackerDice">The collection of dice to be rolled</param>
    /// <returns></returns>
    private int DecipherDiceRolls(SortedDictionary<int, (int, Dice)> DamageRolls, Dice.DiceR[] attackerDice)
    {
        int totalDamage = 0;
        for (int j = 0; j < attackerDice.Length; ++j)
        {
            int damageRolled;
            Dice diceType = new DHundred();
            switch (attackerDice[j])
            {
                case Dice.DiceR.Four:
                    diceType = new DFour();
                    break;
                case Dice.DiceR.Six:
                    diceType = new DSix();
                    break;
                case Dice.DiceR.Eight:
                    diceType = new DEight();
                    break;
                case Dice.DiceR.Ten:
                    diceType = new DTen();
                    break;
                case Dice.DiceR.Twelve:
                    diceType = new DTwelve();
                    break;
                case Dice.DiceR.Twenty:
                    diceType = new DTwenty();
                    break;
            }

            damageRolled = DiceRoller.RollDice(diceType);

            if (DamageRolls is not null)
            {
                if (DamageRolls.Count > 0 && diceType is not DHundred)
                {
                    int currentDice = DamageRolls.Last().Key;
                    DamageRolls.Add(++currentDice, (damageRolled, diceType));
                }
                else if (diceType is not DHundred)
                    DamageRolls.Add(0, (damageRolled, diceType));
            }

            totalDamage += damageRolled;
        }

        return totalDamage;
    }
    /// <summary>
    /// Damages the targetted enemy component with the damage amount and calls the action text with the weapon type
    /// </summary>
    /// <param name="enemyPosition"></param>
    /// <param name="attackingEntity"></param>
    /// <param name="target"></param>
    /// <param name="damage"></param>
    /// <param name="weaponType"></param>
    private async void ActuateDamageText(Entity attackingEntity, Entity target, int damage, WeaponSO.Type weaponType, bool wasCrit, bool isFinalAttack)
    {
        damage = Mathf.Clamp(damage, 0, int.MaxValue);

        // Misses if the damage is 0
        if (damage is 0)
        {
            uiHandler.RetrieveActionText()
                .UpdateActionTextBasic(attackingEntity.GetName(), target.GetName(), ActionTextBox.ActionType.Misses);
        }
        // If ranged or magic than the ranged type is indicated as of now 
        else if (weaponType is WeaponSO.Type.Ranged || weaponType is WeaponSO.Type.Magic)
        {
            uiHandler.RetrieveActionText()
                .UpdateActionTextBasic(attackingEntity.GetName(), target.GetName(), ActionTextBox.ActionType.Ranged, damage);
        }
        // Otherwise, the weapon type is thought to be of a melee variety
        else
        {
            uiHandler.RetrieveActionText()
                .UpdateActionTextBasic(attackingEntity.GetName(), target.GetName(), ActionTextBox.ActionType.Melee, damage);
        }

        bool afterImageCheck = attackingEntity.GatherModList().SmartModCheck("Afterimage");

        DamageEntity(attackingEntity, target, damage, wasCrit, isFinalAttack && !afterImageCheck);

        // Afterimage modifier effect
        if (afterImageCheck && !target.HasDied)
        {
            await uiHandler.RetrieveActionText().GetTextShownStatus();

            int afterDamage = (int)Math.Floor(damage * .4);

            uiHandler.RetrieveActionText().UpdateActionTextUnique(36, afterDamage, target, attackingEntity);
            DamageEntity(attackingEntity, target, afterDamage, false, isFinalAttack);
        }

        if (isFinalAttack)
            EnemyUI.Instance.SwitchMemberTurnText(true);
    }
    /// <summary>
    /// Damages the designated entity after determining its type
    /// </summary>
    /// <param name="attacker">The attacking entity</param>
    /// <param name="target">The target entity</param>
    /// <param name="damage">The amount of damage to do</param>
    private async void DamageEntity(Entity attacker, Entity target, int damage, bool wasCrit, bool isFinalAttack)
    {
        bool modsActivated = false;

        if (target.GatherModList().SmartModCheck("Counter Stance"))
        {
            if (attacker is Player)
                DamagePlayer(damage / 2, false);
            else if (attacker is Ally)
                DamageAlly(attacker as Ally, damage / 2, false);
            else
                DamageEnemy(attacker as Enemy, damage / 2, false, false);
        }

        if (target is Enemy enemy)
        {
            try
            {
                if (damage > 0)
                {
                    AddActivatedMods(attacker.CallMods(enemy), enemy);
                    modsActivated = true;
                }

                DamageEnemy(enemy, damage, wasCrit, isFinalAttack);
            }
            catch (IndexOutOfRangeException)
            {
                if (enemyComps.Length is 0)
                    return;

                enemy = enemyComps[^1];
                if (damage > 0 && !modsActivated)
                    AddActivatedMods(attacker.CallMods(enemy), enemy);

                DamageEnemy(enemy, damage, wasCrit, isFinalAttack);
            }
        }
        else if (target is Ally ally)
        {
            try
            {
                if (damage > 0)
                {
                    AddActivatedMods(attacker.CallMods(ally), ally);
                    modsActivated = true;
                }

                DamageAlly(ally, damage, wasCrit);
            }
            catch (IndexOutOfRangeException)
            {
                if (allyComps.Length is 0)
                    return;

                ally = allyComps[^1];
                if (damage > 0 && !modsActivated)
                    AddActivatedMods(attacker.CallMods(ally), ally);

                DamageAlly(ally, damage, wasCrit);
            }
        }
        else if (target is Player player)
        {
            if (damage > 0)
                AddActivatedMods(attacker.CallMods(player), player);

            DamagePlayer(damage, wasCrit);
        }

        await uiHandler.RetrieveActionText().GetTextShownStatus();
        if ((attacker is Player || attacker is Ally) && isFinalAttack)
            DisablePlayerTurn();
        else
        {
            if (enemyComps.All(enemy => enemy.HasDied))
            {
                DisablePlayerTurn();
                return;
            }

            uiHandler.Fight(attacker, ++currentAttack);
        }
    }
    public async Task AttackLeftSide(List<Dice.DiceR> damageDice, WeaponSO.Type actionType, Enemy enemyRef, bool confused = false)
    {
        Dictionary<int, Ability> abilityList = AbilityBrain.GetAbilityList();

        for (int i = 0; i < enemyRef.AttackCount; ++i)
        {
            // Gather target
            Entity target;
            target = GatherTargetForEnemy(enemyRef, confused);

            await ActivatePreparationSpells(enemyRef, PreparationCalls.NextAttackingEntity);

            // This is simply an easier way to wipe the enemy out if they were killed,
            // as their health won't drop further and still signal an enemy perished
            if (enemyRef.HasDied)
            {
                DamageEnemy(enemyRef, 1, false, false);
                return;
            }

            if (target == null)
            {
                uiHandler.RetrieveActionText().UpdateActionTextUnique(21, -1, target, enemyRef);

                await uiHandler.RetrieveActionText().GetTextShownStatus();
                return;
            }

            List<object> damageAndCritIndic = CalculateEnemyDamage(target, damageDice, enemyRef);

            if (enemyRef.ForcedMiss)
            {
                damageAndCritIndic[0] = 0;
                enemyRef.ForcedMiss = false;
            }
            else if ((bool)damageAndCritIndic[1])
            {
                // Dirty Tactics
                if (target.GetInventory().Abilities.Contains(abilityList[103]))
                    enemyRef.ForcedMiss = true;
            }

            if ((int)damageAndCritIndic[0] is not 0)
            {
                AddActivatedMods(enemyRef.CallMods(target), target);

                // Check for unique Life Contract trigger
                if (enemyRef.GatherModList().SmartModCheck("Life Contract") && (int)damageAndCritIndic[0] > 0)
                    enemyRef.GatherModList().IndicateModification("Life Contract", (int)damageAndCritIndic[0]);
            }

            if (target.GatherModList().SmartModCheck("Counter Stance"))
                DamageEnemy(enemyRef, (int)damageAndCritIndic[0] / 2, false, false);

            if (target is Player)
            {
                bool wasRedirected = false;
                foreach (Ally ally in allyComps)
                {
                    if (ally.GetInventory().Abilities.Contains(abilityList[115]) && (int)damageAndCritIndic[0] < ally.RetrieveHealth())
                    {
                        int currentTargetHealth = target.GetHealthPercentage();
                        int chance = 1;

                        if (currentTargetHealth < 75)
                            chance = 2;
                        else if (currentTargetHealth < 50)
                            chance = 3;
                        else
                            chance = 4;

                        int rolledChance = UnityEngine.Random.Range(0, 11);

                        if (chance > rolledChance)
                        {
                            target = ally;
                            DamageAlly(target as Ally, (int)damageAndCritIndic[0], (bool)damageAndCritIndic[1]);
                            wasRedirected = true;
                            break;
                        }
                    }
                }

                if (wasRedirected is false)
                    DamagePlayer((int)damageAndCritIndic[0], (bool)damageAndCritIndic[1]);
            }
            else
            {
                bool wasRedirected = false;

                if (playerComponent.GetInventory().Abilities.Contains(abilityList[115]) && (int)damageAndCritIndic[0] < playerComponent.RetrieveHealth())
                {
                    int currentTargetHealth = target.GetHealthPercentage();
                    int chance = 1;

                    if (currentTargetHealth < 75)
                        chance = 2;
                    else if (currentTargetHealth < 50)
                        chance = 3;
                    else
                        chance = 4;

                    int rolledChance = UnityEngine.Random.Range(0, 11);

                    if (chance > rolledChance)
                    {
                        target = playerComponent;
                        DamagePlayer((int)damageAndCritIndic[0], (bool)damageAndCritIndic[1]);
                        wasRedirected = true;
                    }
                }

                if (wasRedirected is false)
                {
                    foreach (Ally ally in allyComps)
                    {
                        if (ally.GetInventory().Abilities.Contains(abilityList[115]) && (int)damageAndCritIndic[0] < ally.RetrieveHealth() && ally.GetUniqueID() != target.GetUniqueID())
                        {
                            int currentTargetHealth = target.GetHealthPercentage();
                            int chance = 1;

                            if (currentTargetHealth < 75)
                                chance = 2;
                            else if (currentTargetHealth < 50)
                                chance = 3;
                            else
                                chance = 4;

                            int rolledChance = UnityEngine.Random.Range(0, 11);

                            if (chance > rolledChance)
                            {
                                target = ally;
                                DamageAlly(target as Ally, (int)damageAndCritIndic[0], (bool)damageAndCritIndic[1]);
                                wasRedirected = true;
                                break;
                            }
                        }
                    }
                }

                if (wasRedirected is false)
                    DamageAlly(target as Ally, (int)damageAndCritIndic[0], (bool)damageAndCritIndic[1]);
            }   

            // Afterimage modifier effect
            if (enemyRef.GatherModList().SmartModCheck("Afterimage") && !target.HasDied)
            {
                await uiHandler.RetrieveActionText().GetTextShownStatus();

                int afterDamage = (int)Math.Floor((int)damageAndCritIndic[0] * .4);

                uiHandler.RetrieveActionText().UpdateActionTextUnique(36, afterDamage, target, enemyRef);

                if (target is Player)
                    DamagePlayer(afterDamage, false);
                else
                    DamageAlly(target as Ally, afterDamage, false);
            }

            // If the target perished, then the entity will attempt to laugh
            if (target.HasDied)
                enemyRef.GetAnimationHandler().PlayKilledAllySound();

            if (playerComponent.HasDied && allyComps.All(ally => ally.HasDied))
            {
                DisableBattle();
                return;
            }

            EnemyTextCall(actionType, enemyRef, (int)damageAndCritIndic[0], target.GetName());

            await uiHandler.RetrieveActionText().GetTextShownStatus();
        }
    }
    private async Task ActivatePreparationSpells(Entity attacker, PreparationCalls callForm)
    {
        object retrievedObject = null;
        bool isCorrectPrepCall = attacker.IsPreparing.Item2.Item1 == callForm;

        if (!isCorrectPrepCall)
            return;

        switch (callForm)
        {
            case PreparationCalls.NextAttackingEntity:

                if (attacker is Enemy enemy)
                {
                    bool activePreparation = allyComps.Any(ally => ally.IsPreparing.Item1) || playerComponent.IsPreparing.Item1;

                    if (!activePreparation)
                        return;

                    if (playerComponent.IsPreparing.Item2.Item1 is PreparationCalls.NextAttackingEntity)
                    {
                        retrievedObject = playerComponent.IsPreparing.Item2.Item2;

                        if (retrievedObject is List<Dice.DiceR> dices)
                        {
                            int totalDamage = UtilityHandler.RollValue(dices.ToArray());

                            attacker.DecreaseHealth(totalDamage);
                            attacker.StatusChanged();

                            uiHandler.RetrieveActionText().UpdateActionTextUnique(29, totalDamage, attacker, playerComponent);
                            await uiHandler.RetrieveActionText().GetTextShownStatus();
                        }

                        playerComponent.IsPreparing = (false, (PreparationCalls.FinishRound, null));
                    }
                    foreach (Ally allyComp in allyComps)
                    {
                        if (allyComp.IsPreparing.Item2.Item1 is PreparationCalls.NextAttackingEntity)
                        {
                            retrievedObject = allyComp.IsPreparing.Item2.Item2;

                            if (retrievedObject is List<Dice.DiceR> dices)
                            {
                                int totalDamage = UtilityHandler.RollValue(dices.ToArray());

                                attacker.DecreaseHealth(totalDamage);
                                attacker.StatusChanged();

                                uiHandler.RetrieveActionText().UpdateActionTextUnique(29, totalDamage, attacker, allyComp);
                                await uiHandler.RetrieveActionText().GetTextShownStatus();
                            }

                            allyComp.IsPreparing = (false, (PreparationCalls.FinishRound, null));
                        }
                    }
                }
                else
                {
                    bool activePreparation = enemyComps.Any(ally => ally.IsPreparing.Item1);

                    if (!activePreparation)
                        return;

                    foreach (Enemy enemyComp in enemyComps)
                    {
                        if (enemyComp.IsPreparing.Item2.Item1 is PreparationCalls.NextAttackingEntity)
                        {
                            retrievedObject = enemyComp.IsPreparing.Item2.Item2;

                            if (retrievedObject is List<Dice.DiceR> dices)
                            {
                                int totalDamage = UtilityHandler.RollValue(dices.ToArray());

                                attacker.DecreaseHealth(totalDamage);
                                attacker.StatusChanged();

                                uiHandler.RetrieveActionText().UpdateActionTextUnique(29, totalDamage, attacker, enemyComp);
                                await uiHandler.RetrieveActionText().GetTextShownStatus();
                            }

                            enemyComp.IsPreparing = (false, (PreparationCalls.FinishRound, null));
                        }
                    }
                }

                attacker.IsPreparing = (false, (PreparationCalls.FinishRound, null));
                break;
            case PreparationCalls.NextTurn:

                retrievedObject = attacker.IsPreparing.Item2.Item2;

                List<object> objectList = (List<object>)retrievedObject;

                List<Dice.DiceR> damageDice = objectList[0] as List<Dice.DiceR>;
                Entity target = objectList[1] as Entity;
                string spellCalled = objectList[2] as string;

                switch (spellCalled)
                {
                    case "Precise Shot":

                        int totalDamage = UtilityHandler.RollValue(damageDice.ToArray());

                        if (attacker.IsHidden)
                            totalDamage *= 2;

                        if (target.HasDied)
                        {
                            do
                            {
                                target = enemyComps[UnityEngine.Random.Range(0, enemyComps.Length)];

                            } while (target.HasDied);
                        }

                        target.DecreaseHealth(totalDamage);
                        target.StatusChanged();

                        uiHandler.RetrieveActionText().UpdateActionTextUnique(31, totalDamage, target, attacker);
                        await uiHandler.RetrieveActionText().GetTextShownStatus();

                        if (target.HasDied)
                            DamageEnemy(target as Enemy, 1, false);

                        break;
                }

                attacker.IsPreparing = (false, (PreparationCalls.FinishRound, null));
                break;
            case PreparationCalls.FinishRound:

                attacker.IsPreparing = (false, (PreparationCalls.FinishRound, null));
                break;
            case PreparationCalls.NextEntity:

                attacker.IsPreparing = (false, (PreparationCalls.FinishRound, null));
                break;
        }
    }
    private List<object> CalculateEnemyDamage(Entity target, List<Dice.DiceR> damageDice, Enemy enemyRef)
    {
        Dictionary<int, Ability> abilityList = AbilityBrain.GetAbilityList();
        ExtractAllAvailableEntities(out Ally[] allyAbilityChecks, out Enemy[] enemyAbilityChecks);
        (bool isDisadvantaged, bool isAdvantaged, bool autoHit) = AbilityBrain.PreToHitRollCheck(enemyRef, target, allyAbilityChecks, enemyAbilityChecks);

        bool hasCrit = false;
        int damage = 0;

        if (!autoHit)
        {
            int critValue = CriticalHit - enemyRef.GatherStats().GetStat(EntityStats.Stat.ToCritMod);

            int toHitValue = DiceRoller.RollDice(new DTwenty());
            if (isDisadvantaged && !isAdvantaged)
            {
                int newToHitValue = DiceRoller.RollDice(new DTwenty());

                if (newToHitValue < toHitValue)
                    toHitValue = newToHitValue;
            }
            else if (isAdvantaged && !isDisadvantaged)
            {
                int newToHitValue = DiceRoller.RollDice(new DTwenty());

                if (newToHitValue > toHitValue)
                    toHitValue = newToHitValue;
            }

            hasCrit = toHitValue >= critValue;
            int armorValue = target.GatherStats().GetStat(EntityStats.Stat.Armor, target.RetrieveArmor());

            Dictionary<string, (List<string>, List<object>)> triggers = AbilityBrain.PreTurnCompletionCheck(enemyRef, target, playerObject.activeSelf ? playerComponent : null,
                                                                                                    allyAbilityChecks, enemyAbilityChecks, toHitValue >= armorValue, null, ref hasCrit);
            if (enemyRef.GatherModList().SmartModCheck("Exhausted"))
                toHitValue -= UtilityHandler.RollValue(Dice.DiceR.Four);

            if (!hasCrit)
                toHitValue = Mathf.Clamp(toHitValue + enemyRef.GatherStats().GetStat(EntityStats.Stat.ToHit) + enemyRef.GatherStats().GetStat(EntityStats.Stat.Dexterity), 0, int.MaxValue);

            ArmorTriggerSearch(triggers, ref armorValue, ref toHitValue);

            // Unbreakable Chain Relic Flag
            if (target.GetInventory().GetActiveRelic() != null)
            {
                if (target.GetInventory().GetActiveRelic().ItemId is 0)
                {
                    int totalArmorValue = 4;
                    int targetSize = target.GetSizeIndic();
                    int healthPercentage = target.GetHealthPercentage();

                    while (healthPercentage >= 25)
                    {
                        healthPercentage -= 25;
                        totalArmorValue--;
                    }

                    armorValue += totalArmorValue;

                    bool isWithinThreshold = (healthPercentage <= 5 && targetSize is 0) || (healthPercentage <= 15 && targetSize is 1) || (healthPercentage <= 25 && targetSize is 2);
                    Modifier strangledMod = AbilityBrain.GetModifierList()["Strangled"];

                    if (isWithinThreshold && !target.GatherModList().SmartModCheck("Strangled"))
                        target.AddModToList(strangledMod, 0, 3);
                    else if (!isWithinThreshold && target.GatherModList().SmartModCheck("Strangled"))
                        target.GatherModList().RemoveModifier(strangledMod);

                    target.AfflictedStatus();
                }
            }

            // Rumbling Onslaught Ability
            if (enemyRef.GetInventory().Abilities.Contains(abilityList[118]))
            {
                int aliveCount = (playerComponent.HasDied ? 0 : 1) + allyComps.Where(ally => ally.HasDied is false).Count() + allyMinionComps.Length;

                if (aliveCount > 1)
                {
                    Entity secondaryTarget;

                    do
                    {
                        int posValue = UnityEngine.Random.Range(-1, allyComps.Length);
                        secondaryTarget = posValue is -1 ? playerComponent : allyComps[posValue];

                    } while (secondaryTarget.GetUniqueID() == target.GetUniqueID() || secondaryTarget.HasDied);

                    if (secondaryTarget is Player)
                        DamagePlayer(damage / 2, hasCrit);
                    else if (secondaryTarget is Ally ally)
                        DamageAlly(ally, damage / 2, hasCrit);
                }
            }

            if (hasCrit)
            {
                for (int k = 0; k < DoubleDice; k++)
                {
                    int damageRolled = UtilityHandler.RollValue(damageDice.ToArray());

                    damage += damageRolled;
                }

                // Modify damage value as needed
                damage = DamageTriggerSearch(target, enemyRef, triggers, damage, true);
                damage += enemyRef.GatherStats().GetStat(EntityStats.Stat.Strength);
                damage = UtilityHandler.WeaponTypeChecks(damage, enemyRef, target);
                damage = UtilityHandler.ElementTypeChecks(damage, enemyRef, target, null, null);
                damage = enemyRef.GatherStats().GetStat(EntityStats.Stat.Damage, damage);
                damage = Mathf.Clamp(damage, 0, int.MaxValue);

                if (enemyRef.GetInventory().Abilities.Contains(abilityList[42]))
                    damage += UtilityHandler.RollValue(Dice.DiceR.Six);
            }
            else if (toHitValue >= armorValue)
            {
                damage += UtilityHandler.RollValue(damageDice.ToArray());

                // Modify damage value as needed
                damage = DamageTriggerSearch(target, enemyRef, triggers, damage, false);
                damage += enemyRef.GatherStats().GetStat(EntityStats.Stat.Strength);
                damage = UtilityHandler.WeaponTypeChecks(damage, enemyRef, target);
                damage = UtilityHandler.ElementTypeChecks(damage, enemyRef, target, null, null);
                damage = enemyRef.GatherStats().GetStat(EntityStats.Stat.Damage, damage);
                damage = Mathf.Clamp(damage, 0, int.MaxValue);

                if (enemyRef.GetInventory().Abilities.Contains(abilityList[42]))
                    damage += UtilityHandler.RollValue(Dice.DiceR.Six);
            }
            else
            {
                // Unstoppable Force
                if (enemyRef.GetInventory().Abilities.Contains(abilityList[42]))
                    DamageEnemy(enemyRef, UtilityHandler.RollValue(Dice.DiceR.Four), false, false);

                // Temper Tantrum
                if (enemyRef.GetInventory().Abilities.Contains(abilityList[144]))
                {
                    int rollValue = UtilityHandler.RollValue(Dice.DiceR.Ten);

                    if (rollValue is 1)
                    {
                        int turnValue = UtilityHandler.RollValue(Dice.DiceR.Four);
                        enemyRef.AddModToList(abilityList[144].Mod, 0, turnValue);
                    }
                }
            }

            if (target.GatherModList().SmartModCheck("Tracked Target"))
            {
                Modifier trackerMod = target.GatherModList().GatherModifier("Tracked Target");

                if (trackerMod.RetentionObject is Enemy enemyRetentionData && enemyRetentionData.GetUniqueID() == enemyRef.GetUniqueID())
                    damage += (int)(damage * .25f);
            }
        }
        else
        {
            Inventory attackerInven = enemyRef.GetInventory();
            List<Ability> attackerAbilities = new List<Ability>(attackerInven.Abilities);
            attackerAbilities.AddRange(attackerInven.limitedAbilities);

            if (attackerAbilities.Contains(AbilityBrain.GetAbilityList()[78]))
            {
                uiHandler.RetrieveActionText().UpdateActionTextUnique(17);
                uiHandler.ResetUI();
                uiHandler.RetrieveActionText().GetTextShownStatus().GetAwaiter();

                if (target is Enemy enemy)
                    DamageEnemy(enemy, 999, false, false);
                else if (target is Ally ally)
                    DamageAlly(ally, 999, false);
                else
                    DamagePlayer(999, false);
            }
        }

        return new List<object> { damage, hasCrit };
    }
    private void EnemyTextCall(WeaponSO.Type actionType, Enemy enemyRef, int damageValue, string targetName)
    {
        if (damageValue is 0)
        {
            uiHandler.RetrieveActionText()
                .UpdateActionTextBasic(enemyRef.GetName(), targetName, ActionTextBox.ActionType.Misses);
        }
        else if (actionType is WeaponSO.Type.Magic || actionType is WeaponSO.Type.Ranged)
        {
            uiHandler.RetrieveActionText()
                .UpdateActionTextBasic(enemyRef.GetName(), targetName, ActionTextBox.ActionType.Ranged, damageValue);
        }
        else
        {
            uiHandler.RetrieveActionText()
                .UpdateActionTextBasic(enemyRef.GetName(), targetName, ActionTextBox.ActionType.Melee, damageValue);
        }
    }
    /// <summary>
    /// Adds all of the mods that were rolled and indicated to be activated to the target's mod list
    /// </summary>
    /// <param name="modList">The list of mods that were rolled for, true is activated, false is disabled</param>
    /// <param name="target">The entity to add to the mod list</param>
    private void AddActivatedMods(Dictionary<Modifier, bool> modList, Entity target)
    {
        if (modList == null || modList.Count is 0 || target == null)
            return;

        // Selects all mods that hid a value of true and adds them to the target
        foreach (KeyValuePair<Modifier, bool> pair in modList)
        {
            if (pair.Value)
                target.AddModToList(pair.Key);
        }
    }
    /// <summary>
    /// Damages the enemy before checking if they have perished
    /// </summary>
    /// <param name="enemy">The index of the enemy in their array</param>
    /// <param name="damage">The amount of damage done</param>
    public async void DamageEnemy(Enemy enemy, int damage, bool wasCrit , bool endOfTurn = true)
    {
        // Activates certain functions depending on which flags are flipped in Globals and the inventory references
        for (int i = 1; i <= 2; ++i)
            damage = FindTableFlagFunction(enemy, i, damage, wasCrit);

        // Decrease health of enemy
        bool statusTrigger = enemy.DecreaseHealth(damage);
        enemy.StatusChanged();

        // Destroys the enemy game object on screen if the decrease health call yielded true to reaching zero
        if (statusTrigger)
        {
            // UI is reset to prevent player interactions after killing an enemy
            uiHandler.ResetUI();

            while (enemy.GetAnimationHandler().AcquireAnimationState())
                await Task.Yield();

            if (!enemy.IsMinion)
            {
                if (bountyEnabled is true)
                {
                    Ability abRef = playerComponent.GetInventory().Abilities.Find(ability => ability.AbilityID is 70);
                    TakenBounty bountyLogic = ((TakenBounty)abRef.ReferenceObject);
                    Enemy bounty = bountyLogic.Bounty;

                    if (bounty.GetName().Equals(enemy.GetName()))
                    {
                        bountyLogic.IndicateBountyHasFallen();
                        bountyEnabled = false;
                    }
                }

                int indexPoint = enemyComps.ToList().IndexOf(enemy);
                await DeactivateEntity(indexPoint, true);
                await uiHandler.DeactivateEntityValue(indexPoint, true);
            }
            else
                DestroyMinionInstance(enemy);
        }

        if (endOfTurn)
        {
            uiHandler.ResetUI();
            DisablePlayerTurn();
        }
    }
    /// <summary>
    /// Damages an ally and destroys it if the HP drops to 0
    /// </summary>
    /// <param name="ally">The ally being targetted</param>
    /// <param name="damage">The amount of damage being afflicted to the ally</param>
    public async void DamageAlly(Ally ally, int damage, bool wasCrit)
    {
        // Activates certain functions depending on which flags are flipped in Globals and the inventory references
        // TODO ---> Optimize, no magic 3
        for (int i = 1; i <= 3; ++i)
            damage = FindTableFlagFunction(ally, i, damage, wasCrit);

        // Pulls true if the health drops below or equal to 0
        bool statusTrigger = ally.DecreaseHealth(damage);
        ally.StatusChanged();

        // If the health is below or equal to 0 then the entity is destroyed 
        if (statusTrigger)
        {
            // TODO ---> Implement ally animation systems when more animations are given
            //while (ally.GetAnimationHandler().AcquireAnimationState())
            //    await Task.Yield();

            // Check if the ally is a minion first
            if (!ally.IsMinion)
            {
                ally.GetGUI().UpdateStats(ally);
                int indexPoint = allyComps.ToList().IndexOf(ally);
                await DeactivateEntity(indexPoint, false);
                await uiHandler.DeactivateEntityValue(indexPoint, false);
            }
            else
            {
                GeneralUI.Instance.EliminateMinionGUI(ally);
                DestroyMinionInstance(ally);
            }
        }
    }
    /// <summary>
    /// Damages the player and updates the health condition on screen
    /// </summary>
    /// <param name="damage">Damage the player takes</param>
    /// <param name="pRef">The player being affected</param>
    public async void DamagePlayer(int damage, bool wasCrit)
    {
        Player pRef = playerComponent;

        // Activates certain functions depending on which flags are flipped in Globals and the inventory references
        for (int i = 1; i <= 2; ++i)
            damage = FindTableFlagFunction(pRef, i, damage, wasCrit);

        bool trigger = pRef.DecreaseHealth(damage);
        pRef.StatusChanged();

        if (trigger)
        {
            uiHandler.ResetUI();
            GeneralUI.Instance.SetInformation(false);

            while (pRef.GetAnimationHandler().AcquireAnimationState())
                await Task.Yield();

            await DeactivateEntity(-1, false);
            await uiHandler.DeactivateEntityValue(-1, false);
        }
    }
    private int FindTableFlagFunction(Entity entityComponent, int idValue, int damage, bool wasCrit)
    {
        try
        {
            if (entityComponent.GetInventory().Flaglist[idValue] && Globals.Flags[idValue])
            {
                switch (idValue)
                {
                    case 1:
                        damage -= 3;                    // Improved Iron Helmet Damage Reduction Effect
                        break;
                    case 2:                             // Immutable Star Ring replenish mana effect
                        entityComponent.IncreaseMana(2);
                        entityComponent.StatusChanged();
                        break;
                    case 3:                             // Ring of Rage
                        if (wasCrit)
                            entityComponent.AddModToList(AbilityBrain.GetModifierList()["Rage"]);
                        break;
                    case 4:

                        break;
                }
            }
        }
        catch { }

        return damage;
    }
    /// <summary>
    /// Disables the player's turn
    /// </summary>
    public async void DisablePlayerTurn(bool checkProcess = false)
    {
        await uiHandler.RetrieveActionText().GetTextShownStatus();
        await uiHandler.DisableLeftBattle(TurnCounter == 0, checkProcess);
    }
    /// <summary>
    /// Destroys the entity via gameobject and component in their respective collections based on
    /// if they are an ally or an enemy in the battle
    /// </summary>
    /// <param name="entityPosition">The index of the entity in their respective collection</param>
    /// <param name="isEnemy">True for if the enemy collections need to be changed or False if ally collections need to be changed</param>
    private async Task DeactivateEntity(int entityPosition, bool isEnemy)
    {
        // This acts as a queue guard for destroying entities
        if (entityDestruction == null)
            await Task.Yield();

        entityDestruction = null;

        // This is a signal for when the player has been taken out
        if (entityPosition is -1)
        {
            // If the entity being killed is the player than simply remove from the order and signal completion before returning
            deadEntities.Add(playerComponent);
            playerComponent.DeactivateVisually();
            entityDestruction = Task.CompletedTask;
            return;
        }
        // Removes and disables the necessary garbage game object marked by the position
        else
        {
            if (isEnemy)
            {
                deadEntities.Add(enemyObjects[entityPosition].GetComponent<Enemy>());
                enemyObjects[entityPosition].SetActive(false);
            }
            else
            {
                deadEntities.Add(allyObjects[entityPosition].GetComponent<Ally>());
                allyObjects[entityPosition].GetComponent<Ally>().DeactivateVisually();
            }
        }

        int loopLength = isEnemy ? enemyComps.Length : allyComps.Length;

        // Sets the array values with the old array values and removes the unneccessary value in the CombatOrder
        for (int i = 0; i < loopLength; i++)
        {
            if (i == entityPosition && isEnemy)
            {
                enemyComps[i].enabled = false;
                break;
            }
        }

        entityDestruction = Task.CompletedTask;
    }
    /// <summary>
    /// Destroys all enemies and their respective health indicator child
    /// </summary>
    public void DeactivateAllEnemies()
    {
        // Deactivates all enemy attributes
        for (int i = 0; i < enemyObjects.Length; i++)
        {
            enemyObjects[i].SetActive(false);
            enemyComps[i].enabled = false;
        }
    }
    /// <summary>
    /// Destroys and clears the list of ally game objects within the handler and scene
    /// </summary>
    public void DeactivateAllAllies()
    {
        // 'Destroy' the allies by deactivating their models
        for (int i = 0; i < allyComps.Length; ++i)
            allyComps[i].DeactivateVisually();
    }
    /// <summary>
    /// Creates the order that this battle will carry out in 
    /// </summary>
    /// <exception cref="InvalidOperationException">Exception is thrown if the enemy values rolled does not match the number of enemies in the scene</exception>
    public async void InitializeOrder()
    {
        // Resets the combat order class container
        if (combatOrder != null)
            combatOrder = null;
        
        combatOrder = new OrderOfCombat();
        deadEntities = new();
        TurnCounter = 0;
        await AbilityBrain.PreBattleChecks(playerComponent, allyComps, enemyComps);

        Dictionary<int, Ability> abList = AbilityBrain.GetAbilityList();

        // Bounty Check
        if (playerComponent.GetInventory().Abilities.Contains(abList[70]) && bountyEnabled is null)
        {
            Ability abRef = playerComponent.GetInventory().Abilities.Find(ability => ability.AbilityID is 70);
            
            if (abRef.ReferenceObject is not null)
            {
                Enemy bounty = ((TakenBounty)abRef.ReferenceObject).Bounty;
                
                foreach (Enemy enemy in enemyComps)
                {
                    if (enemy.GetName().Equals(bounty.GetName()))
                    {
                        bountyEnabled = true;
                        break;
                    }
                }

                if (bountyEnabled is not true)
                    bountyEnabled = false;
            }
        }

        // Check for Root Network
        bool groupAdvantage = allyComps.Any(ally => ally.GetInventory().Abilities.Contains(abList[62]));

        // Calls player roll initiative
        Player playerComp = playerComponent;
        int playerV = playerComp.RollOrderValue();
        
        if (groupAdvantage || playerComponent.GetInventory().Abilities.Contains(abList[129]))   // Quickdraw check
        {
            int newPlayerV = playerComp.RollOrderValue();

            if (newPlayerV > playerV)
                playerV = newPlayerV;
        }

        combatOrder.CallOrderInitiative(playerComp, playerV);

        // Gathers all of the enemy rolls, makes sure that that all of the enemy rolls are unique 
        int[] enemyVs = new int[enemyComps.Length];
        for (int i = 0; i < enemyComps.Length; i++)
        {
            int c = enemyComps[i].RollOrderValue();

            // Unique roll check, if not unique than the enemy is rerolled
            if (c == playerV || enemyVs.Contains(c))
                i--;
            else
                enemyVs[i] = c;
        }

        if (enemyVs.Length != enemyComps.Length)
            throw new InvalidOperationException($"Non equal rolls detected for enemy_Vs : {enemyVs} and enemy_Comps : " +
                $"{enemyComps.Length}, check loop to make sure all enemies are rolling for their turn!");

        // Combat Order is called to input all of the enemy roll values
        int pos = 0;
        foreach (int v in enemyVs)
            combatOrder.CallOrderInitiative(enemyComps[pos++], v);

        if (allyComps != null)
        {
            // Gathers all of the ally rolls, also makes sure that all of the ally rolls are unique
            int[] allyVs = new int[allyComps.Length];
            for (int i = 0; i < allyComps.Length; i++)
            {
                int c = allyComps[i].RollOrderValue();

                if (groupAdvantage)
                {
                    int newC = allyComps[i].RollOrderValue();

                    if (newC > c)
                        c = newC;
                }

                // Unique roll check for the ally
                if (c == playerV || enemyVs.Contains(c) || allyVs.Contains(c))
                    i--;
                else
                    allyVs[i] = c;
            }

            if (allyVs.Length != allyComps.Length)
                throw new InvalidOperationException($"Non equal rolls detected for ally_Vs : {allyVs} and ally_Comps : " +
                    $"{allyComps.Length}, check loop to make sure all allies are rolling for their turn!");

            // Combat Order is called to input all of the ally roll values
            pos = 0;
            foreach (int v in allyVs)
                combatOrder.CallOrderInitiative(allyComps[pos++], v);
        }

        // Then then combat order is sorted based off of the roll values for each of the entities
        order = new List<Entity>(combatOrder.SortOrder());
        activeEntity = 0;
        uiHandler.currentEntityTurnText.text = $"{order[activeEntity].GetName()}";
        uiHandler.currentEntityTurnText.enabled = true;
        Debug.Log(combatOrder.ToString());
    }
    /// <summary>
    /// Sets the active entity within the turn order
    /// </summary>
    public async Task SetActiveEntity()
    {
        Debug.LogError($"{order[activeEntity].GetName()} is going now!");

        // Set the current entity that is currently performing their turn
        currentEntity = order[activeEntity];
        uiHandler.currentEntityTurnText.text = $"{order[activeEntity].GetName()}";

        // If entity has health regen they will regenerate before any adverse weather effects them
        Dictionary<string, object> triggers = AbilityBrain.StartTurnCheck(currentEntity, playerComponent, allyComps, enemyComps);
        ProcHealthRegen(triggers);
        ProcManaRegen();

        // Weather check protocols
        bool entityStatus = await PerformWeatherFunctions(currentEntity);
        if (!entityStatus)
        {
            // This prevents being stuck in battle when all enemies or player entities are destroyed
            if (enemyObjects.All(enemy => !enemy.activeSelf) || (playerComponent.HasDied && allyComps.All(ally => ally.HasDied)))
            {
                DisableBattle();
                return;
            }

            // If entity died to blizzard damage then simply go to the next turn
            previousEntity = currentEntity;
            GoToNextTurn();
            return;
        }

        // Calls for any DOT damage to be done on the entity
        (bool skippingTurn, bool confused)= currentEntity.CallTurnModifierEffects();

        // If the entity is under certain modifiers they will attack an ally of theirs
        if (confused && !skippingTurn)
        {
            if (currentEntity is Player || currentEntity is Ally)
            {
                Entity target = null;
                do
                {
                    int posValue = UnityEngine.Random.Range(-1, allyComps.Length);

                    target = posValue is -1 ? playerComponent : allyComps[posValue];

                } while (target.HasDied || target.GetUniqueID() == currentEntity.GetUniqueID());

                CalculateDamage(false, true, currentEntity, target, 999, 0, null, null, true);
            }
            else if (currentEntity is Enemy enemy)
                AttackLeftSide(enemy.GetDamageDice(), enemy.GetDamageType(), enemy, true).GetAwaiter();
        }
        else if (!skippingTurn)
        {
            if (currentEntity is Player || currentEntity is Ally)
            {
                if (uiHandler.GetUITask() is null && previousEntity != currentEntity)
                    await uiHandler.DisableLeftBattle(TurnCounter == 0);

                for (int i = 0; i < currentEntity.ActionCount; ++i)
                {
                    if (enemyComps.All(enemy => enemy.HasDied))
                        break;

                    // If the entity is already preparing a spell, activate the spell then move on
                    if (currentEntity.IsPreparing.Item1)
                        await ActivatePreparationSpells(currentEntity, PreparationCalls.NextTurn);
                    // The player takes their turn, to which the thread halts until a choice is made
                    else
                        await uiHandler.EnableLeftBattle(currentEntity, triggers);
                }
            }
            else if (currentEntity is Enemy enemy)
            {
                // The enemy takes its turn
                await uiHandler.DisableLeftBattle(TurnCounter == 0);

                for (int i = 0; i < currentEntity.ActionCount; ++i)
                {
                    if (currentEntity.IsPreparing.Item1)
                        await ActivatePreparationSpells(currentEntity, PreparationCalls.NextTurn);
                    // The player takes their turn, to which the thread halts until a choice is made
                    else
                        await enemy.ActivateEnemy();
                }
            }
        }

        // Calculates post turn checks from each of the entities abilities,
        // including the dead entity list
        await AbilityBrain.PostTurnCheck(order, false);
        if (deadEntities != null)
            await AbilityBrain.PostTurnCheck(deadEntities, true);

        // Check system that allies were present in the battle or not
        bool alliesPresentIndicator = allyComps is not null;
        bool allyStateIndicator = alliesPresentIndicator;
        if (alliesPresentIndicator)
        {
            for (int i = 0; i < allyComps.Length; i++)
            {
                if (!allyComps[i].HasDied)
                    break;
                else if (i == allyComps.Length - 1)
                    allyStateIndicator = false;
            }
        }

        // If the battle is still occurring then the next entity is set active,
        // otherwise the battle is disabled and the post screen is created
        if (!stillBattling || (playerObject.activeSelf is false && (!alliesPresentIndicator || !allyStateIndicator)))
        {
            DisableBattle();
            return;
        }

        // If the entity whose turn is about to end has the condition Amped they can go once again
        // Once the entities second turn is performed than the trigger is switched to its opposite once it
        // returns false
        if (order[activeEntity].GatherModList().SmartModCheck("Amped"))
        {
            previousEntity = currentEntity;
            return;
        }

        // Decrements the current entities mods if they fully completed their turn
        currentEntity.DecrementTurnsOnMods();

        // Increments the turn order until an active entity is found then starts the next entities turn
        GoToNextTurn();
        previousEntity = currentEntity;
    }
    /// <summary>
    /// Health regenerates slightly if the current entity has any health regeneration
    /// </summary>
    private void ProcHealthRegen(Dictionary<string, object> triggers)
    {
        // Prevents health regeneration while dead
        if (currentEntity.HasDied)
            return;

        int entityHPRegen = currentEntity.GatherStats().GetStat(EntityStats.Stat.HPRegen, currentEntity.RetrieveMaxHealth());

        if (triggers.ContainsKey("Adrenal Surge"))
            entityHPRegen += (int)triggers["Adrenal Surge"];

        if (currentEntity.GetInventory().GetActiveRelic() != null)
        {
            Relic relic = currentEntity.GetInventory().GetActiveRelic();

            if (relic.ItemId is 2)
                currentEntity.IncreaseHealth(UtilityHandler.RollValue(Dice.DiceR.Six));
        }

        if (entityHPRegen >= 0)
            currentEntity.IncreaseHealth((int)Math.Ceiling(currentEntity.RetrieveMaxHealth() * (entityHPRegen / 100f)));

        currentEntity.StatusChanged();
    }
    private void ProcManaRegen()
    {
        bool bypassRegen = false;
        if (currentEntity.GetInventory().GetActiveRelic() != null)
        {
            Relic relic = currentEntity.GetInventory().GetActiveRelic();

            if (relic.ItemId is 2 && currentEntity.RetrieveMana() > 0 && !currentEntity.GatherModList().SmartModCheck("Unquenched"))
            {
                currentEntity.DecreaseMana(UtilityHandler.RollValue(Dice.DiceR.Four));

                if (currentEntity.RetrieveMana() is 0)
                    currentEntity.AddModToList(AbilityBrain.GetModifierList()["Unquenched"]);

                bypassRegen = true;
            }
        }

        if (currentEntity.GatherStats().GetStat(EntityStats.Stat.MPRegen) is not 0 && !bypassRegen)
        {
            int refillAmount = currentEntity.GatherStats().GetStat(EntityStats.Stat.MPRegen);
            currentEntity.IncreaseMana(refillAmount);
        }

        currentEntity.StatusChanged();
    }
    private async Task<bool> PerformWeatherFunctions(Entity currentEntity)
    {
        if (currentEntity is Player || currentEntity is Ally)
        {
            if (currentEntity.HasDied)
                return false;
        }

        // Modifier check for Impalement and weather conditions
        if (currentEntity.GatherModList().SmartModCheck("Impaled"))
            await ImpalementFunctionality(ClimateManager.Instance.GetWeather());

        if (currentEntity.HasDied)
            return false;

        // If the current weather is a Blizzard, then perform damage on the current turn entity
        if (ClimateManager.Instance.GetWeather() is ClimateManager.Weather.Blizzard)
        {
            int damage = UtilityHandler.RollValue(Dice.DiceR.Four);
            damage = UtilityHandler.ElementWeaknessAndResistChecks(damage, Element.Ice, currentEntity);
            if (currentEntity is Enemy enemy && damage is not 0)
                DamageEnemy(enemy, damage, false, false);
            else if (currentEntity is Ally ally && damage is not 0)
                DamageAlly(ally, damage, false);
            else if (damage is not 0)
                DamagePlayer(damage, false);

            if (damage is not 0)
                uiHandler.RetrieveActionText().UpdateActionTextBasic("Blizzard", currentEntity.GetName(), ActionTextBox.ActionType.Ranged, damage);
            else
                uiHandler.RetrieveActionText().UpdateActionTextBasic("Blizzard", currentEntity.GetName(), ActionTextBox.ActionType.Ranged);

            await uiHandler.RetrieveActionText().GetTextShownStatus();   
        }

        if (currentEntity.HasDied)
            return false;

        return true;

        async Task ImpalementFunctionality(ClimateManager.Weather currentWeather)
        {
            int damageRoll;
            switch (currentWeather)
            {
                case ClimateManager.Weather.Snowy:      // 1D4 of Ice Damage
                    damageRoll = UtilityHandler.RollValue(Dice.DiceR.Four);
                    damageRoll = UtilityHandler.ElementWeaknessAndResistChecks(damageRoll, Element.Ice, currentEntity);
                    break;
                case ClimateManager.Weather.Blizzard:   // 2D4 of Ice Damage
                    damageRoll = UtilityHandler.RollValue(Dice.DiceR.Four, Dice.DiceR.Four);
                    damageRoll = UtilityHandler.ElementWeaknessAndResistChecks(damageRoll, Element.Ice, currentEntity);
                    break;
                case ClimateManager.Weather.Rainy:      // 1D4 of Energy Damage
                    damageRoll = UtilityHandler.RollValue(Dice.DiceR.Four);
                    damageRoll = UtilityHandler.ElementWeaknessAndResistChecks(damageRoll, Element.Energy, currentEntity);
                    break;
                case ClimateManager.Weather.Monsoon:    // 2D12 of Energy Damage (Basically a lightning strike)
                    damageRoll = UtilityHandler.RollValue(Dice.DiceR.Twelve, Dice.DiceR.Twelve);
                    damageRoll = UtilityHandler.ElementWeaknessAndResistChecks(damageRoll, Element.Energy, currentEntity);
                    break;
                default:                                // 1D4 of Normal Damage
                    damageRoll = UtilityHandler.RollValue(Dice.DiceR.Four);
                    damageRoll = UtilityHandler.ElementWeaknessAndResistChecks(damageRoll, Element.Normal, currentEntity);
                    break;
            }

            if (currentEntity is Enemy enemy && damageRoll is not 0)
                DamageEnemy(enemy, damageRoll, false, false);
            else if (currentEntity is Ally ally && damageRoll is not 0)
                DamageAlly(ally, damageRoll, false);
            else if (damageRoll is not 0)
                DamagePlayer(damageRoll, false);

            if (damageRoll is not 0)
            {
                switch (currentWeather)
                {
                    case ClimateManager.Weather.Rainy:
                        uiHandler.RetrieveActionText().UpdateActionTextUnique(12, damageRoll, currentEntity);
                        break;
                    case ClimateManager.Weather.Monsoon:
                        uiHandler.RetrieveActionText().UpdateActionTextUnique(13, damageRoll, currentEntity);
                        break;
                    case ClimateManager.Weather.Snowy:
                        uiHandler.RetrieveActionText().UpdateActionTextUnique(10, damageRoll, currentEntity);
                        break;
                    case ClimateManager.Weather.Blizzard:
                        uiHandler.RetrieveActionText().UpdateActionTextUnique(11, damageRoll, currentEntity);
                        break;
                    default:
                        uiHandler.RetrieveActionText().UpdateActionTextUnique(9, damageRoll, currentEntity);
                        break;
                }
            }
            else
                uiHandler.RetrieveActionText().UpdateActionTextUnique(14, damageRoll, currentEntity);

            await uiHandler.RetrieveActionText().GetTextShownStatus();
        }
    }
    /// <summary>
    /// Determines the next entity to go next in the turn order
    /// </summary>
    private void GoToNextTurn()
    {
        // Takes reference of the current entity before beginning to switch between entities
        Entity previousTurnEntity = order[activeEntity];
        bool disableBattle = false;

        // Loops until an active entity is found
        while (true)
        {
            // Switches to next entity in line
            activeEntity = activeEntity + 1 > order.Count - 1 ? 0 : activeEntity + 1;

            // If the entities game object is active continue the battle with the current entity selected
            if (order[activeEntity].gameObject.activeSelf)
                break;
            // If the loop goes full circle and finds the previous entity that went, send trigger to disable battle
            else if (order[activeEntity] == previousTurnEntity)
            {
                disableBattle = true;
                break;
            }
            // Otherwise keep incrementing the turns to find an active entity to do their turn
            else
                continue;
        }

        // If a full entity loop is performed in the while loop, disable the battle
        if (disableBattle)
            DisableBattle();
        // Otherwise increment the turn since an entity was found
        else
            ++TurnCounter;
    }
    public Entity GatherTargetForEnemy(Enemy enemyRef, bool confused = false)
    {
        if (confused && enemyComps.Length > 1)
        {
            Enemy target;
            do
            {
                target = enemyComps[UnityEngine.Random.Range(0, enemyComps.Length)];

            } while (target.HasDied || target.GetUniqueID() == enemyRef.GetUniqueID());

            return target;
        }
        else if (confused && enemyComps.Length is 1)
            return null;

        if (allyComps.Length is 0 && UniqueTargetCheck(enemyRef, playerComponent))
        {
            if (playerComponent.IsHidden)
                return null;
            else
                return playerComponent;
        }
        else
        {
            Entity target;
            target = CheckForAttentionMods();
            return GatherRandomTarget(target);
        }

        // Gathers a random target from the order list that is not fainted or an enemy
        Entity GatherRandomTarget(Entity target)
        {
            int targetGatherAttempts = 0;
            if (target == null)
            {
                while (true)
                {
                    // Failure to gather a target
                    if (targetGatherAttempts is 5)
                        break;

                    targetGatherAttempts++;
                    int randomTargetValue = UnityEngine.Random.Range(-1, order.Count);

                    if (randomTargetValue is -1)
                    {
                        if (playerComponent.HasDied)
                            continue;
                        else
                            return playerComponent;
                    }
                    else if (order[randomTargetValue].HasDied || order[randomTargetValue] is Enemy || order[randomTargetValue].IsHidden)
                        continue;
                    else
                    {
                        target = order[randomTargetValue];
                        break;
                    }
                }
            }

            return target;
        }
    }
    private bool UniqueTargetCheck(Entity attackerComponent, Entity entityComponent)
    {
        List<Ability> targetAbilities = new List<Ability>(entityComponent.GetInventory().Abilities);
        targetAbilities.AddRange(entityComponent.GetInventory().limitedAbilities);

        Dictionary<int, Ability> abilityList = AbilityBrain.GetAbilityList();

        // Sin Incarnation Check
        if (targetAbilities.Contains(abilityList[121]) && attackerComponent.RetrieveEnemyType().Equals("Demonic"))
            return false;

        // Death and Decay Check
        if (targetAbilities.Contains(abilityList[114]) && attackerComponent.RetrieveEnemyType().Equals("Undead"))
            return false;

        return true;
    }
    /// <summary>
    /// Extracts all of the minion components if available and combines them with their respective true component arrays
    /// </summary>
    /// <param name="allyAbilityChecks">Output of all available ally systems</param>
    /// <param name="enemyAbilityChecks">Output of all available enemy systems</param>
    private void ExtractAllAvailableEntities(out Ally[] allyAbilityChecks, out Enemy[] enemyAbilityChecks)
    {
        Ally[] availableAllies = allyComps.Where(ally => ally.HasDied is false).ToArray();
        Enemy[] availableEnemies = enemyComps.Where(enemy => enemy.HasDied is false).ToArray();

        try
        {
            Ally[] availableMinionAllies = allyMinionComps;
            if (availableMinionAllies.Length is 0)
                throw new InvalidOperationException();

            // Attempt to combine minion component and true ally component
            allyAbilityChecks = new Ally[availableAllies.Length + availableMinionAllies.Length];
            Array.Copy(availableAllies, 0, allyAbilityChecks, 0, availableAllies.Length);
            Array.Copy(availableMinionAllies, 0, allyAbilityChecks, availableAllies.Length, availableMinionAllies.Length);
        }
        catch
        {
            // If exception is thrown simply copy just the base ally components
            allyAbilityChecks = new Ally[availableAllies.Length];
            Array.Copy(availableAllies, 0, allyAbilityChecks, 0, availableAllies.Length);
        }
        try
        {
            Enemy[] availableMinionEnemies = enemyMinionComps;
            if (availableMinionEnemies.Length is 0)
                throw new InvalidOperationException();

            // Attempt to combine minion component and true enemy component
            enemyAbilityChecks = new Enemy[availableEnemies.Length + availableMinionEnemies.Length];
            Array.Copy(availableEnemies, 0, enemyAbilityChecks, 0, availableEnemies.Length);
            Array.Copy(availableMinionEnemies, 0, enemyAbilityChecks, availableEnemies.Length, availableMinionEnemies.Length);
        }
        catch
        {
            // If exception is thrown simply copy just the base enemy components
            enemyAbilityChecks = new Enemy[availableEnemies.Length];
            Array.Copy(availableEnemies, 0, enemyAbilityChecks, 0, availableEnemies.Length);
        }
    }
    private Entity CheckForAttentionMods()
    {
        // Check player
        if (playerObject.activeSelf is true)
        {
            bool playerHas = playerComponent.GatherModList().SmartModCheck("Attention Getter");
            
            if (playerHas)
            {
                int focusedRollValue = UnityEngine.Random.Range(1, 5);

                if (focusedRollValue >= 2)
                    return playerComponent;
            }
        }
        
        // Check true allies
        if (allyComps.Length is not 0)
        {
            for (int i = 0; i < allyComps.Length; ++i)
            {
                if (allyComps[i].GatherModList().SmartModCheck("Attention Getter"))
                {
                    int focusedRollValue = UnityEngine.Random.Range(1, 5);

                    if (focusedRollValue >= 2)
                        return allyComps[i];
                }
            }
        }

        // Check ally minions
        if (allyMinionComps is not null)
        {
            for (int i = 0; i < allyMinionComps.Length; ++i)
            {
                if (allyMinionComps[i].GatherModList().SmartModCheck("Attention Getter"))
                {
                    int focusedRollValue = UnityEngine.Random.Range(1, 5);

                    if (focusedRollValue >= 2)
                        return allyMinionComps[i + allyComps.Length];
                }
            }
        }

        return null;
    }
    /// <summary>
    /// Simpler form of the AttackWithSpell method that damages the target with the value designated
    /// before changing the mana and status of the user of the spell and showing the necessary text on screen
    /// </summary>
    /// <param name="damageValue">Value for the Spell</param>
    /// <param name="spell">The spell being cast</param>
    /// <param name="spellUser">The entity using the spell</param>
    /// <param name="spellTarget">The target of the spell</param>
    /// <param name="endSpell">Indicator if the spell is an advanced spell and has not ended</param>
    /// <returns></returns>
    public async Task AttackWithSpell(int damageValue, Spell spell, Entity spellUser, Entity spellTarget, bool endSpell = true)
    {
        // Check for unique Life Contract trigger
        if (spellUser.GatherModList().SmartModCheck("Life Contract") && damageValue > 0)
            spellUser.GatherModList().IndicateModification("Life Contract", damageValue);

        // Unique to Sorcerer - Obsessive Nature
        if (spellUser is Enemy && !playerComponent.HasDied && playerComponent.GetInventory().Abilities.Contains(AbilityBrain.GetAbilityList()[128]))
            playerComponent.IncreaseExperience(playerComponent.GetInventory().Spells.Contains(spell) ? 50 : 25);

        // Shows the necessary action text for the series of logic that took place
        if (endSpell)
        {
            switch (spell.SpellEffects[0])
            {
                case SpellEffect.Damage:
                    uiHandler.RetrieveActionText().UpdateActionTextSpell(spellUser.GetName(), spellTarget.GetName(), ActionTextBox.ActionType.DamagingSpell, spell, damageValue);
                    if (damageValue <= 0)
                    {
                        await StopPlayerTurn(spellUser);
                        return;
                    }
                    break;
                case SpellEffect.Heal:
                    uiHandler.RetrieveActionText().UpdateActionTextSpell(spellUser.GetName(), spellTarget.GetName(), ActionTextBox.ActionType.HealingSpell, spell, damageValue * -1);
                    if (damageValue <= 0)
                    {
                        await StopPlayerTurn(spellUser);
                        return;
                    }
                    break;
                case SpellEffect.Refill:
                    uiHandler.RetrieveActionText().UpdateActionTextSpell(spellUser.GetName(), spellTarget.GetName(), ActionTextBox.ActionType.RefillingSpell, spell, damageValue * -1);
                    if (damageValue <= 0)
                    {
                        await StopPlayerTurn(spellUser);
                        return;
                    }
                    break;
                case SpellEffect.Buff:
                    uiHandler.RetrieveActionText().UpdateActionTextSpell(spellUser.GetName(), spellTarget.GetName(), ActionTextBox.ActionType.BuffingSpell, spell);
                    await StopPlayerTurn(spellUser);
                    return;
                case SpellEffect.Debuff:
                    uiHandler.RetrieveActionText().UpdateActionTextSpell(spellUser.GetName(), spellTarget.GetName(), ActionTextBox.ActionType.DebuffingSpell, spell);
                    await StopPlayerTurn(spellUser);
                    return;
            }
        }

        // Damages the necessary entity
        if (damageValue is not 0 && spellTarget is Player)
            DamagePlayer(damageValue, false);
        else if (damageValue is not 0 && spellTarget is Enemy enemyTarget)
            DamageEnemy(enemyTarget, damageValue, false, endSpell);
        else if (damageValue is not 0 && spellTarget is Ally allyTarget)
            DamageAlly(allyTarget, damageValue, false);

        await uiHandler.RetrieveActionText().GetTextShownStatus();
        await Task.CompletedTask;

        async Task StopPlayerTurn(Entity spellUser)
        {
            uiHandler.ResetUI();
            if (spellUser is Ally || spellUser is Player)
                DisablePlayerTurn();
            else
                await uiHandler.RetrieveActionText().GetTextShownStatus();

            await Task.CompletedTask;
        }
    }
    /// <summary>
    /// Advanced form of the AttackWithSpell method meant for targetting whole sides
    /// </summary>
    /// <param name="v">Spell value</param>
    /// <param name="spell">Spell being cast</param>
    /// <param name="spellUser">The entity casting the spell</param>
    /// <param name="left">Indicator if the left side is being targetted</param>
    /// <param name="right">Indicator if the right side is being targetted</param>
    /// <returns>The completed task of the state of the spell attack</returns>
    /// <exception cref="DataMisalignedException">Exception is thrown when both left and right are false which indicates malignant data</exception>
    public async Task AttackWithSpell(int[] damageValues, Spell spell, Entity spellUser, bool left, bool right)
    {
        // Check for unique Life Contract trigger
        if (spellUser.GatherModList().SmartModCheck("Life Contract") && damageValues.Any(x => x > 0))
            spellUser.GatherModList().IndicateModification("Life Contract", damageValues.Where(x => x > 0).ToArray());

        // Theory Crafting Copy Ability needs to be placed inline
        if (spellUser is Enemy)
        {
            Inventory playerInven = playerComponent.GetInventory();
            if (playerInven.Abilities.Contains(AbilityBrain.GetAbilityList()[90]) && !playerInven.Spells.Contains(spell))
            {
                int rolledValue = DiceRoller.RollDice(new DHundred());

                if (rolledValue <= 3)
                    playerInven.Add(spell);
            }
        }

        // Cycles through to the necessary action text desired for the circumstance
        if (left && right)
        {
            switch (spell.SpellEffects[0])
            {
                case SpellEffect.Damage:
                    uiHandler.RetrieveActionText().UpdateActionTextSpell(spellUser.GetName(), "everyone", ActionTextBox.ActionType.DamagingSpell, spell, UtilityHandler.Average(damageValues));
                    break;
                case SpellEffect.Heal:
                    uiHandler.RetrieveActionText().UpdateActionTextSpell(spellUser.GetName(), "everyone", ActionTextBox.ActionType.HealingSpell, spell, UtilityHandler.Average(damageValues));
                    break;
                case SpellEffect.Buff:
                    uiHandler.RetrieveActionText().UpdateActionTextSpell(spellUser.GetName(), "everyone", ActionTextBox.ActionType.BuffingSpell, spell);
                    uiHandler.ResetUI();
                    if (spellUser is Player || spellUser is Ally)
                        DisablePlayerTurn();
                    else
                        await uiHandler.RetrieveActionText().GetTextShownStatus();

                    await Task.CompletedTask;
                    return;
                case SpellEffect.Debuff:
                    uiHandler.RetrieveActionText().UpdateActionTextSpell(spellUser.GetName(), "everyone", ActionTextBox.ActionType.DebuffingSpell, spell);
                    uiHandler.ResetUI();
                    if (spellUser is Player || spellUser is Ally)
                        DisablePlayerTurn();
                    else
                        await uiHandler.RetrieveActionText().GetTextShownStatus();

                    await Task.CompletedTask;
                    return;
            }
        }
        else if (left)
        {
            switch (spell.SpellEffects[0])
            {
                case SpellEffect.Damage:
                    uiHandler.RetrieveActionText().UpdateActionTextSpell(spellUser.GetName(), "all Companions", ActionTextBox.ActionType.DamagingSpell, spell, UtilityHandler.Average(damageValues));
                    break;
                case SpellEffect.Heal:
                    uiHandler.RetrieveActionText().UpdateActionTextSpell(spellUser.GetName(), "all Companions", ActionTextBox.ActionType.HealingSpell, spell, UtilityHandler.Average(damageValues));
                    break;
                case SpellEffect.Buff:
                    uiHandler.RetrieveActionText().UpdateActionTextSpell(spellUser.GetName(), "all Companions", ActionTextBox.ActionType.BuffingSpell, spell);
                    uiHandler.ResetUI();
                    if (spellUser is Player || spellUser is Ally)
                        DisablePlayerTurn();
                    else
                        await uiHandler.RetrieveActionText().GetTextShownStatus();

                    await Task.CompletedTask;
                    return;
                case SpellEffect.Debuff:
                    uiHandler.RetrieveActionText().UpdateActionTextSpell(spellUser.GetName(), "all Companions", ActionTextBox.ActionType.DebuffingSpell, spell);
                    uiHandler.ResetUI();
                    if (spellUser is Player || spellUser is Ally)
                        DisablePlayerTurn();
                    else
                        await uiHandler.RetrieveActionText().GetTextShownStatus();

                    await Task.CompletedTask;
                    return;
            }
        }
        else if (right)
        {
            switch (spell.SpellEffects[0])
            {
                case SpellEffect.Damage:
                    uiHandler.RetrieveActionText().UpdateActionTextSpell(spellUser.GetName(), "all Enemies", ActionTextBox.ActionType.DamagingSpell, spell, UtilityHandler.Average(damageValues));
                    break;
                case SpellEffect.Heal:
                    uiHandler.RetrieveActionText().UpdateActionTextSpell(spellUser.GetName(), "all Enemies", ActionTextBox.ActionType.HealingSpell, spell, UtilityHandler.Average(damageValues));
                    break;
                case SpellEffect.Buff:
                    uiHandler.RetrieveActionText().UpdateActionTextSpell(spellUser.GetName(), "all Enemies", ActionTextBox.ActionType.BuffingSpell, spell);
                    uiHandler.ResetUI();
                    if (spellUser is Player || spellUser is Ally)
                        DisablePlayerTurn();
                    else
                        await uiHandler.RetrieveActionText().GetTextShownStatus();

                    await Task.CompletedTask;
                    return;
                case SpellEffect.Debuff:
                    uiHandler.RetrieveActionText().UpdateActionTextSpell(spellUser.GetName(), "all Enemies", ActionTextBox.ActionType.DebuffingSpell, spell);
                    uiHandler.ResetUI();
                    if (spellUser is Player || spellUser is Ally)
                        DisablePlayerTurn();
                    else
                        await uiHandler.RetrieveActionText().GetTextShownStatus();

                    await Task.CompletedTask;
                    return;
            }
        }

        // Damages the designated side first
        if (left && spell.SpellEffects[0] is not SpellEffect.Heal)
        {
            if (!playerComponent.HasDied)
            {
                if (damageValues[0] is not 0 && UniqueSpellDamageChecks(spell, playerComponent))
                    DamagePlayer(damageValues[0], false);
            }

            int counter = 0;

            Ally[] aliveAllies = allyComps.Where(ally => ally.HasDied is false).ToArray();

            if (allyMinionComps != null)
            {
                if (allyMinionComps.Length > 0)
                    aliveAllies.Concat(allyMinionComps.Where(allyMinion => allyMinion.HasDied is false));
            }

            foreach (Ally ally in aliveAllies)
            {
                if (damageValues[counter + 1] is not 0 && UniqueSpellDamageChecks(spell, ally))
                {
                    try
                    {
                        DamageAlly(ally, damageValues[counter + 1], false);
                    }
                    catch { Debug.Log("error caught"); }
                }

                ++counter;
            }
        }
        if (right && spell.SpellEffects[0] is not SpellEffect.Heal)
        {
            int counter = 0;

            List<Enemy> aliveEnemies = enemyComps.Where(enemy => enemy.HasDied is false).ToList();

            if (enemyMinionComps != null)
            {
                if (enemyMinionComps.Length > 0)
                    aliveEnemies.AddRange(enemyMinionComps);
            }

            foreach (Enemy enemy in aliveEnemies)
            {
                if (damageValues[counter] is not 0 && UniqueSpellDamageChecks(spell, enemy))
                {
                    try
                    {
                        DamageEnemy(enemy, damageValues[counter], false);
                    }
                    catch { Debug.Log("error caught"); }
                }

                ++counter;
            }
        }

        await uiHandler.RetrieveActionText().GetTextShownStatus();
        await Task.CompletedTask;
    }
    public async Task FailedSpellCall(Spell spellFailure)
    {
        uiHandler.RetrieveActionText().SignalFailedSpellText(spellFailure);
        uiHandler.ResetUI();

        if (currentEntity is Player || currentEntity is Ally)
            DisablePlayerTurn();

        await uiHandler.RetrieveActionText().GetTextShownStatus();
        await Task.CompletedTask;
    }
    private bool UniqueSpellDamageChecks(Spell spellToCheck, Entity entity)
    {
        bool output = true;
        switch (spellToCheck.SpellID)
        {
            case 23:    // Order: Rupture only affects people inflicted with 'Sick'
                if (!entity.GatherModList().SmartModCheck("Sick"))
                    output = false;
                break;
            default:
                break;
        }

        return output;
    }
    /// <summary>
    /// Damages the target with the value of the consumable while also calling for the action text
    /// </summary>
    /// <param name="damageValue">The value of the item rolls</param>
    /// <param name="consumable">The consumable being used</param>
    /// <param name="itemUser">The entity user of the consumable</param>
    /// <param name="itemTarget">The entity target of the consumable</param>
    /// <returns>The completed state when the damage is carried through</returns>
    public async Task AttackWithItem(int damageValue, Consumable consumable, Entity itemUser, Entity itemTarget)
    {
        if (damageValue is not 0 && itemTarget is Player)
            DamagePlayer(damageValue, false);
        else if (damageValue is not 0 && itemTarget is Enemy)
            DamageEnemy(itemTarget as Enemy, damageValue, false);
        else if (damageValue is not 0 && itemTarget is Ally)
            DamageAlly(itemTarget as Ally, damageValue, false);

        uiHandler.RetrieveActionText().UpdateActionTextItem(itemUser.GetName(), itemTarget, consumable, ActionTextBox.ActionType.DamagingItemOnSingle, damageValue);

        await uiHandler.RetrieveActionText().GetTextShownStatus();
        await Task.CompletedTask;
    }
#nullable enable
    /// <summary>
    /// Damages the necessary targets based on parameters passed, i.e. left damages all allies and players, right damages all enemies
    /// </summary>
    /// <param name="damageValue">The value of the item rolls</param>
    /// <param name="consumable">The consumable being used</param>
    /// <param name="itemUser">The entity user of the consumable</param>
    /// <param name="itemTarget">The entity target of the consumable</param>
    /// <param name="left">Indicator if all of the companions side is affected</param>
    /// <param name="right">Indicator if all of the enemies side is affected</param>
    /// <returns>The completed state when the damage is carried through</returns>
    /// <exception cref="DataMisalignedException">Exception is thrown when left and right are false which indicates malignant data</exception>
    public async Task AttackWithItem(int damageValue, Consumable consumable, Entity itemUser, Entity itemTarget, bool left, bool right)
    {
        if (left && right)
        {
            if (damageValue is not 0)
            {
                DamagePlayer(damageValue, false);
                foreach (Ally a in allyComps)
                    DamageAlly(a, damageValue, false);
                foreach (Enemy e in enemyComps)
                    DamageEnemy(e, damageValue, false);
            }

            uiHandler.RetrieveActionText().UpdateActionTextItem(itemUser.GetName(), itemTarget, consumable, ActionTextBox.ActionType.DamagingItemOnAll, damageValue);
        }
        // Damages the designated side first
        else if (left)
        {
            if (damageValue is not 0)
            {
                DamagePlayer(damageValue, false);
                foreach (Ally a in allyComps)
                    DamageAlly(a, damageValue, false);
            }

            uiHandler.RetrieveActionText().UpdateActionTextItem(itemUser.GetName(), itemTarget, consumable, ActionTextBox.ActionType.DamagingItemOnType, damageValue);
        }
        else if (right)
        {
            if (damageValue is not 0)
                foreach (Enemy e in enemyComps)
                    DamageEnemy(e, damageValue, false);

            uiHandler.RetrieveActionText().UpdateActionTextItem(itemUser.GetName(), itemTarget, consumable, ActionTextBox.ActionType.DamagingItemOnType, damageValue);
        }
        else
            throw new DataMisalignedException($"The consumable has flawed information for attacking - Consumable ({consumable.ItemName}) - Left Ind {left} - Right Ind {right}");

        await uiHandler.RetrieveActionText().GetTextShownStatus();
        await Task.CompletedTask;
    }
#nullable disable
    private void ArmorTriggerSearch(Dictionary<string, (List<string>, List<object>)> triggers, ref int armorValue, ref int toHitRoll)
    {
        if (triggers.ContainsKey("AddArmor"))
            armorValue = UtilityHandler.AddArmorDecipher(triggers, armorValue);

        if (triggers.ContainsKey("MinusArmor"))
            armorValue = UtilityHandler.MinusArmorDecipher(triggers, armorValue);

        if (triggers.ContainsKey("ToHitAdd"))
            toHitRoll = UtilityHandler.ToHitAddDecipher(triggers, toHitRoll);

        // The value component should be negative to begin with
        if (triggers.ContainsKey("ToHitMinus"))
            toHitRoll = UtilityHandler.ToHitMinusDecipher(triggers, toHitRoll);
    }
    private int DamageTriggerSearch(Entity target, Entity attacker, Dictionary<string, (List<string>, List<object>)> triggers, int value, bool isCrit)
    {
        if (triggers is null)
            return value;

        // Doubles the damage
        if (triggers.ContainsKey("DoubleDamage"))
        {
            foreach (var item in triggers["DoubleDamage"].Item2)
                value *= 2;
        }

        // Halves the damage
        if (triggers.ContainsKey("HalfCrits") && isCrit)
        {
            foreach (var item in triggers["HalfCrits"].Item2)
                value /= 2;
        }

        // Add more damage
        if (triggers.ContainsKey("AddDamageValue"))
        {
            int counterIndex = 0;
            foreach (var item in triggers["AddDamageValue"].Item2)
            {
                if (item is float fVal)
                {
                    int damage = (int)Math.Floor(fVal * value);
                    DetermineValue(damage, counterIndex);
                }
                else if (item is int iVal)
                {
                    int damage = iVal;
                    DetermineValue(damage, counterIndex);
                }
                else if (item is Dice dVal)
                {
                    int damage = DiceRoller.RollDice(dVal);
                    DetermineValue(damage, counterIndex);
                }
                else if (item is Dice[] dVals)
                {
                    int damage = DiceRoller.RollDice(dVals);
                    DetermineValue(damage, counterIndex);
                }
                else if (item is Dice.DiceR d)
                {
                    int damage = UtilityHandler.RollValue(d);
                    DetermineValue(damage, counterIndex);
                }
                else if (item is Dice.DiceR[] ds)
                {
                    int damage = UtilityHandler.RollValue(ds);
                    DetermineValue(damage, counterIndex);
                }
                else
                    throw new TypeLoadException();

                ++counterIndex;
            }
        }

        // Take away damage
        if (triggers.ContainsKey("MinusDamageValue"))
        {
            foreach (var item in triggers["MinusDamageValue"].Item2)
            {
                // Additive, item values should be negative to begin with, if strange values check in AbilityBrain
                if (item is float fVal)
                    value += (int)Math.Ceiling(value * fVal);
                else if (item is int iVal)
                    value += iVal;
                else if (item is Dice dval)
                    value += DiceRoller.RollDice(dval);
                else if (item is Dice[] dVals)
                    value += DiceRoller.RollDice(dVals);
                else if (item is Dice.DiceR d)
                    value += UtilityHandler.RollValue(d);
                else if (item is Dice.DiceR[] ds)
                    value += UtilityHandler.RollValue(ds);
                else if (item is List<object> listOfvalues)
                    value += (int)listOfvalues[0];
                else
                    throw new TypeLoadException();
            }
        }
        

        // Percentage of damage back to the attacker
        if (triggers.ContainsKey("DamageBack"))
        {
            int damageBack = 0;
            foreach (var item in triggers["DamageBack"].Item2)
            {
                if (item is float fVal)
                    damageBack += (int)Math.Floor(value * fVal);
                else if (item is int iVal)
                    damageBack += iVal;
                else if (item is Dice dVal)
                    damageBack += DiceRoller.RollDice(dVal);
                else if (item is Dice[] dVals)
                    damageBack += DiceRoller.RollDice(dVals);
                else if (item is Dice.DiceR d)
                    damageBack += UtilityHandler.RollValue(d);
                else if (item is Dice.DiceR[] ds)
                    damageBack += UtilityHandler.RollValue(ds);
                else
                    throw new TypeLoadException();
            }

            if (attacker is Enemy enemy)
                DamageEnemy(enemy, damageBack, false, false);
            else if (attacker is Ally ally)
                DamageAlly(ally, damageBack, false);
            else
                DamagePlayer(damageBack, false);
        }

        // Scavenge Functionality
        if (triggers.ContainsKey("Scavenge") && !attacker.HasDied)
        {
            int healthIncrease = 0;

            foreach (var item in triggers["Scavenge"].Item2)
            {
                if (item is float fVal)
                    healthIncrease += (int)Math.Floor(value * fVal);
                else if (item is int iVal)
                    healthIncrease += iVal;
                else if (item is Dice dVal)
                    healthIncrease += DiceRoller.RollDice(dVal);
                else if (item is Dice[] dVals)
                    healthIncrease += DiceRoller.RollDice(dVals);
                else if (item is Dice.DiceR d)
                    healthIncrease += UtilityHandler.RollValue(d);
                else if (item is Dice.DiceR[] ds)
                    healthIncrease += UtilityHandler.RollValue(ds);
                else
                    throw new TypeLoadException();
            }

            attacker.IncreaseHealth(healthIncrease);
            attacker.StatusChanged();
        }

        return value;

        // Check function to determine the type of damage being inflicted
        void DetermineValue(int damage, int counterIndex)
        {
            try
            {
                value += UtilityHandler.ElementWeaknessAndResistChecks(damage, (Element)triggers["AddDamageType"].Item2[counterIndex], target);
            }
            catch
            {
                value += UtilityHandler.WeaponTypeChecks(damage, attacker, target);
            }
        }
    }
    /// <summary>
    /// Disables the enemy battling portion of the Encounter
    /// </summary>
    /// <param name="ran">Trigger if the player ran away from the enemies</param>
    public async void DisableBattle(bool ran = false)
    {
        Globals.IsBossEncounter = false;
        uiHandler.currentEntityTurnText.enabled = false;

        // Destroys all minions
        ClearTemporaryMinions();
        uiHandler.ClearTempMinions();
        GeneralUI.Instance.EliminateTempGUIs();

        // Checks if all the allies have fainted
        bool allFainted = true;
        for (int i = 0; i < allyObjects.Length; i++)
        {
            if (!allyObjects[i].GetComponent<Ally>().HasDied)
            {
                allFainted = false;
                break;
            }
        }

        // If all of the companions pass out/die than the game over screen will pop up
        if (playerComponent.HasDied && allFainted)
        {
            SceneManager.LoadScene(2);
            return;
        }
        else
        {
            if (playerComponent.HasDied)
                playerComponent.Revive(true);

            foreach (Ally ally in allyComps)
            {
                if (ally.HasDied)
                    ally.Revive(true);
            }
        }

        await AbilityBrain.PostBattleChecks(playerComponent, allyComps);

        bountyEnabled = null;
        uiHandler.GiveExperience(playerComponent, allyComps);

        // Deactivates all the companion game objects
        playerComponent.DeactivateVisually();
        DeactivateAllAllies();

        // Creates post battle buttons determined by if the player ran
        uiHandler.CreatePostBattleButtons(ran);
    }
    /// <summary>
    /// Injects information into the spell manager to begin the usage of a spell
    /// </summary>
    /// <param name="spell">The spell being used</param>
    /// <param name="entity">The entity using the spell</param>
    public async Task InjectIntoSpellManager(Spell spell, Entity entity, bool noChoose = false)
    {
        // Guards spell activation if the entity attempting to cast a spell is silenced
        if (entity.GatherModList().SmartModCheck("Silenced"))
            return;

        if (!noChoose)
        {
            ExtractAllAvailableEntities(out Ally[] allyComponents, out Enemy[] enemyComponents);

            if (playerObject.activeSelf == true)
            {
                await spellManager.BeginSpellProcess(entity, spell, playerComponent, enemyComponents, allyComponents, this);

                if (entity is Enemy eRef)
                {
                    bool anyKills = allyComponents.Any(ally => ally.HasDied) || playerObject.activeSelf is false;

                    if (anyKills)
                        eRef.GetAnimationHandler().PlayKilledAllySound();
                }
            }
            else
            {
                await spellManager.BeginSpellProcess(entity, spell, null, enemyComponents, allyComponents, this);

                if (entity is Enemy eRef)
                {
                    bool anyKills = allyComponents.Any(ally => ally.HasDied);
                    if (anyKills)
                        eRef.GetAnimationHandler().PlayKilledAllySound();
                }
            }
        }

        // This call is primarily meant for the Unstable Magical Core Ability for Wild Magic instances
        if (noChoose)
        {
            if (spell.SpellEffects.Contains(SpellEffect.Damage) || spell.SpellEffects.Contains(SpellEffect.Debuff))
                spellManager.ChooseTarget(enemyComps[UnityEngine.Random.Range(0, enemyComps.Length)]);
            else
            {
                List<Entity> entitiesToChoose = new List<Entity>();
                if (playerObject.activeSelf)
                    entitiesToChoose.Add(playerComponent);
                foreach (Ally ally in allyComps)
                    entitiesToChoose.Add(ally);
                spellManager.ChooseTarget(entitiesToChoose[UnityEngine.Random.Range(0, entitiesToChoose.Count)]);
            }
        }
    }
    /// <summary>
    /// Injects a spell and enemy into the spell manager for the battle handler when a spell is preparing to be used by an enemy
    /// </summary>
    /// <param name="spell">The spell being casted</param>
    /// <param name="entity">The enemy casting the spell</param>
    /// <returns>The completed state when an enemy uses a spell</returns>
    public async Task AwaitEnemySpellUse(Spell spell, Entity entity)
        => await InjectIntoSpellManager(spell, entity);
    
    /// <summary>
    /// Unique Call for Action Text for spells determined by the user and target
    /// </summary>
    /// <param name="user">Name of the object that used the spell</param>
    /// <param name="target">Name of the target of the spell</param>
    /// <param name="spell">The spell being used</param>
    /// <param name="value">Heal amount, damage amount, 0 otherwise</param>
    public async void CallSpellActionText(string user, string target, Spell spell, int value = 0, bool failed = false)
    {
        if (failed)
            uiHandler.RetrieveActionText().UpdateActionTextSpell(user, target, ActionTextBox.ActionType.SpellFailed, spell);
        else if (spell.SpellEffects.Contains(SpellEffect.Heal))
            uiHandler.RetrieveActionText().UpdateActionTextSpell(user, target, ActionTextBox.ActionType.HealingSpell, spell, value);
        else if (spell.SpellEffects.Contains(SpellEffect.Debuff))
            uiHandler.RetrieveActionText().UpdateActionTextSpell(user, target, ActionTextBox.ActionType.DebuffingSpell, spell);
        else if (spell.SpellEffects.Contains(SpellEffect.Buff))
            uiHandler.RetrieveActionText().UpdateActionTextSpell(user, target, ActionTextBox.ActionType.BuffingSpell, spell);
        else
            uiHandler.RetrieveActionText().UpdateActionTextSpell(user, target, ActionTextBox.ActionType.DamagingSpell, spell, value);

        await uiHandler.RetrieveActionText().GetTextShownStatus();
        await Task.CompletedTask;
    }
    /// <summary>
    /// Unique Call for Action Text for spells determined by which side is fully affected
    /// </summary>
    /// <param name="user">The entity casting the spell</param>
    /// <param name="left">Indicator if the companions side is being targetted</param>
    /// <param name="right">Indicator if the enemy side is being targetted</param>
    /// <param name="spell">The spell being casted</param>
    /// <param name="value">The value for the spell</param>
    public async void CallSpellActionText(Entity user, bool left, bool right, SpellEffect spellEffect, Spell spell, int value = 0)
    {
        if (left)
        {
            switch (spellEffect)
            {
                case SpellSO.SpellEffect.Damage:
                    uiHandler.RetrieveActionText().UpdateActionTextSpell(user.GetName(), "all Companions", ActionTextBox.ActionType.DamagingSpell, spell, value);
                    break;
                case SpellSO.SpellEffect.Heal:
                    uiHandler.RetrieveActionText().UpdateActionTextSpell(user.GetName(), "all Companions", ActionTextBox.ActionType.HealingSpell, spell, value);
                    break;
                case SpellSO.SpellEffect.Buff:
                    uiHandler.RetrieveActionText().UpdateActionTextSpell(user.GetName(), "all Companions", ActionTextBox.ActionType.BuffingSpell, spell);
                    break;
                case SpellSO.SpellEffect.Debuff:
                    uiHandler.RetrieveActionText().UpdateActionTextSpell(user.GetName(), "all Companions", ActionTextBox.ActionType.DebuffingSpell, spell);
                    break;
            }   
        }
        else if (right)
        {
            switch (spellEffect)
            {
                case SpellSO.SpellEffect.Damage:
                    uiHandler.RetrieveActionText().UpdateActionTextSpell(user.GetName(), "all Enemies", ActionTextBox.ActionType.DamagingSpell, spell, value);
                    break;
                case SpellSO.SpellEffect.Heal:
                    uiHandler.RetrieveActionText().UpdateActionTextSpell(user.GetName(), "all Enemies", ActionTextBox.ActionType.HealingSpell, spell, value);
                    break;
                case SpellSO.SpellEffect.Buff:
                    uiHandler.RetrieveActionText().UpdateActionTextSpell(user.GetName(), "all Enemies", ActionTextBox.ActionType.BuffingSpell, spell);
                    break;
                case SpellSO.SpellEffect.Debuff:
                    uiHandler.RetrieveActionText().UpdateActionTextSpell(user.GetName(), "all Enemies", ActionTextBox.ActionType.DebuffingSpell, spell);
                    break;
            }
        }

        await uiHandler.RetrieveActionText().GetTextShownStatus();
        await Task.CompletedTask;
    }
#nullable enable
    /// <summary>
    /// Unique call for action text when using an item
    /// </summary>
    /// <param name="user">The name of the user of the item</param>
    /// <param name="target">The target of the item when applicable</param>
    /// <param name="consumable">The consumable that is being used</param>
    /// <param name="grouping">Indicator of what is being targetted</param>
    /// <param name="value">The value of the damage or healing being done</param>
    public async void CallItemActionText(string user, Entity? target, Consumable consumable, Target.Targetted grouping = Target.Targetted.Single, int value = 0)
    {
        switch (grouping)
        {
            case Target.Targetted.Single:
                switch (consumable.Effects[0])
                {
                    case ConsumableSO.Effect.Heal:
                        uiHandler.RetrieveActionText().UpdateActionTextItem(user, target, consumable, ActionTextBox.ActionType.HealingItemOnSingle, value);
                        break;
                    case ConsumableSO.Effect.Refill:
                        uiHandler.RetrieveActionText().UpdateActionTextItem(user, target, consumable, ActionTextBox.ActionType.RefillingItemOnSingle, value);
                        break;
                    case ConsumableSO.Effect.Buff: 
                        uiHandler.RetrieveActionText().UpdateActionTextItem(user, target, consumable, ActionTextBox.ActionType.BuffingItemOnSingle);
                        break;
                    case ConsumableSO.Effect.Debuff:
                        uiHandler.RetrieveActionText().UpdateActionTextItem(user, target, consumable, ActionTextBox.ActionType.DebuffingItemOnSingle);
                        break;
                    case ConsumableSO.Effect.Damage:
                        uiHandler.RetrieveActionText().UpdateActionTextItem(user, target, consumable, ActionTextBox.ActionType.DamagingItemOnSingle, value);
                        break;
                }
                break;
            case Target.Targetted.AllOfType:
                switch (consumable.Effects[0])
                {
                    case ConsumableSO.Effect.Heal:
                        uiHandler.RetrieveActionText().UpdateActionTextItem(user, target, consumable, ActionTextBox.ActionType.HealingItemOnType, value);
                        break;
                    case ConsumableSO.Effect.Refill:
                        uiHandler.RetrieveActionText().UpdateActionTextItem(user, target, consumable, ActionTextBox.ActionType.RefillingItemOnType, value);
                        break;
                    case ConsumableSO.Effect.Buff:
                        uiHandler.RetrieveActionText().UpdateActionTextItem(user, target, consumable, ActionTextBox.ActionType.BuffingItemOnType);
                        break;
                    case ConsumableSO.Effect.Debuff:
                        uiHandler.RetrieveActionText().UpdateActionTextItem(user, target, consumable, ActionTextBox.ActionType.DebuffingItemOnType);
                        break;
                    case ConsumableSO.Effect.Damage:
                        uiHandler.RetrieveActionText().UpdateActionTextItem(user, target, consumable, ActionTextBox.ActionType.DamagingItemOnType, value);
                        break;
                }
                break;
            case Target.Targetted.All:
                switch (consumable.Effects[0])
                {
                    case ConsumableSO.Effect.Heal:
                        uiHandler.RetrieveActionText().UpdateActionTextItem(user, target, consumable, ActionTextBox.ActionType.HealingItemOnAll, value);
                        break;
                    case ConsumableSO.Effect.Refill:
                        uiHandler.RetrieveActionText().UpdateActionTextItem(user, target, consumable, ActionTextBox.ActionType.RefillingItemOnAll, value);
                        break;
                    case ConsumableSO.Effect.Buff:
                        uiHandler.RetrieveActionText().UpdateActionTextItem(user, target, consumable, ActionTextBox.ActionType.BuffingItemOnAll);
                        break;
                    case ConsumableSO.Effect.Debuff:
                        uiHandler.RetrieveActionText().UpdateActionTextItem(user, target, consumable, ActionTextBox.ActionType.DebuffingItemOnAll);
                        break;
                    case ConsumableSO.Effect.Damage:
                        uiHandler.RetrieveActionText().UpdateActionTextItem(user, target, consumable, ActionTextBox.ActionType.DamagingItemOnAll, value);
                        break;
                }
                break;
        }

        await uiHandler.RetrieveActionText().GetTextShownStatus();
        await Task.CompletedTask;
    }
#nullable disable
    /// <summary>
    /// Disables the interactivity of the spells while choosing a target for a spell that was already chosen
    /// </summary>
    public void AwaitSpellChoice(Entity entity) 
        => uiHandler.DisableSpellButtonInteractivity(entity);
    /// <summary>
    /// Disables the interactivity of the item buttons while choosing a target when necessary
    /// </summary>
    /// <param name="entity">The entity that is choosing</param>
    public void AwaitConsumableChoice(Entity entity) 
        => uiHandler.DisableItemButtonInteractivity(entity);
    /// <summary>
    /// Cancels the spell attempting to be used
    /// </summary>
    public void CancelSpellUse() 
        => spellManager.Cancel();
    /// <summary>
    /// Cancels the item usage and cancels the tasks in the consumable manager
    /// </summary>
    public void CancelItemUse() 
        => consumableManager.Cancel();
    /// <summary>
    /// Activates the consumable selected and prepares to utilize it
    /// </summary>
    /// <param name="activeInven">The active inventory that the consumable is being used from</param>
    /// <param name="consumable">The consumable that is being used</param>
    /// <param name="user">The user of the consumable</param>
    public async void ActivateConsumable(Inventory activeInven, Consumable consumable, Entity user)
    {
        ExtractAllAvailableEntities(out Ally[] allyComponents, out Enemy[] enemyComponents);

        if (playerObject.activeSelf == true)
            consumableManager.BeginConsumableProcess(user, consumable, playerComponent, enemyComponents, allyComponents, this);
        else
            consumableManager.BeginConsumableProcess(user, consumable, null, enemyComponents, allyComponents, this);

        // Waits for the consumable manager to complete the task state, or for the task state to be canceled
        while (consumableManager.GetUsedConsumableState() is false && !consumableManager.GetConsumableTaskState())
            await Task.Yield();

        // If the consumable was used than it is removed from the active inventory
        bool check = consumableManager.GetUsedConsumableState();
        if (check)
            activeInven.Remove(consumable, 1);
    }
    /// <summary>
    /// Revives the entity indicated by switching the game object back on and reimplementing their turn order
    /// </summary>
    /// <param name="entity">The entity to be revived</param>
    public void Revive(Entity entity)
    {
        if (entity is Player player)
        {
            playerObject.SetActive(true);
            deadEntities.Remove(player);
        }
        else if (entity is Ally)
        {
            for (int i = 0; i < deadEntities.Count; i++)
            {
                if (deadEntities[i] is Ally ally && ally == entity as Ally)
                {
                    deadEntities[i].gameObject.SetActive(true);
                    deadEntities.RemoveAt(i);
                }
            }
        }
        else
        {
            for (int i = 0; i < deadEntities.Count; i++)
            {
                if (deadEntities[i].TryGetComponent(out Enemy enemy))
                {
                    enemy.gameObject.SetActive(true);
                    deadEntities.RemoveAt(i);
                }
            }
        }
    }
    /// <summary>
    /// Creates a temporary minion for one of the sides
    /// </summary>
    /// <param name="minion">The minion game object to summon</param>
    /// <param name="isLeft">Indicator if the minion being summoned is an Ally, true is Ally, false is Enemy</param>
    /// <returns></returns>
    public bool CreateMinion(GameObject minion, bool isLeft)
    {
        // When no free spots are available just return false and indicate it was a failed spell cast
        if ((isLeft && allyComps.Length is 3) || (!isLeft && enemyComps.Length is 4))
            return false;

        // If the minion comps don't exist then simply continue on, since the prior check was false
        try
        {
            int trueAllyLength = allyComps.Length;
            if (isLeft && trueAllyLength + allyMinionComps.Length is 3)
                return false;
        }
        catch { }

        try
        {
            int trueEnemyLength = enemyComps.Length;
            if (!isLeft && trueEnemyLength + enemyMinionComps.Length is 4)
                return false;
        }
        catch { }

        // Create Temp Minion
        GameObject createdMinion = pHandler.InjectMinion(minion, isLeft);
        int turnValue;
        if (isLeft)
        {
            if (allyMinionComps is null || allyMinionObjects is null)
            {
                allyMinionComps = new Ally[1];
                allyMinionObjects = new GameObject[1];
            }
            else
            {
                Array.Resize(ref allyMinionComps, allyMinionComps.Length + 1);
                Array.Resize(ref allyMinionObjects, allyMinionObjects.Length + 1);
            }

            Ally allyComp           = createdMinion.GetComponent<Ally>();
            allyComp.IsMinion       = true;
            uiHandler.InjectTempMinion(allyComp);
            allyMinionObjects[^1]   = createdMinion;
            allyMinionComps[^1]     = allyComp;
            turnValue               = allyComp.RollOrderValue();
            combatOrder.CallOrderInitiative(allyComp, turnValue);
        }
        else
        {
            if (enemyMinionComps is null || enemyMinionObjects is null)
            {
                enemyMinionComps    = new Enemy[1];
                enemyMinionObjects  = new GameObject[1];
            }
            else
            {
                Array.Resize(ref enemyMinionComps, enemyMinionComps.Length + 1);
                Array.Resize(ref enemyMinionObjects, enemyMinionObjects.Length + 1);
            }

            Enemy enemyComp         = createdMinion.GetComponent<Enemy>();
            enemyComp.InjectHandler(this);
            enemyComp.IsMinion      = true;
            uiHandler.InjectTempMinion(enemyComp);
            enemyMinionObjects[^1]  = createdMinion;
            enemyMinionComps[^1]    = enemyComp;
            turnValue               = enemyComp.RollOrderValue();
            combatOrder.CallOrderInitiative(enemyComp, turnValue);
        }

        // Re-sort the combat order
        order = combatOrder.SortOrder();

        // Make sure that the current entity is still selected for the set active entity method
        foreach (Entity entity in order)
        {
            if (entity.GetUniqueID() == currentEntity.GetUniqueID())
            {
                activeEntity = order.IndexOf(entity);
                break;
            }
        }

        // If it is a friendly minion create a temporary GUI
        if (isLeft)
            GeneralUI.Instance.CreateTempGUI(createdMinion.GetComponent<Ally>());

        return true;
    }
    /// <summary>
    /// All of the minions summoned this battle are destroyed and wiped
    /// </summary>
    private void ClearTemporaryMinions()
    {
        // Try loop is used in case the Enemy Minion Objects wasn't initialized
        try
        {
            for (int i = 0; i < enemyMinionObjects.Length; ++i)
                Destroy(enemyMinionObjects[i]);
        }
        catch { }

        // See above
        try
        {
            for (int i = 0; i < allyMinionObjects.Length; ++i)
                Destroy(allyMinionObjects[i]);
        }
        catch { }

        enemyMinionObjects  = null;
        enemyMinionComps    = null;
        allyMinionObjects   = null;
        allyMinionComps     = null;
    }
    /// <summary>
    /// Destroys the minion object and minion component in the arrays
    /// </summary>
    /// <param name="minionComp">The minion component to eliminate</param>
    /// <exception cref="DataMisalignedException">Exception thrown when the Lengths of the ally or enemy minion objects and components don't match</exception>
    private void DestroyMinionInstance(Entity minionComp)
    {
        bool isAlly = minionComp is Ally;

        // Both ally minion arrays or enemy minion arrays should match up in length

        // Ally destruction protocol
        if (isAlly)
        {
            if (allyMinionObjects.Length != allyMinionComps.Length)
                throw new DataMisalignedException("The Length of the Ally Minion Objects and the Ally Minion Components do NOT match! Error will occur if destructing instance.");

            int objectLength = allyMinionObjects.Length;
            for (int i = 0; i < objectLength; ++i)
            {
                if (allyMinionComps[i].GetUniqueID() == minionComp.GetUniqueID())
                {
                    // Remove from the order
                    order.Remove(minionComp);

                    // Collect the garbage value
                    GameObject garbageValue         = allyMinionObjects[i];
                    Ally allyComponent              = allyMinionComps[i];

                    // Cycle through all minions pass the point that is being nullified
                    // and move their values down the index
                    for (int k = i; k < objectLength - 1; ++k)
                    {
                        allyMinionComps[k]          = allyMinionComps[k + 1];
                        allyMinionComps[k + 1]      = null;

                        allyMinionObjects[k]        = allyMinionObjects[k + 1];
                        allyMinionObjects[k + 1]    = null;
                    }

                    // Shrink the arrays and destroy the garbage value
                    Array.Resize(ref allyMinionObjects, objectLength - 1);
                    Array.Resize(ref allyMinionComps, objectLength - 1);

                    if (allyMinionComps.Length is 0)
                    {
                        allyMinionComps     = null;
                        allyMinionObjects   = null;
                    }

                    uiHandler.DestroyTempMinion(allyComponent);
                    Destroy(garbageValue);
                }
            }
        }
        // Enemy destruction protocol
        else
        {
            if (enemyMinionObjects.Length != enemyMinionComps.Length)
                throw new DataMisalignedException("The Length of the Enemy Minion Objects and the Enemy Minion Components do NOT match! Error will occur if destructing instance.");

            int objectLength = enemyMinionObjects.Length;
            for (int i = 0; i < objectLength; ++i)
            {
                if (enemyMinionComps[i].GetUniqueID() == minionComp.GetUniqueID())
                {
                    // Remove from the order
                    order.Remove(minionComp);

                    // Collect the garbage value
                    GameObject garbageValue         = enemyMinionObjects[i];
                    Enemy enemyComponent            = enemyMinionComps[i];

                    // Cycle through all minions pass the point that is being nullified
                    // and move their values down the index
                    for (int k = i; k < objectLength - 1; ++k)
                    {
                        enemyMinionComps[k] = enemyMinionComps[k + 1];
                        enemyMinionComps[k + 1] = null;

                        enemyMinionObjects[k] = enemyMinionObjects[k + 1];
                        enemyMinionObjects[k + 1] = null;
                    }

                    // Shrink the arrays and destroy the garbage value
                    Array.Resize(ref enemyMinionObjects, objectLength - 1);
                    Array.Resize(ref enemyMinionComps, objectLength - 1);

                    if (enemyMinionComps.Length is 0)
                    {
                        enemyMinionComps = null;
                        enemyMinionObjects = null;
                    }

                    uiHandler.DestroyTempMinion(enemyComponent);
                    Destroy(garbageValue);
                }
            }
        }

        // Re-establish the correct entity in the order
        foreach (Entity entity in order)
        {
            if (entity.GetUniqueID() == currentEntity.GetUniqueID())
            {
                activeEntity = order.IndexOf(entity);
                break;
            }
        }
    }
    public Task DealDamageToLeftRandom(int damageValue)
    {
        List<Entity> leftEntities = new List<Entity>();

        if (!playerComponent.HasDied)
            leftEntities.Add(playerComponent);
        foreach (Ally ally in allyComps)
        {
            if (!ally.HasDied)
                leftEntities.Add(ally);
        }

        Entity chosenEntity = leftEntities[UnityEngine.Random.Range(0, leftEntities.Count)];

        uiHandler.RetrieveActionText().UpdateActionTextUnique(16, damageValue, chosenEntity);

        if (chosenEntity is Player)
            DamagePlayer(damageValue, false);
        else
            DamageAlly(chosenEntity as Ally, damageValue, false);

        return Task.CompletedTask;
    }
    public Task DealDamageToRightRandom(int damageValue)
    {
        List<Enemy> rightEntities = new List<Enemy>(enemyComps.Where(enemy => enemy.HasDied is false).ToList());
        Enemy target = rightEntities[UnityEngine.Random.Range(0, rightEntities.Count)];

        uiHandler.RetrieveActionText().UpdateActionTextUnique(16, damageValue, target);

        DamageEnemy(target, damageValue, false, false);
        return Task.CompletedTask;
    }
    public async Task<(bool, Entity)> IndicateRevivalChoices()
    {
        (bool choice, Entity spellTarget) = await uiHandler.ProvideDeadChoices(deadEntities);

        return (choice, spellTarget);
    }
    public Enemy ChooseRandomDeadEnemy()
    {
        foreach (Entity entity in deadEntities)
        {
            if (entity is Enemy enemy)
                return enemy;
        }

        return null;
    }
}