Encounter / Assets / Scripts / BattleLogic / ConsumableManagement.cs
ConsumableManagement.cs
Raw
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using UnityEngine;

/// <summary>
/// Handles Consumable usage situtations via the Items button
/// </summary>
public class ConsumableManagement : MonoBehaviour
{
    private BattleHandler bhReference;                  // Reference to the battle handler that is feeding the information to the manager
    private bool inBattle;                              // Reference to if the consumable management system needs to act as if in battle

    private Player playerRetainer;                     // Information storage for the player object
    private Enemy[] enemyRetainers;                    // Information storage of all of the enemies within the current battle
    private Ally[] allyRetainers;                      // Information storage of all of the current allies in the party
    private Consumable currentConsumable;              // The current consumable that is being used, information storage

    private Target[] enemyTargets;                     // Target components for enemies for indicator instantiation
    private Target[] allyTargets;                      // Target components for allies for indicator instantiation
    private Target playerTarget;                       // Target component for the player when trying to self activate
    private Task chosenTarget;                         // Task system to awawit for the chosen target for player selection

    private Entity consumableUser;                     // The user of the consumable
    private Entity consumableTarget;                   // The target of the consumable

    private bool UsedConsumable;
    private bool consumableTaskCancel;
    private bool[] signals;
    private static bool consumableSignaledToNotUse;

    private const int MaxChance = 100;

    public static void IndicateNoConsume()
        => consumableSignaledToNotUse = true;
    public bool GetUsedConsumableState() 
        => UsedConsumable;
    public bool GetConsumableTaskState() 
        => consumableTaskCancel; 
    public void StopConsumableTasks() 
        => consumableTaskCancel = true;
    /// <summary>
    /// Passes the target of the spell as an entity and indicates what child type the passed parameter it is
    /// </summary>
    /// <param name="target">Parent Entity class for the Enemies and Player classes</param>
    /// <exception cref="NullReferenceException">When target is null or an unexpected Entity type</exception>
    public void ChooseTarget(Entity target)
    {
        if (target is Player)
            consumableTarget = target as Player;
        else if (target is Enemy)
            consumableTarget = target as Enemy;
        else if (target is Ally)
            consumableTarget = target as Ally;
        else
            throw new NullReferenceException();

        chosenTarget = Task.CompletedTask;
    }
    public void BeginConsumableProcess(Entity user, Consumable consumable, Player player, Enemy[] enemyComps, Ally[] allyComps, BattleHandler bh)
    {
        UsedConsumable                  = false;
        consumableTaskCancel            = false;
        consumableSignaledToNotUse      = false;

        bhReference                     = bh;
        currentConsumable               = consumable;
        consumableUser                  = user;
        if (player != null)
        {
            playerRetainer = player;
            playerTarget = player.gameObject.GetComponent<Target>();
            playerTarget.InjectManager(this);
        }
        else
        {
            playerRetainer = null;
            playerTarget = null;
        }

        if (allyComps != null)
        {
            allyRetainers = allyComps;
            allyTargets = new Target[allyComps.Length];

            for (int i = 0; i < allyRetainers.Length; i++)
            {
                allyTargets[i] = allyRetainers[i].gameObject.GetComponent<Target>();
                allyTargets[i].InjectManager(this);
            }
        }
        else
        {
            allyRetainers = null;
            allyTargets = null;
        }
        
        enemyRetainers             = enemyComps;
        enemyTargets               = new Target[enemyComps.Length];
        
        for (int i = 0; i < enemyRetainers.Length; i++)
        {
            enemyTargets[i] = enemyRetainers[i].gameObject.GetComponent<Target>();
            enemyTargets[i].InjectManager(this);
        }

        if (currentConsumable.Effects.Count > 1)
            BeginAdvancedConsumableProcess();
        else
            BeginNormalConsumableProcess();
    }
    /// <summary>
    /// Normal Consumable Process when there is only one effect in the list
    /// </summary>
    private void BeginNormalConsumableProcess()
    {
        switch (currentConsumable.Effects.FirstOrDefault())
        {
            case ConsumableSO.Effect.Damage:
                signals = new bool[6] { true, false, false, false, false, false };
                ActivateDamageCon();
                break;
            case ConsumableSO.Effect.Heal:
                signals = new bool[6] { false, true, false, false, false, false };
                ActivateHealCon();
                break;
            case ConsumableSO.Effect.Refill:
                signals = new bool[6] { false, false, true, false, false, false };
                ActivateRefillCon();
                break;
            case ConsumableSO.Effect.Buff:
                signals = new bool[6] { false, false, false, true, false, false };
                ActivateBuffCon();
                break;
            case ConsumableSO.Effect.Debuff:
                signals = new bool[6] { false, false, false, false, true, false };
                ActivateDebuffCon();
                break;
        }
    }
    /// <summary>
    /// More Advanced Consumable Process when there is more than one effect in the consumable list
    /// </summary>
    private void BeginAdvancedConsumableProcess()
    {
        for (int i = 0; i < currentConsumable.Effects.Count; i++)
        {
            bool endOfEffects = i == currentConsumable.Effects.Count - 1;

            switch (currentConsumable.Effects[i])
            {
                case ConsumableSO.Effect.Heal:
                    signals = new bool[6] { true, false, false, false, false, false };
                    ActivateHealCon(endOfEffects);
                    break;
                case ConsumableSO.Effect.Refill:
                    signals = new bool[6] { false, true, false, false, false, false };
                    ActivateRefillCon(endOfEffects);
                    break;
                case ConsumableSO.Effect.Buff:
                    signals = new bool[6] { false, false, true, false, false, false };
                    ActivateBuffCon(endOfEffects);
                    break;
                case ConsumableSO.Effect.Debuff:
                    signals = new bool[6] { false, false, false, true, false, false };
                    ActivateDebuffCon(endOfEffects);
                    break;
                case ConsumableSO.Effect.Damage:
                    signals = new bool[6] { false, false, false, false, true, false };
                    ActivateDamageCon(endOfEffects);
                    break;
                default:
                    throw new DataMisalignedException($"Invalid Type detected in AdvancedConsumableProcess. " +
                        $"CurrentConsumable.Effects[i] -> ({currentConsumable.Effects[i]})");
            }
        }
    }
    /// <summary>
    /// Damage Consumable Handler
    /// </summary>
    private async void ActivateDamageCon(bool isEndOfConsumable = true)
    {
        int v = UtilityHandler.RollValueWithBase(currentConsumable.BaseValue, currentConsumable.DamageChance.ToArray());

        if (currentConsumable.EffectAll)
        {
            if (!consumableSignaledToNotUse)
                UsedConsumable = true;

            await bhReference.AttackWithItem(v, currentConsumable, consumableUser, null, true, true);
        }

        if (consumableUser is Player || consumableUser is Ally)
        {
            // When the user is the player or ally they select either side for damage
            if (currentConsumable.EffectAllType)
            {
                SwitchAllIndicatorTargets(true);
                bhReference.AwaitConsumableChoice(consumableUser);
                bool trigger = await Awaiter();

                SwitchAllIndicatorTargets(false);

                if (!trigger)
                {
                    GarbageCleanUp();
                    return;
                }

                bhReference.GetUIHandler().ResetUI();

                if (!consumableSignaledToNotUse)
                    UsedConsumable = true;
                await bhReference.AttackWithItem(v, currentConsumable, consumableUser, consumableTarget, 
                                                (consumableTarget is Ally || consumableTarget is Player), consumableTarget is Enemy);
            }
            // When the user is the player or ally they can select one enemy to receive the damage
            else
            {
                SwitchIndicatorsOfSide(false, true, true);
                bhReference.AwaitConsumableChoice(consumableUser);
                bool trigger = await Awaiter();

                SwitchIndicatorsOfSide(false, true, false);

                if (!trigger)
                {
                    GarbageCleanUp();
                    return;
                }

                bhReference.GetUIHandler().ResetUI();

                if (!consumableSignaledToNotUse)
                    UsedConsumable = true;
                await bhReference.AttackWithItem(v, currentConsumable, consumableUser, consumableTarget);
            }
        }
        else
        {
            // Enemy will use a damaging item on only the companion side if it affects all
            if (currentConsumable.EffectAllType)
            {
                if (!consumableSignaledToNotUse)
                    UsedConsumable = true;
                await bhReference.AttackWithItem(v, currentConsumable, consumableUser, null, true, false);
            }
            // Enemy will target a random companion and attack with the consumable
            else
            {
                if (!consumableSignaledToNotUse)
                    UsedConsumable = true;
                await bhReference.AttackWithItem(v, currentConsumable, consumableUser, ChooseRandomTargetForEnemy());
            }
        }

        if (isEndOfConsumable)
            GarbageCleanUp();
    }
    /// <summary>
    /// Heals either a single entity, all of a side, or all entities on screen
    /// </summary>
    private async void ActivateHealCon(bool isEndOfConsumable = true)
    {
        string consumeName = currentConsumable.ItemName;
        if (consumeName.Equals("Replenishment Concoction") || consumeName.Equals("Replenishment Potion"))
        {
            SwitchIndicatorsOfSide(true, false, true);

            bhReference.AwaitConsumableChoice(consumableUser);
            bool trigger = await Awaiter();

            SwitchIndicatorsOfSide(true, false, false);

            if (!trigger)
            {
                GarbageCleanUp();
                return;
            }

            bhReference.GetUIHandler().ResetUI();

            int healValue = 1;
            if (consumeName.Equals("Replenishment Concoction"))
                healValue = (int)(consumableTarget.RetrieveMaxHealth() * .25f);
            else if (consumeName.Equals("Replenishment Potion"))
                healValue = (int)(consumableTarget.RetrieveMaxHealth() * .5f);

            if (consumableTarget.HasDied)
                consumableTarget.Revive(false, healValue);
            else
                consumableTarget.IncreaseHealth(healValue);

            consumableTarget.StatusChanged();

            if (!consumableSignaledToNotUse)
                UsedConsumable = true;

            bhReference.CallItemActionText(consumableUser.GetName(), consumableTarget, currentConsumable, Target.Targetted.Single, healValue);
            bhReference.DisablePlayerTurn();
            return;
        }

        int healAmount = UtilityHandler.RollValueWithBase(currentConsumable.BaseValue, currentConsumable.HealChance.ToArray());

        // Heals all entities on screen currently
        if (currentConsumable.EffectAll)
        {
            IncreaseHealthOfEntities(true, true, healAmount);

            if (!consumableSignaledToNotUse)
                UsedConsumable = true;
            bhReference.CallItemActionText(consumableUser.GetName(), null, currentConsumable, Target.Targetted.All, healAmount);
            bhReference.DisablePlayerTurn();
        }

        // Player Healing Consumable Usage with companions
        if (consumableUser is Player || consumableUser is Ally)
        {
            // Heals all of a single side
            if (currentConsumable.EffectAllType)
            {
                SwitchAllIndicatorTargets(true);

                bhReference.AwaitConsumableChoice(consumableUser);
                bool trigger = await Awaiter();

                SwitchAllIndicatorTargets(false);

                if (!trigger)
                {
                    GarbageCleanUp();
                    return;
                }

                bhReference.GetUIHandler().ResetUI();

                if (consumableTarget is Enemy) // Heals Right (Enemies)
                    IncreaseHealthOfEntities(false, true, healAmount);
                else                            // Heals Left (Companions)
                    IncreaseHealthOfEntities(true, false, healAmount);

                if (!consumableSignaledToNotUse)
                    UsedConsumable = true;

                bhReference.CallItemActionText(consumableUser.GetName(), consumableTarget, currentConsumable, Target.Targetted.AllOfType, healAmount);
                bhReference.DisablePlayerTurn();
            }
            // Heals single target
            else
            {
                SwitchIndicatorsOfSide(true, false, true);

                bhReference.AwaitConsumableChoice(consumableUser);
                bool trigger = await Awaiter();

                SwitchIndicatorsOfSide(true, false, false);
                if (!trigger)
                {
                    GarbageCleanUp();
                    return;
                }

                bhReference.GetUIHandler().ResetUI();

                consumableTarget.IncreaseHealth(AbilityBrain.ConsumableChecks(consumableUser, consumableTarget, healAmount, signals));
                consumableTarget.StatusChanged();

                if (!consumableSignaledToNotUse)
                    UsedConsumable = true;
                bhReference.CallItemActionText(consumableUser.GetName(), consumableTarget, currentConsumable, Target.Targetted.Single, healAmount);
                bhReference.DisablePlayerTurn();
            }
        }
        // Enemy Healing Consumable Usage
        else
        {
            if (currentConsumable.EffectAllType)
            {
                IncreaseHealthOfEntities(false, true, healAmount);
                if (!consumableSignaledToNotUse)
                    UsedConsumable = true;
                bhReference.CallItemActionText(consumableUser.GetName(), consumableTarget, currentConsumable, Target.Targetted.AllOfType, healAmount);
            }
            else
            {
                consumableTarget = PickMostDamagedEnemy();
                consumableTarget.IncreaseHealth(healAmount);
                consumableTarget.StatusChanged();

                if (!consumableSignaledToNotUse)
                    UsedConsumable = true;
                bhReference.CallItemActionText(consumableUser.GetName(), consumableTarget, currentConsumable, Target.Targetted.Single, healAmount);
            }
        }

        if (isEndOfConsumable)
            GarbageCleanUp();
    }
    /// <summary>
    /// Picks the most damaged enemy from the containers available, if all are healthy then randomly selects one
    /// </summary>
    /// <returns>The most damaged enemy or a random enemy</returns>
    private Enemy PickMostDamagedEnemy()
    {
        Enemy output = null;
        Enemy[] damagedEnemies = enemyRetainers
                                 .Where(e => e.RetrieveHealth() < e.RetrieveMaxHealth())
                                 .ToArray();
        
        if (damagedEnemies.Length is 0)
            output = enemyRetainers[UnityEngine.Random.Range(0, enemyRetainers.Length)];

        // Cycles through all of the damaged enemies for the most damaged
        // If two enemies have the same health than a coin flip for the place
        // holder of being held is essentially held
        foreach (Enemy enemy in damagedEnemies)
        {
            if (output == null)
            {
                output = enemy;
                continue;
            }

            // Percentages are taken since there is variability between health
            if (output.GetHealthPercentage() > enemy.GetHealthPercentage())
                output = enemy;
            else if (output.GetHealthPercentage() == enemy.GetHealthPercentage())
            {
                int randomChoice = UnityEngine.Random.Range(0 , MaxChance + 1);
                if (randomChoice > MaxChance / 2)
                    output = enemy;
            }
        }

        return output;
    }
    /// <summary>
    /// Function to refill mana of the individuals indicated via the consumable item and target functionalities
    /// </summary>
    private async void ActivateRefillCon(bool isEndOfConsumable = true)
    {
        int refillAmount = UtilityHandler.RollValueWithBase(currentConsumable.BaseValue, currentConsumable.RefillChance.ToArray());

        // Refills mana of all entites on screen currently
        if (currentConsumable.EffectAll)
        {
            IncreaseManaOfEntities(true, true, refillAmount);

            if (!consumableSignaledToNotUse)
                UsedConsumable = true;
            bhReference.CallItemActionText(consumableUser.GetName(), null, currentConsumable, Target.Targetted.All, refillAmount);
            bhReference.DisablePlayerTurn();
        }

        // Mana refill with companions
        if (consumableUser is Player || consumableUser is Ally)
        {
            if (currentConsumable.EffectAllType)
            {
                SwitchAllIndicatorTargets(true);

                bhReference.AwaitConsumableChoice(consumableUser);
                bool trigger = await Awaiter();

                SwitchAllIndicatorTargets(false);
                if (!trigger)
                {
                    GarbageCleanUp();
                    return;
                }

                bhReference.GetUIHandler().ResetUI();

                if (consumableTarget is Enemy)
                    IncreaseManaOfEntities(false, true, refillAmount);
                else
                    IncreaseManaOfEntities(true, false, refillAmount);

                if (!consumableSignaledToNotUse)
                    UsedConsumable = true;

                bhReference.CallItemActionText(consumableUser.GetName(), consumableTarget, currentConsumable, Target.Targetted.AllOfType, refillAmount);
                bhReference.DisablePlayerTurn();
            }
            else
            {
                SwitchIndicatorsOfSide(true, false, true);

                bhReference.AwaitConsumableChoice(consumableUser);
                bool trigger = await Awaiter();

                SwitchIndicatorsOfSide(true, false, false);

                if (!trigger)
                {
                    GarbageCleanUp();
                    return;
                }

                bhReference.GetUIHandler().ResetUI();

                consumableTarget.IncreaseMana(refillAmount);
                consumableTarget.StatusChanged();

                if (!consumableSignaledToNotUse)
                    UsedConsumable = true;

                bhReference.CallItemActionText(consumableUser.GetName(), consumableTarget, currentConsumable, Target.Targetted.Single, refillAmount);
                bhReference.DisablePlayerTurn();
            }
        }
        else
        {
            if (currentConsumable.EffectAllType)
            {
                IncreaseManaOfEntities(false, true, refillAmount);
                if (!consumableSignaledToNotUse)
                    UsedConsumable = true;
                bhReference.CallItemActionText(consumableUser.GetName(), consumableTarget, currentConsumable, Target.Targetted.AllOfType, refillAmount);
            }
            else
            {
                consumableTarget = PickMostExhaustedEnemy();
                consumableTarget.IncreaseMana(refillAmount);
                consumableTarget.StatusChanged();

                if (!consumableSignaledToNotUse)
                    UsedConsumable = true;
                bhReference.CallItemActionText(consumableUser.GetName(), consumableTarget, currentConsumable, Target.Targetted.Single, refillAmount);
            }
        }

        GarbageCleanUp();
    }
    /// <summary>
    /// Pick the enemy with the least mana percentage wise
    /// </summary>
    /// <returns>Most exhausted enemy</returns>
    private Enemy PickMostExhaustedEnemy()
    {
        Enemy output = null;
        // Chooses enemies that have less than their max mana, also specifies that the enemies should have mana to begin with
        Enemy[] exhaustedEnemies = enemyRetainers
                                   .Where(e => e.RetrieveMana() < e.RetrieveMaxMana() && e.RetrieveMaxMana() is not 0)
                                   .ToArray();

        if (exhaustedEnemies.Length is 0)
            output = enemyRetainers[UnityEngine.Random.Range(0, enemyRetainers.Length)];

        // Cycles through all of the enemies with lower mana than the max mana
        // of the enemy to retrieve the most exhausted enemy for the mana item
        foreach (Enemy enemy in exhaustedEnemies)
        {
            if (output == null)
            {
                output = enemy;
                continue;
            }
            if (output.GetManaPercentage() > enemy.GetManaPercentage())
                output = enemy;
            else if (output.GetManaPercentage() == enemy.GetManaPercentage())
            {
                int randomChoice = UnityEngine.Random.Range(0 , MaxChance + 1);
                if (randomChoice > MaxChance / 2)
                    output = enemy;
            }
        }

        return output;
    }
    /// <summary>
    /// Buff Modifier addition logic
    /// </summary>
    private async void ActivateBuffCon(bool isEndOfConsumable = true)
    {
        if (currentConsumable.EffectAll)
        {
            if (!consumableSignaledToNotUse)
                UsedConsumable = true;
            ModifierCall(true, true);
        }

        if (consumableUser is Ally || consumableUser is Player)
        {
            // Activates buffs on the selected side by the player/allies
            if (currentConsumable.EffectAllType)
            {
                SwitchAllIndicatorTargets(true);
                bhReference.AwaitConsumableChoice(consumableUser);
                bool trigger = await Awaiter();

                SwitchAllIndicatorTargets(false);

                if (!trigger)
                {
                    
                    GarbageCleanUp();
                    return;
                }

                bhReference.GetUIHandler().ResetUI();

                if (!consumableSignaledToNotUse)
                    UsedConsumable = true;

                ModifierCall(consumableTarget is Ally || consumableTarget is Player, consumableTarget is Enemy);
            }
            // Activates singular buff on the selected target
            else
            {
                SwitchIndicatorsOfSide(true, false, true);
                bhReference.AwaitConsumableChoice(consumableUser);
                bool trigger = await Awaiter();

                SwitchIndicatorsOfSide(true, false, false);

                if (!trigger)
                {
                    GarbageCleanUp();
                    return;
                }

                bhReference.GetUIHandler().ResetUI();

                if (!consumableSignaledToNotUse)
                    UsedConsumable = true;

                ModifierCall();
            }
        }
        else
        {
            // Always buffs the enemies side when an enemy casts a buff item
            if (currentConsumable.EffectAllType)
            {
                if (!consumableSignaledToNotUse)
                    UsedConsumable = true;
                ModifierCall(false, true);
            }
            // Enemy chooses a random enemy target to buff
            else
            {
                consumableTarget = enemyRetainers[UnityEngine.Random.Range(0, enemyRetainers.Length)];
                if (!consumableSignaledToNotUse)
                    UsedConsumable = true;
                ModifierCall();
            }
        }

        if (isEndOfConsumable)
            GarbageCleanUp();
    }
    /// <summary>
    /// Debuff modifier addition logic
    /// </summary>
    private async void ActivateDebuffCon(bool isEndOfConsumable = true)
    {
        if (currentConsumable.EffectAll)
        {
            if (!consumableSignaledToNotUse)
                UsedConsumable = true;
            ModifierCall(true, true);
        }

        if (consumableUser is Ally || consumableUser is Player)
        {
            // Activates buffs on the selected side by the player/allies
            if (currentConsumable.EffectAllType)
            {
                SwitchAllIndicatorTargets(true);
                bhReference.AwaitConsumableChoice(consumableUser);
                bool trigger = await Awaiter();

                SwitchAllIndicatorTargets(false);

                if (!trigger)
                {
                    GarbageCleanUp();
                    return;
                }

                bhReference.GetUIHandler().ResetUI();
                
                if (!consumableSignaledToNotUse)
                    UsedConsumable = true;

                ModifierCall(consumableTarget is Ally || consumableTarget is Player, consumableTarget is Enemy);
            }
            // Activates singular buff on the selected target
            else
            {
                SwitchIndicatorsOfSide(true, false, true);
                bhReference.AwaitConsumableChoice(consumableUser);
                bool trigger = await Awaiter();

                SwitchIndicatorsOfSide(true, false, false);

                if (!trigger)
                {
                    GarbageCleanUp();
                    return;
                }

                bhReference.GetUIHandler().ResetUI();
                
                UsedConsumable = true;
                ModifierCall();
            }
        }
        else
        {
            // Always buffs the enemies side when an enemy casts a buff item
            if (currentConsumable.EffectAllType)
            {
                if (!consumableSignaledToNotUse)
                    UsedConsumable = true;

                ModifierCall(true, false);
            }
            // Enemy chooses a random enemy target to buff
            else
            {
                consumableTarget = ChooseRandomTargetForEnemy();
                if (!consumableSignaledToNotUse)
                    UsedConsumable = true;

                ModifierCall();
            }
        }

        if (isEndOfConsumable)
            GarbageCleanUp();
    }
    /// <summary>
    /// Simpler Modifier Call that adds on the modifier taken from the current consumable to the consumable 
    /// target if it is not within the mod list of the entity
    /// </summary>
    private void ModifierCall()
    {
        bhReference.CallItemActionText(consumableUser.GetName(), consumableTarget, currentConsumable);
        Modifier m = Globals.TurnModifierFromObject(currentConsumable.AcquireModifier());

        // Checks that the target doesn't already have the modification within their list
        if (!consumableTarget.GatherModList().Contains(m))
            consumableTarget.AddModToList(m);

        if (consumableUser is Player || consumableUser is Ally)
            bhReference.DisablePlayerTurn();
    }
    /// <summary>
    /// Collective side calls for modifier add-ons
    /// </summary>
    /// <param name="left">Condition of the left side indicator if companions are wholly effected</param>
    /// <param name="right">Condition of the right side indicator if enemies are wholly effected</param>
    /// <exception cref="DataMisalignedException">Exception is thrown when both left and right show false</exception>
    private void ModifierCall(bool left, bool right)
    {
        Modifier m = Globals.TurnModifierFromObject(currentConsumable.AcquireModifier());

        if (!left && !right)
            throw new DataMisalignedException($"Modifier Call has thrown an exception due to misaligned side information - Modifier --> {m.Name}" +
                $" - Left Ind {left} - Right Ind {right}");

        bhReference.CallItemActionText(consumableUser.GetName(), consumableTarget, currentConsumable, 
                (left && right) ? Target.Targetted.All : (left || right) ? Target.Targetted.AllOfType : default);

        if (left)       // Adds condition to all companions if not already present
        {
            if (playerRetainer != null)
            {
                if (!playerRetainer.GatherModList().Contains(m))
                    playerRetainer.AddModToList(m);
            }

            if (allyRetainers != null)
            {
                foreach (Ally a in allyRetainers)
                {
                    if (!a.GatherModList().Contains(m))
                        a.AddModToList(m);
                }
            }
        }
        if (right)      // Adds condition to all enmemies if not already present
        {
            foreach (Enemy e in enemyRetainers)
            {
                if (!e.GatherModList().Contains(m))
                    e.AddModToList(m);
            }
        }

        if (consumableUser is Player || consumableUser is Ally)
            bhReference.DisablePlayerTurn();
    }
#pragma warning disable UNT0008
    /// <summary>
    /// Cleans up the unnecessary information from the consumable manager now that the process is complete
    /// </summary>
    private void GarbageCleanUp()
    {
        currentConsumable          = null;
        consumableUser             = null;
        consumableTarget           = null;
        allyRetainers              = null;
        playerRetainer             = null;
        enemyRetainers             = null;

        if (enemyTargets is not null)
        {
            foreach (Target t in enemyTargets)
            {
                if (t != null)
                    t.SwitchConsumableIndicationMode(false);
            }
        }

        if (allyTargets is not null)
        {
            foreach (Target t in allyTargets)
            {
                if (t != null)
                    t.SwitchConsumableIndicationMode(false);
            }
        }

        playerTarget?.SwitchConsumableIndicationMode(false);

        enemyTargets       = null;
        allyTargets        = null;
        playerTarget       = null;
        chosenTarget       = null;
    }
#pragma warning restore UNT0008
    /// <summary>
    /// Public reset call for button in consumable selection fields and stops all consumable tasks
    /// </summary>
    public void Cancel()
    {
        StopConsumableTasks();
        GarbageCleanUp();
    }
    /// <summary>
    /// Consumable Awaiter for item selection for players and allies that has a cancelling component
    /// </summary>
    /// <returns>Completed Task once a target has been chosen</returns>
    private async Task<bool> Awaiter()
    {
        while (chosenTarget == null)
        {
            // Cancel call if the task cancel is switched to true while trying to select a target
            if (consumableTaskCancel)
                return false;

            await Task.Yield();
        }

        return true;
    }
    /// <summary>
    /// Switches all of the targets to a designated status for the arrow indicators to disappear and appear
    /// </summary>
    /// <param name="status">The condition of the indicator status</param>
    private void SwitchAllIndicatorTargets(bool status)
    {
        playerTarget?.SwitchConsumableIndicationMode(status);
        foreach (Target target in enemyTargets)
            target.SwitchConsumableIndicationMode(status);

        if (allyTargets != null)
        {
            foreach (Target target in allyTargets)
                target.SwitchConsumableIndicationMode(status);
        }
    }
    /// <summary>
    /// Switches a designated sides indicators when necessary
    /// </summary>
    /// <param name="left">The companion side indicators</param>
    /// <param name="right">The enemy side indicators</param>
    /// <param name="status">The condition of the targets indicators</param>
    private void SwitchIndicatorsOfSide(bool left, bool right, bool status)
    {
        if (left)           // Companion side
        {
            playerTarget?.SwitchConsumableIndicationMode(status);

            if (allyTargets != null)
            {
                foreach (Target t in allyTargets)
                    t.SwitchConsumableIndicationMode(status);
            }
        }
        else if (right)     // Enemy side
        {
            foreach (Target t in enemyTargets)
                t.SwitchConsumableIndicationMode(status);
        }
    }
    /// <summary>
    /// Handles collective side healing effects, works for type and all targetting
    /// </summary>
    /// <param name="left">The companion side targetting indication</param>
    /// <param name="right">The enemy side targetting indication</param>
    /// <param name="healAmount">The value that is healing the targets</param>
    private void IncreaseHealthOfEntities(bool left, bool right, int healAmount)
    {
        // The companions side
        if (left)
        {
            playerRetainer?.IncreaseHealth(AbilityBrain.ConsumableChecks(consumableUser, playerRetainer, healAmount, signals));
            playerRetainer?.StatusChanged();

            if (allyRetainers != null)
            {
                foreach (Ally ally in allyRetainers)
                {
                    ally.IncreaseHealth(AbilityBrain.ConsumableChecks(consumableUser, ally, healAmount, signals));
                    ally.StatusChanged();
                }
            }
        }

        // The enemy side
        if (right)
        {
            foreach (Enemy enemy in enemyRetainers)
            {
                enemy.IncreaseHealth(AbilityBrain.ConsumableChecks(consumableUser, enemy, healAmount, signals));
                enemy.StatusChanged();
            }
        }
    }
    /// <summary>
    /// Increases mana of all of one side or both sides
    /// </summary>
    /// <param name="left">Companion Side</param>
    /// <param name="right">Enemy Side</param>
    /// <param name="refillAmount">The amount to refill</param>
    private void IncreaseManaOfEntities(bool left, bool right, int refillAmount)
    {
        // The companions side
        if (left)
        {
            playerRetainer?.IncreaseMana(AbilityBrain.ConsumableChecks(consumableUser, playerRetainer, refillAmount, signals));
            playerRetainer?.StatusChanged();

            if (allyRetainers != null)
            {
                foreach (Ally ally in allyRetainers)
                {
                    ally.IncreaseMana(AbilityBrain.ConsumableChecks(consumableUser, ally, refillAmount, signals));
                    ally.StatusChanged();
                }
            }
        }

        // The enemy side
        if (right)
        {
            foreach (Enemy enemy in enemyRetainers)
            {
                enemy.IncreaseMana(AbilityBrain.ConsumableChecks(consumableUser, enemy, refillAmount, signals));
                enemy.StatusChanged();
            }
        }
    }
    /// <summary>
    /// Cycles for an entity that the enemy can target
    /// </summary>
    /// <returns>The entity that the enemy wants to target</returns>
    private Entity ChooseRandomTargetForEnemy()
    {
        Entity output = null;

        const int CutoffMax = 100;
        if (allyRetainers == null && playerRetainer != null)
            output = playerRetainer;
        else if (allyRetainers != null && playerRetainer != null)
        {
            int count = allyRetainers.Length;
            int quo = CutoffMax / (allyRetainers.Length + 1);
            int v = UnityEngine.Random.Range(1, CutoffMax + 1);
            switch (count)
            {
                case 1:
                    if (v >= quo)
                        output = playerRetainer;
                    else
                        output = allyRetainers[0];
                    break;
                case 2:
                    if (v >= quo * count)
                        output = playerRetainer;
                    else if (v >= quo)
                        output = allyRetainers[1];
                    else
                        output = allyRetainers[0];
                    break;
                case 3:
                    if (v >= quo * count)
                        output = playerRetainer;
                    else if (v >= quo * (count - 1))
                        output = allyRetainers[2];
                    else if (v >= quo)
                        output = allyRetainers[1];
                    else
                        output = allyRetainers[0];
                    break;
            }
        }
        else if (allyRetainers != null && playerRetainer == null)
        {
            int count = allyRetainers.Length;
            int quo = CutoffMax / allyRetainers.Length;
            int v = UnityEngine.Random.Range(1, CutoffMax + 1);
            switch (count)
            {
                case 1:
                    output = allyRetainers[0];
                    break;
                case 2:
                    if (v >= quo)
                        output = allyRetainers[1];
                    else
                        output = allyRetainers[0];
                    break;
                case 3:
                    if (v >= quo * (count - 1))
                        output = allyRetainers[2];
                    else if (v >= quo)
                        output = allyRetainers[1];
                    else
                        output = allyRetainers[0];
                    break;
            }
        }

        return output;
    }
}