Encounter / Assets / Scripts / GUIHandlers / EnemyUI.cs
EnemyUI.cs
Raw
using Cinemachine;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using TMPro;
using UnityEngine;
using UnityEngine.UI;

/// <summary>
/// Handles mostly the Canvas UI Components of the Battling System,
/// such as the Buttons, Dialogues, and Cameras, logic is held mostly in BattleHandler
/// </summary>
public class EnemyUI : MonoBehaviour
{
    public static EnemyUI Instance { get; private set; }

    [Header("UI Properties")]
    public Canvas primaryCanvas;             // Canvas for the primary Enemy UI container
    public Canvas lootingCanvas;             // Canvas for the looting aspects
    public Transform playerField;            // The transform that holds the buttons
    public GameObject normalButton;          // The prefab for the smaller button variety
    public GameObject spellButton;           // The prefab for the spell button variety
    public ActionTextBox actionText;         // The text box for the actions being performed in the battle
    public TextMeshProUGUI currentEntityTurnText;   

    [Header("Looting UI Properties")]
    [SerializeField] private GameObject gridObjectRef;         // Prefab reference for the grid that holds the objects in the loot and inventory fields
    [SerializeField] private TextMeshProUGUI currentMemberText;
    [SerializeField] private TextMeshProUGUI currentMemberCurrentInvenCount;
    [SerializeField] private TextMeshProUGUI goldValueText;
    [SerializeField] private List<GameObject> activatedIcons;
    [SerializeField] private List<GameObject> memberIcons;
    [SerializeField] private GameObject itemContainerPrefab;
    [SerializeField] private Transform inventoryTransform;
    [SerializeField] private Transform lootingTransform;

    [Header("Camera")]
    [SerializeField] private CinemachineVirtualCamera checkTrackCamera;

    private BattleHandler battleComponent;                      // The container for the scene's battle handler for this UI instance
    private Dictionary<Item, int> currentLoot;                  // Loot for the current encounter
    private List<int> experienceGathered;
    private List<GameObject> lootGrids;
    private List<GameObject> invenGrids;
    private Inventory currentInven;

    private Player player;
    private GameObject[] EnemyRefs;                             // The container for the enemy GameObjects within this instance of the enemy UI battling
    private Enemy[] Enemies;                                    // The container for the enemy components within this instance of the enemy UI battling
    private Ally[] Allies;                                      // The container for the ally components for this instance of the enemy UI battling
    private Enemy[] TempEnemies;                                // The container for the minion enemy components 
    private Ally[] TempAllies;                                  // The container for the minion ally components
    
    private List<GameObject> buttons;
    private bool runUsed;
    private Task uiTask;                                          // Task call for the enabling and disabling of the player UI 

    /// <summary>
    /// Retrieves the state of the task for player battling
    /// null is shown if the left battle side has not been disabled and
    /// complete if the left side has been disabled
    /// </summary>
    /// <returns></returns>
    public Task GetUITask()
        => uiTask;
    /// <summary>
    /// Switches the battle off
    /// </summary>
    private void InvokeBattleOff() 
        => battleComponent.SetBattlingStatus(false);
    private void Awake()
        => Instance = this;
    private async void OnEnable()
    {
        // Waits until the enemies are loaded from files
        await EntityLoad();

        // Sets the overlay mode for the canvas as well as the layer
        SetCanvasComponents();

        // Then sets the enemies and player into position
        // as well as setting the EnemyUI handler within the BattleHandler
        battleComponent = BattleHandler.Instance;
        currentLoot = new Dictionary<Item, int>();
        battleComponent.SetHandler(this);

        SetEntities();

        await Task.Delay(1000);

        battleComponent.InitializeOrder();
        battleComponent.SetBattlingStatus(true);

        while (battleComponent.GetBattlingStatus())
            await battleComponent.SetActiveEntity();

        async Task EntityLoad()
        {
            while (EnemyRefs is null)
                await Task.Yield();

            await Task.CompletedTask;
        }
        void SetCanvasComponents()
        {
            primaryCanvas.worldCamera = Camera.main;
            primaryCanvas.sortingLayerName = "UI";

            lootingCanvas.worldCamera = Camera.main;
            lootingCanvas.sortingLayerName = "UI";

            GeneralUI.Instance.DeactivateInventoryButton();
        }
    }
    /// <summary>
    /// Positions the player and enemies into position
    /// </summary>
    private void SetEntities()
    {
        GameManager gmInstance = GameManager.Instance;

        GeneralUI.Instance.UpdateGUIs(gmInstance.GetAllyObjects());

        if (Globals.IsBossEncounter)
        {
            CameraManager.Instance.LightenScreen().GetAwaiter();
            Enemies = battleComponent.CallForEntityPositioning(EnemyRefs, true);
        }
        else
            Enemies = battleComponent.CallForEntityPositioning(EnemyRefs, false);

        PositionHandler.Instance.ShowAndRaisePlayerObject(gmInstance.GetPlayerObject());
        PositionHandler.Instance.ShowAndRaiseAllyObjects(gmInstance.GetAllyObjects());
        Allies = gmInstance.GetAllyObjects()?.Select(ally => ally.GetComponent<Ally>()).ToArray();
        player = gmInstance.GetPlayerObject().GetComponent<Player>();
    }
    /// <summary>
    /// Intakes the entitiy prefabs into the new enemy UI system to be dispersed among
    /// other systems, determines if Enemy prefabs or Ally prefabs
    /// </summary>
    /// <param name="enemies">Entity prefab instances</param>
    public void InsertEnemyInfo(GameObject[] enemies)
    {
        this.EnemyRefs = new GameObject[enemies.Length];
        for (int i = 0; i < enemies.Length; i++)
            this.EnemyRefs[i] = enemies[i];
    }
    /// <summary>
    /// Destroys the indicated entity value based on index position and the trigger for
    /// if the entity destroyed is an enemy or not
    /// </summary>
    /// <param name="index">The position in the designated entity collection</param>
    /// <param name="isEnemy">Trigger for which collection is affected</param>
    public Task DeactivateEntityValue(int index, bool isEnemy)
    {
        // Player value, simply returns after switching the component off
        if (index is -1)
        {
            player.DeactivateVisually();
            return Task.CompletedTask;
        }

        int loopLength = isEnemy ? Enemies.Length : Allies.Length;

        // Cycles through the enemies or allies to determine which should be deactivated
        for (int i = 0; i < loopLength ; i++)
        {
            if (isEnemy && i == index)
            {
                GenerateLoot(Enemies[i]);
                GenerateExperience(Enemies[i]);
                Enemies[i].enabled = false;
            }
            else if (!isEnemy && i == index)
                Allies[i].DeactivateVisually();
        }

        // Searches if all of a side has been deactivated to determine the outcome of the battle
        bool trigger = true;
        if (isEnemy)
        {
            foreach (Enemy enemyCheck in Enemies)
            {
                if (enemyCheck.isActiveAndEnabled)
                {
                    trigger = false;
                    break;
                }
            }
        }
        else
        {
            if (!player.HasDied)
                trigger = false;
            
            if (trigger)
            {
                foreach (Ally ally in Allies)
                {
                    if (!ally.HasDied)
                    {
                        trigger = false;
                        break;
                    }
                }
            }
        }

        // If a side is determined to not have any entities then the battle is over
        if (trigger)
            battleComponent.SetBattlingStatus(false);

        return Task.CompletedTask;
    }
    /// <summary>
    /// Destroys all enemies within the scene, meant primarily to be used for the running calls
    /// </summary>
    private void DestroyAllEnemies() 
        => battleComponent.DeactivateAllEnemies();
    /// <summary>
    /// Destroys all allies within the scene
    /// </summary>
    private void DestroyAllAllies() 
        => battleComponent.DeactivateAllAllies();
    /// <summary>
    /// Provides list of enemies to target with the active weapon of the player along with the cancel option
    /// </summary>
    public void Fight(Entity entity, int attackPerformed)
    {
        ResetUI();

        buttons = new List<GameObject>();
        // Enemy options
        for (int i = 0; i < Enemies.Length; ++i)
        {
            if (!Enemies[i].gameObject.activeSelf)
                continue;

            GameObject buttonRef = Instantiate(normalButton, playerField);
            buttons.Add(buttonRef);
            buttonRef.GetComponentInChildren<TextMeshProUGUI>().text = Enemies[i].GetName();

            int tempVar = i;
            buttonRef.GetComponent<Button>().onClick.AddListener(() =>
            {
                battleComponent.RollToHit(tempVar, entity, false, attackPerformed);
            });
        }
        // Enemy Minion options
        if (TempEnemies != null)
        {
            for (int i = 0; i < TempEnemies.Length; ++i)
            {
                GameObject buttonRef = Instantiate(normalButton, playerField);
                buttons.Add(buttonRef);
                buttonRef.GetComponentInChildren<TextMeshProUGUI>().text = TempEnemies[i].GetName();

                // Temp variable needs to include enemy length otherwise buttons will have incorrect correlations
                int tempVar = Enemies.Length + i;
                buttonRef.GetComponent<Button>().onClick.AddListener(() =>
                {
                    battleComponent.RollToHit(tempVar, entity, false, attackPerformed);
                });
            }
        }

        if (attackPerformed is 0)
            CreateCancelButton(entity);
    }
    /// <summary>
    /// Creates a spell button for each of the spells available to the player as well as the cancel button
    /// </summary>
    public void Magic(Entity entity)
    {
        ResetUI();

        // Creates a list of the spells that includes the limited spells the entity has access to
        List<Spell> spellList = new List<Spell>(entity.GetInventory().Spells);
        spellList.AddRange(entity.GetInventory().limitedSpells);
        
        // This cycles through the list in case their are any duplicate spells which shouldn't be listed
        for (int i = 0; i < spellList.Count - 1; ++i)
        {
            for (int j = i + 1; j < spellList.Count; ++j)
            {
                try
                {
                    if (spellList[i] == spellList[j])
                    {
                        spellList.Remove(spellList[j]);
                        --j;
                    }
                }
                catch
                {
                    throw;
                }
            }
        }

        buttons = new List<GameObject>();

        // Exploitative Check
        ExploitativeFunction(entity, spellList);

        for (int i = 0; i < spellList.Count; i++)
        {
            // Skips spells that are not meant for battle
            if (SkipSpell(spellList[i]))
                continue;

            GameObject buttonRef = Instantiate(spellButton, playerField);
            buttons.Add(buttonRef);
            buttonRef.GetComponentInChildren<TextMeshProUGUI>().text = spellList[i].SpellName;

            // Puts the spell in the player's spell list into the spell helper conenction
            buttonRef.GetComponent<SpellHelperConnector>().SpellInjectionStart(spellList[i]);

            // Disables button if unable to be used
            CheckSpellUseStatus(spellList, i, buttonRef, entity);

            int tempVar = i;
            buttonRef.GetComponent<Button>().onClick.AddListener(() =>
            {
                // Warning disabled due to method begin called from a listener
#pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
                battleComponent.InjectIntoSpellManager(spellList[tempVar], entity);
#pragma warning restore CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
            });
        }

        // Cancel Button
        CreateCancelButton(entity);

        // Skips spells that aren't meant for battle
        bool SkipSpell(Spell spell)
        {
            return spell.SpellName switch
            {
                "Detect Magic" => true,
                "Pillage" => Enemies.All(enemy => enemy.Pillaged is true),

                _ => false,
            };
        }

        void ExploitativeFunction(Entity entity, List<Spell> spellList)
        {
            if (entity.GetInventory().Abilities.Contains(AbilityBrain.GetAbilityList()[126]) || entity.GetInventory().Abilities.Contains(AbilityBrain.GetAbilityList()[126]))
            {
                int numberOfAlliesToExploit = 0;
                if (!player.HasDied)
                    numberOfAlliesToExploit++;
                if (Allies is not null)
                {
                    foreach (Ally ally in Allies)
                    {
                        if (!ally.HasDied)
                            numberOfAlliesToExploit++;
                    }
                }
                if (TempAllies is not null)
                {
                    foreach (Ally ally in TempAllies)
                    {
                        if (!ally.HasDied)
                            numberOfAlliesToExploit++;
                    }
                }

                // Take one away for the entity being checked currently
                numberOfAlliesToExploit--;

                // Percentage compounds, does not straight stack
                foreach (Spell spell in spellList)
                {
                    for (int i = 0; i < numberOfAlliesToExploit; ++i)
                        spell.SpellCost -= (int)Math.Floor(spell.SpellCost * .1f);
                }
            }
        }
    }
    /// <summary>
    /// Makes sure that the spell indicated within the button can be activated/used based 
    /// on the user's current mana pool
    /// </summary>
    /// <param name="spell_List">The list of spells available</param>
    /// <param name="index">The index within the spell list</param>
    /// <param name="button_Ref">The button object reference</param>
    private void CheckSpellUseStatus(List<Spell> spell_List, int index, GameObject button_Ref, Entity entity)
    {
        // Retrieves the current mana value from the player if the current entity is not an ally, otherwise retrieves the passed allies mana
        int mana = entity is Player player ? player.RetrieveMana() : ((Ally)entity).RetrieveMana();

        if (spell_List[index].SpellCost > mana)
        {
            button_Ref.GetComponent<Button>().interactable = false;
            button_Ref.GetComponent<Image>().color = Globals.DisabledColor;
        }
    }
    /// <summary>
    /// Creates buttons for each consumable in the ally/player's inventory with their value indicated in the buttons
    /// with listeners to activate their consumabels
    /// </summary>
    /// <param name="ally">Ally component if needed</param>
    public void Items(Entity entity)
    {
        ResetUI();

        // Gather consumables from needed inventory
        Dictionary<Consumable, int> consumables = entity.GetInventory().Consumables;
        buttons = new List<GameObject>();

        foreach (KeyValuePair<Consumable, int> con in consumables)
        {
            GameObject buttonRef = Instantiate(normalButton, playerField);
            buttons.Add(buttonRef);

            buttonRef.GetComponentInChildren<TextMeshProUGUI>().text = $"{con.Key.ItemName} ({con.Value})";
            buttonRef.GetComponent<Button>().onClick.AddListener(() =>
            {
                battleComponent.ActivateConsumable(entity.GetInventory(), con.Key, entity);
            });
        }

        // Cancel Button
        CreateCancelButton(entity);
    }
    /// <summary>
    /// Handles analyizing an entity for helpful information
    /// </summary>
    /// <param name="ally">Ally component if their turn and available</param>
    public void Check(Entity entity)
    {
        ResetUI();

        buttons = new List<GameObject>();

        for (int i = 0; i < Enemies.Length; i++)
        {
            if (!Enemies[i].gameObject.activeSelf)
                continue;

            GameObject bRef = Instantiate(normalButton, playerField);
            buttons.Add(bRef);
            bRef.GetComponentInChildren<TextMeshProUGUI>().text = Enemies[i].GetName();

            int tempVar = i;
            bRef.GetComponent<Button>().onClick.AddListener(() =>
            {
                BeginCheckProcess(Enemies[tempVar]);
            });
        }

        CreateCancelButton(entity);
    }
    /// <summary>
    /// Calculates running chances and rolls to see if the player (or ally) is able to escape
    /// </summary>
    /// <param name="ally">If it is an allies turn their Dex Modifier will be used</param>
    public async void Run(Entity entity)
    {
        DisableOptions();
        bool trigger = CalculateSuccess();
        await actionText.UpdateActionTextFlee(entity.GetName(), trigger);
        
        if (trigger)
        {
            DestroyAllEnemies();
            DestroyAllAllies();
            InvokeBattleOff();

            battleComponent.DisableBattle(true);
        }
        else
        {
            EnableOptions();
            buttons[^1].GetComponent<Button>().interactable = false;
            buttons[^1].GetComponent<Image>().color = Color.gray;

            runUsed = true;
        }

        bool CalculateSuccess(bool isRecalc = false)
        {
            if (Globals.IsBossEncounter)
                return false;

            int retrievedDexStat = entity.GatherStats().GetStat(EntityStats.Stat.Dexterity, entity.GetBaseStat(EntityStats.Stat.Dexterity)); 

            const float BaseRun = 100;
            float baseRunChance = BaseRun - entity.GetLevel();
            float totalRunChance = baseRunChance + retrievedDexStat;

            float rolledValue = UnityEngine.Random.Range(0f, 99f);

            foreach (Enemy enemy in Enemies)
            {
                // Foreach enemy that is still alive, their dexterity is added to the roll value for a higher chance of failing
                if (enemy.HasDied is false)
                    rolledValue += enemy.GatherStats().GetStat(EntityStats.Stat.Dexterity);
            }
            // Checks if the entity running away has the ability Evasive Maneuvers
            Inventory entityInven = entity.GetInventory();
            Dictionary<int, Ability> abilityList = AbilityBrain.GetAbilityList();
            if (entityInven.Abilities.Contains(abilityList[64]) || entityInven.limitedAbilities.Contains(abilityList[64]))
            {
                if (rolledValue > totalRunChance && !isRecalc)
                    return CalculateSuccess(true);
            }

            return rolledValue <= totalRunChance;
        }
    }
    /// <summary>
    /// Simply leaves the current Enemy Encounter to start the next Encounter
    /// </summary>
    private void ExitEncounter()
    {
        // Destroys all of the disabled enemies 
        foreach (Enemy enemy in Enemies)
        {
            // Try catch is implemented if Run was activated and successful
            try
            {
                Destroy(enemy.gameObject);
            } 
            catch { }
        } 

        if (Allies != null)
            GameManager.Instance.EndEncounter(player, Allies);
        else
            GameManager.Instance.EndEncounter(player);
    }
    /// <summary>
    /// Creates the cancel button for each of the options listed above
    /// </summary>
    public void CreateCancelButton(Entity entity)
    {
        // Cancel button
        GameObject cancelRef = Instantiate(normalButton, playerField);
        buttons.Add(cancelRef);
        cancelRef.GetComponentInChildren<TextMeshProUGUI>().text = "Cancel";

        cancelRef.GetComponent<Button>().onClick.AddListener(() =>
        {
            Cancel(entity);
        });
    }
    /// <summary>
    /// Cancels the current selection fields to go back to the primary fields
    /// </summary>
    public void Cancel(Entity entity)
    {
        foreach (Transform child in playerField.transform)
            Destroy(child.gameObject);

        buttons?.Clear();
        EnableEnemyLayout(entity);
    }
    /// <summary>
    /// The Player UI is enabled for their turn in battle 
    /// </summary>
    /// <returns>Returns the indication that the task is complete</returns>
    public async Task EnableLeftBattle(Entity entity, Dictionary<string, object> triggers)
    {
        // Task is reset once player is active, resets run available for player turn
        uiTask = null;
        runUsed = false;
        ResetUI();

        if (triggers.ContainsKey("CoreSpell"))
            await battleComponent.InjectIntoSpellManager((Spell)triggers["CoreSpell"], entity, true);

        EnableEnemyLayout(entity);

        // The thread awaits until the task has been completed, i.e. the player chooses to fight, use magic, run, etc. 
        while (uiTask == null)
            await Task.Yield();
        
        await uiTask;
    }
    /// <summary>
    /// The Player UI is disabled and signals that the task is complete to complete the thread call in EnablePlayerBattle() or EnableAllyBattle()
    /// </summary>
    public async Task DisableLeftBattle(bool startBattle, bool isCheckProcess = false)
    {
        ResetUI();

        if (!startBattle && !isCheckProcess)
            await actionText.GetTextShownStatus();
            
        uiTask = Task.CompletedTask;
        await uiTask;
    }
    /// <summary>
    /// Retrieves the action text box in the UI for indication of what is happening in the battle
    /// (NEEDED ESPECIALLY WITHOUT ANIMATIONS)
    /// </summary>
    /// <returns>The ActionTextBox within the scene and Enemy UI</returns>
    public ActionTextBox RetrieveActionText() 
        => actionText;
    /// <summary>
    /// Resets the UI back to a clear field
    /// </summary>
    public void ResetUI()
    {
        foreach (Transform child in playerField)
            Destroy(child.gameObject);

        buttons?.Clear();
    }
    /// <summary>
    /// Creates the enemy layout for the battle, including fighting, magic, items, etc.
    /// </summary>
    /// <param name="ally">Indicator if it is an Ally's turn and the data that comes with the indicator</param>
    public void EnableEnemyLayout(Entity entity)
    {
        buttons = new List<GameObject>();

        List<string> NumberOfActions = DetermineActionAmount(entity);

        for (int i = 0; i < NumberOfActions.Count; i++)
        {
            buttons.Add(Instantiate(normalButton, playerField));
            TextMeshProUGUI retainer = buttons[i].GetComponentInChildren<TextMeshProUGUI>();
            switch (NumberOfActions[i])
            {
                case "Fight":
                    retainer.text = "Fight";

                    buttons[^1].GetComponent<Button>().onClick.AddListener(() =>
                    {
                        Fight(entity, 0);
                    });

                    break;
                case "Magic":
                    retainer.text = "Magic";

                    buttons[^1].GetComponent<Button>().onClick.AddListener(() =>
                    {
                        Magic(entity);
                    });

                    // If the entity is silenced, the Magic button simply won't function
                    if (entity.GatherModList().SmartModCheck("Silenced"))
                    {
                        buttons[^1].GetComponent<Button>().interactable = false;
                        buttons[^1].GetComponent<Image>().color = new Color(.65f, .65f, .65f, 1f);
                    }

                    break;
                case "Items":
                    retainer.text = "Items";

                    buttons[^1].GetComponent<Button>().onClick.AddListener(() =>
                    {
                        Items(entity);
                    });

                    break;
                case "Check":
                    retainer.text = "Check";

                    buttons[^1].GetComponent<Button>().onClick.AddListener(() =>
                    {
                        Check(entity);
                    });

                    break;
                case "Run":
                    retainer.text = "Run";

                    buttons[^1].GetComponent<Button>().onClick.AddListener(() =>
                    {
                        Run(entity);
                    });

                    if (runUsed)
                    {
                        buttons[^1].GetComponent<Button>().interactable = false;
                        buttons[^1].GetComponent<Image>().color = Color.gray;
                    }

                    break;
                case "Dream Master":
                    retainer.text = "Dream Powers";

                    buttons[^1].GetComponent<Button>().onClick.AddListener(() =>
                    {
                        TitlePowers.DreamPowers(this, entity, buttons);
                    });
                    
                    break;
            }
        }
    }
    private List<string> DetermineActionAmount(Entity entity)
    {
        List<string> amount = new List<string>() 
        {
            "Fight",
            "Magic",
            "Items",
            "Check",
            "Run"
        };

        // Minion Check, doesn't have Check, Items, or Run
        if (entity is Ally || entity is Enemy)
        {
            bool isAlly = entity is Ally;

            if (isAlly)
            {
                if (((Ally)entity).IsMinion)
                {
                    amount.Remove("Check");
                    amount.Remove("Items");
                    amount.Remove("Run");
                    return amount;
                }
            }
            else
            {
                if (((Enemy)entity).IsMinion)
                {
                    amount.Remove("Check");
                    amount.Remove("Items");
                    amount.Remove("Run");
                    return amount;
                }
            } 
        }

        try
        {
            foreach (string title in entity.EntityFlags)
            {
                switch (title)
                {
                    case "Dream Master":
                        amount.Insert(2, "Dream Master");
                        break;
                    default:
                        break;
                }
            }
        }
        catch { }

        return amount;
    }
    /// <summary>
    /// Grays out and makes the player's options uninteractable
    /// </summary>
    public void DisableOptions()
    {
        foreach (Transform child in playerField)
        {
            child.GetComponent<Button>().interactable = false;
            child.GetComponent<Image>().color = Color.gray;
        }
    }
    /// <summary>
    /// Enables the player's options and colors them back to their normal white mode
    /// </summary>
    public void EnableOptions()
    {
        foreach (Transform child in playerField)
        {
            child.GetComponent<Button>().interactable = true;
            child.GetComponent<Image>().color = Color.white;
        }
    }
    /// <summary>
    /// Creates post-battle buttons depending on the state of the enemy encounter if the player ran away before killing all enemies
    /// </summary>
    /// <param name="ranAway">Indicator trigger if the loot button should be left out</param>
    public void CreatePostBattleButtons(bool ranAway = false)
    {
        // Cleans the slate
        ResetUI();

        buttons = new List<GameObject>();

        // Indicate stats after battle
        player.ClearModifiers();
        player.StatusChanged();
        foreach (Ally ally in Allies)
        {
            ally.ClearModifiers();
            ally.StatusChanged();
        }

        // Adds two buttons that will give the option to loot the enemies killed or to start the next encounter
        const int NumberOfActions = 2;
        for (int i = 1; i <= NumberOfActions; i++)
        {
            // If the player runs away than the loot action is simply not given
            if (i == 1 && ranAway)
                continue;

            buttons.Add(Instantiate(normalButton, playerField));
            TextMeshProUGUI retainer = buttons[^1].GetComponentInChildren<TextMeshProUGUI>();
            switch (i)
            {
                // When all enemies are killed the player can loot the items that the enemies randomly dropped during the battle
                case 1:
                    retainer.text = "Loot";
                    buttons[^1].GetComponent<Button>().onClick.AddListener(() =>
                    {
                        LootMonstersCall();
                    });
                    
                    break;
                // Starts the next encounter
                case 2:
                    retainer.text = "Leave";

                    buttons[^1].GetComponent<Button>().onClick.AddListener(() =>
                    {
                        ExitEncounter();
                    });
                    break;
            }
        }

        GeneralUI.Instance.ReactivateInventoryButton();
    }
    /// <summary>
    /// Generates the loot stash when an enemy is killed by cycling through possible loot items
    /// </summary>
    /// <param name="enemy">The enemy that holds the loot information</param>
    private void GenerateLoot(Enemy enemy)
    {
        Dictionary<ItemSO, float> lootAndChances = enemy.GetPotentialLoot();
        Vector2Int goldRange = enemy.GetGoldRange();

        // False Idol Relic Flag
        bool idolActive = Globals.RelicFlags[1];

        int itemCutoff = idolActive ? 2 : 3;

        // If the enemy is a boss more loot is dropped from the boss
        if (enemy.GetEnemyDifficulty() is Enemy.DifficultyRating.Boss)
            itemCutoff += 3;

        int counter = 0;

        // Based on the chances adds items to the loot stash to be collected at the end of the battle
        // If the itemSO is detected to be gold, the gold range is used instead to add to the stash
        foreach (KeyValuePair<ItemSO, float> loot in lootAndChances)
        {
            float v = UnityEngine.Random.Range(0f, 100f);
            bool check = v <= loot.Value;
            
            if (!check)
                continue;

            Item item;
            if (loot.Key is WeaponSO weapon)
                item = Globals.TurnWeaponFromObject(weapon);
            else if (loot.Key is ApparelSO apparel)
                item = Globals.TurnApparelFromObject(apparel);
            else if (loot.Key is ConsumableSO consume)
                item = Globals.TurnConsumableFromObject(consume);
            else
                item = Globals.TurnItemFromObject(loot.Key);

            if (currentLoot.ContainsKey(item) && item.IsUniqueItem)
                continue;

            if (!currentLoot.ContainsKey(item))
            {
                if (item.ItemName != "Gold")
                    currentLoot.Add(item, 1);
                else
                {
                    int g = UnityEngine.Random.Range(goldRange.x, goldRange.y + 1);
                    
                    if (idolActive)
                        g += (int)(Math.Floor(g * .1f));

                    currentLoot.Add(item, g);
                }

                ++counter;
                if (counter == itemCutoff)
                    break;
            }
            else
            {
                if (item.ItemName != "Gold")
                    currentLoot[item]++;
                else
                {
                    int g = UnityEngine.Random.Range(goldRange.x, goldRange.y + 1);

                    if (idolActive)
                        g += (int)(Math.Floor(g * .1f));

                    currentLoot[item] += g;
                }

                ++counter;
                if (counter == itemCutoff)
                    break;
            }
        }
    }
    /// <summary>
    /// Generates experience points based on the enemies current experience level
    /// </summary>
    /// <param name="enemy">The enemy to calculate experience from</param>
    private void GenerateExperience(Enemy enemy)
    {
        experienceGathered ??= new List<int>();

        experienceGathered.Add(enemy.GetExperienceValue());
    }
    /// <summary>
    /// Shows the loot screen and provides a button to exit
    /// </summary>
    private void LootMonstersCall()
    {
        actionText.enabled = false;
        GeneralUI.Instance.DeactivateInventoryButton();
        
        ResetUI();
        buttons = new List<GameObject>();
        GameObject go = Instantiate(normalButton, playerField);
        Button buttonRef = go.GetComponent<Button>();

        go.GetComponentInChildren<TextMeshProUGUI>().text = "Exit Looting";
        buttonRef.onClick.AddListener(() =>
        {
            ExitLootingScreen();
        });
        buttons.Add(go);

        FillLootingAspects();
         
        lootingCanvas.enabled = true;
    }
    /// <summary>
    /// Spawns in the items for both the active inventory as well as the loot available after the battle
    /// </summary>
    private void FillLootingAspects(bool lootAllUsed = false)
    {
        // Clear GUI screen if loot all button was used before reinitializing
        if (lootAllUsed)
        {
            int max = lootGrids.Count < invenGrids.Count ? invenGrids.Count : lootGrids.Count;
            for (int i = 0; i < max; ++i)
            {
                try
                {
                    Destroy(lootGrids[i]);
                }
                catch { }
                try
                {
                    Destroy(invenGrids[i]);
                }
                catch { }
            }
        }

        currentInven = player.GetInventory();

        // Fill the gold text
        goldValueText.text = player.GetInventory().GetGold().ToString();

        // Start on main player's inventory
        currentMemberText.text = player.GetName();
        currentMemberCurrentInvenCount.text = $"{currentInven.GetInvenCount()} / {currentInven.GetInvenLimit()}";

        // Turns on the activation icon for the main player and off for the rest to indicate who's inventory is open
        for (int i = 0; i < activatedIcons.Count; i++)
        {
            if (i == 0)
                activatedIcons[i].GetComponent<Image>().enabled = true;
            else
                activatedIcons[i].GetComponent<Image>().enabled = false;
        }

        // Cycles through each of the icons in the buttons 
        int counter = 0;
        foreach (GameObject icon in memberIcons)
        {
            // Tries until either all of the member icons are filled or a Arugment out of range exception is created which just turns off the buttons
            try
            {
                icon.GetComponentsInChildren<Image>()[1].enabled = true;
                icon.GetComponentsInChildren<Image>()[1].sprite = counter == 0 ? player.GetSprite() : Allies[counter - 1].GetSprite();
                icon.GetComponent<Button>().interactable = true;

                int tempVar = counter;
                icon.GetComponent<Button>().onClick.AddListener(() =>
                {
                    if (tempVar is 0)
                        SwitchInventories(player.GetInventory(), tempVar, player);
                    else
                        SwitchInventories(Allies[tempVar - 1].GetInventory(), tempVar, Allies[tempVar - 1]);
                });
            }
            catch 
            {
                icon.GetComponent<Button>().interactable = false;
                icon.GetComponent<Image>().enabled = false;
                icon.GetComponentsInChildren<Image>()[1].enabled = false;
            }

            counter++;
        }

        lootGrids = new List<GameObject>();
        invenGrids = new List<GameObject>();

        // Spawns loot within the looting canvas object with their values 
        foreach (KeyValuePair<Item, int> pair in currentLoot)
        {
            GameObject grid = Instantiate(gridObjectRef, lootingTransform);
            grid.GetComponent<DropBox>().DetectItemUISize(DropBox.DropLocations.LootStock);
            lootGrids.Add(grid);
            GameObject gen = Instantiate(itemContainerPrefab, grid.transform);
            gen.GetComponent<DraggableItem>().Type = DraggableItem.DraggableItemType.LootStock;
            ItemGUI gui = gen.GetComponent<ItemGUI>();
            gui.SwitchCostToValueText();
            gui.InjectItemInformation(pair.Key, pair.Value);
            gui.IndicateNoNameLargeSpriteWithValue();
            AspectHelperManager ahm = gen.GetComponent<AspectHelperManager>();
            ahm.InjectTransform(lootingCanvas.transform);
            ahm.InjectAspect(pair.Key);
            ahm.InjectOffset(new Vector2(-4.25f, -1.55f));
        }

        // Spawns in the player's inventory within the inventory transform indicator
        Dictionary<Item, int> currentInvenItems = currentInven.GetAllItems();
        foreach (KeyValuePair<Item, int> item in currentInvenItems)
        {
            if (item.Key.CantBeSold)
                continue;

            GameObject grid = Instantiate(gridObjectRef, inventoryTransform);
            grid.GetComponent<DropBox>().DetectItemUISize(DropBox.DropLocations.LootInventory);
            invenGrids.Add(grid);
            GameObject gen = Instantiate(itemContainerPrefab, grid.transform);
            gen.GetComponent<DraggableItem>().Type = DraggableItem.DraggableItemType.InventoryInLootScreen;
            ItemGUI gui = gen.GetComponent<ItemGUI>();
            gui.SwitchCostToValueText();
            gui.InjectItemInformation(item.Key, item.Value);
            gui.IndicateNoNameLargeSpriteWithValue();
            AspectHelperManager ahm = gen.GetComponent<AspectHelperManager>();
            ahm.InjectTransform(lootingCanvas.transform);
            ahm.InjectAspect(item.Key);
            ahm.InjectOffset(new Vector2(4.25f, -1.55f));
        }
    }
    /// <summary>
    /// Moves the full amount of the loot item into the active inventory
    /// </summary>
    /// <param name="itemGen">The item to move into the inventory</param>
    /// <param name="value">The amount of the item to move into the inventory</param>
    public void MoveToActiveInven(GameObject itemObject, Item itemGen, int value)
    {
        // Adds the gold to the collective pile
        if (itemGen.ItemName.Equals("Gold"))
        {
            player.GetInventory().AddGold(value);
            goldValueText.text = player.GetInventory().GetGold().ToString();
        }
        // Adds the item to the active inventory and instantiates it to the inventory transform
        else
        {
            bool? addedToPresentKey = DecipherItem(itemGen, value);

            if (addedToPresentKey is null)
                return;
            else if ((bool)addedToPresentKey)
            {
                // Childern are the grid holders
                foreach (Transform child in inventoryTransform)
                {
                    ItemGUI itemGUIInfo = child.transform.GetChild(0).GetComponent<ItemGUI>();

                    if (itemGUIInfo.GetAspect().ItemId == itemGen.ItemId)
                    {
                        int amount = itemGen is Weapon weap ? currentInven.Weapons[weap] :
                            (itemGen is Apparel app ? currentInven.Apparel[app] :
                            (itemGen is Consumable con ? currentInven.Consumables[con] : currentInven.Items[itemGen]));

                        itemGUIInfo.InjectItemInformation(itemGen, amount);
                        Destroy(itemObject);
                        break;
                    }
                }
            }
            else
            {
                GameObject grid = Instantiate(gridObjectRef, inventoryTransform);
                grid.GetComponent<DropBox>().Type = DropBox.DropLocations.LootInventory;
                GameObject movedItem = Instantiate(itemContainerPrefab, grid.transform);
                movedItem.GetComponent<DraggableItem>().Type = DraggableItem.DraggableItemType.InventoryInLootScreen;

                ItemGUI gui = movedItem.GetComponent<ItemGUI>();
                gui.InjectItemInformation(itemGen, value);
                gui.IndicateNoNameLargeSpriteWithValue();
                AspectHelperManager aspectMan = movedItem.GetComponent<AspectHelperManager>();
                aspectMan.InjectTransform(lootingCanvas.transform);
                aspectMan.SwitchOffsetSign(true);
                aspectMan.InjectAspect(gui.GetAspect());

                currentMemberCurrentInvenCount.text = $"{currentInven.GetInvenCount()} / {currentInven.GetInvenLimit()}";
            }
        }

        currentLoot.Remove(itemGen);
        foreach (Transform child in lootingTransform)
        {
            try
            {
                if (itemGen.ItemName.Equals(child.GetComponentInChildren<ItemGUI>().GetItemName()))
                {
                    Destroy(child.gameObject);
                    break;
                }
            }
            catch
            {
                Destroy(child.gameObject);
                break;
            }
        }
    }
    private bool? DecipherItem(Item itemGen, int value)
    {
        bool? addedItem = null;

        if (itemGen is Weapon weapon)
        {
            if (currentInven.Weapons.ContainsKey(weapon))
            {
                currentInven.Weapons[weapon] += value;
                addedItem = true;
            }
            else if (currentInven.HaveRoom())
            {
                currentInven.Add(weapon, value);
                addedItem = false;
            }
        }
        else if (itemGen is Apparel apparel)
        {
            if (currentInven.Apparel.ContainsKey(apparel))
            {
                currentInven.Apparel[apparel] += value;
                addedItem = true;
            }
            else if (currentInven.HaveRoom())
            {
                currentInven.Add(apparel, value);
                addedItem = false;
            }
        }
        else if (itemGen is Consumable consumable)
        {
            if (currentInven.Consumables.ContainsKey(consumable))
            {
                currentInven.Consumables[consumable] += value;
                addedItem = true;
            }
            else if (currentInven.HaveRoom())
            {
                currentInven.Add(consumable, value);
                addedItem = false;
            }
        }
        else
        {
            if (currentInven.Items.ContainsKey(itemGen))
            {
                currentInven.Items[itemGen] += value;
                addedItem = true;
            }
            else if (currentInven.HaveRoom())
            {
                currentInven.Add(itemGen, value);
                addedItem = false;
            }
        }

        return addedItem;
    }
    /// <summary>
    /// Move the item indicated in the player's inventory to the looting inventory transform
    /// </summary>
    /// <param name="itemPlayer">The item in the player's inventory that is wanted to be moved</param>
    /// <param name="value">The amount of the item</param>
    public void MoveToLootingInven(Item itemPlayer, int value)
    {
        if (itemPlayer is Weapon)
            currentInven.Remove(itemPlayer as Weapon, value);
        else if (itemPlayer is Apparel)
            currentInven.Remove(itemPlayer as Apparel, value);
        else if (itemPlayer is Consumable)
            currentInven.Remove(itemPlayer as Consumable, value);
        else
            currentInven.Remove(itemPlayer, value);

        bool lootContainsItem = false;
        if (currentLoot.ContainsKey(itemPlayer))
        {
            currentLoot[itemPlayer] += value;
            lootContainsItem = true;
        }
        else
            currentLoot.Add(itemPlayer, value);

        foreach (Transform t in inventoryTransform)
        {
            try
            {
                if (itemPlayer.ItemName.Equals(t.GetComponentInChildren<ItemGUI>().GetItemName()))
                {
                    Destroy(t.gameObject);
                    break;
                }
            }
            catch
            {
                Destroy(t.gameObject);
                break;
            }
        }

        if (lootContainsItem)
        {
            foreach (Transform child in lootingTransform)
            {
                ItemGUI itemGUIReference = child.GetChild(0).GetComponent<ItemGUI>();

                if (itemGUIReference.GetAspect().ItemId == itemPlayer.ItemId)
                {
                    itemGUIReference.InjectItemInformation(itemPlayer, currentLoot[itemPlayer]);   
                    break;
                }
            }
        }
        else
        {
            GameObject grid = Instantiate(gridObjectRef, lootingTransform);
            grid.GetComponent<DropBox>().Type = DropBox.DropLocations.LootStock;
            GameObject newLootItem = Instantiate(itemContainerPrefab, grid.transform);
            newLootItem.GetComponent<DraggableItem>().Type = DraggableItem.DraggableItemType.LootStock;
            ItemGUI gui = newLootItem.GetComponent<ItemGUI>();
            gui.InjectItemInformation(itemPlayer, value);
            gui.IndicateNoNameLargeSpriteWithValue();
            AspectHelperManager aspectMan = newLootItem.GetComponent<AspectHelperManager>();
            aspectMan.InjectTransform(lootingCanvas.transform);
            aspectMan.SwitchOffsetSign(false);
            aspectMan.InjectAspect(gui.GetAspect());
        }
    }
    /// <summary>
    /// Exits the looting screen for the player
    /// </summary>
    private void ExitLootingScreen()
    {
        lootingCanvas.enabled = false;

        ClearLootingTransforms();
        CreatePostBattleButtons();

        actionText.enabled = true;
        GeneralUI.Instance.ReactivateInventoryButton();
    }
    /// <summary>
    /// Switches the inventory active by the buttons on the left of the looting screen designated by party member icons
    /// </summary>
    /// <param name="inven">The inventory to switch to</param>
    /// <param name="index">The reference to which activation symbol should highlight whose inventory is active</param>
    /// <param name="ally">Data for if an allies inventory is selected</param>
    private void SwitchInventories(Inventory inven, int index, Entity entity)
    {
        if (currentInven == inven)
            return;

        ClearLootingTransforms(true);
        currentInven = inven;

        // Fill the gold text
        goldValueText.text = player.GetInventory().GetGold().ToString();

        // Start on main player's inventory
        currentMemberText.text = entity.GetName();
        currentMemberCurrentInvenCount.text = $"{currentInven.GetInvenCount()} / {currentInven.GetInvenLimit()}";

        // Turns on the activation icon for the main player and off for the rest to indicate who's inventory is open
        for (int i = 0; i < activatedIcons.Count; i++)
        {
            if (i == index)
                activatedIcons[i].GetComponent<Image>().enabled = true;
            else
                activatedIcons[i].GetComponent<Image>().enabled = false;
        }

        // Spawns in the player's inventory within the inventory transform indicator
        Dictionary<Item, int> currentInvenItems = currentInven.GetAllItems();
        invenGrids?.Clear();
        invenGrids = new List<GameObject>();
        foreach (KeyValuePair<Item, int> item in currentInvenItems)
        {
            if (item.Key.CantBeSold)
                return;

            GameObject grid = Instantiate(gridObjectRef, inventoryTransform);
            grid.GetComponent<DropBox>().DetectItemUISize(DropBox.DropLocations.LootInventory);
            invenGrids.Add(grid);
            GameObject gen = Instantiate(itemContainerPrefab, grid.transform);

            gen.GetComponent<Button>().onClick.AddListener(() =>
            {
                MoveToLootingInven(item.Key, item.Value);
            });
            ItemGUI gui = gen.GetComponent<ItemGUI>();
            gui.SwitchCostToValueText();
            gui.InjectItemInformation(item.Key, item.Value);
            AspectHelperManager ahm = gen.GetComponent<AspectHelperManager>();
            ahm.InjectAspect(gui.GetAspect());
            ahm.InjectTransform(lootingCanvas.transform);
            ahm.InjectOffset(new Vector2(4.25f, -1.55f));
        }
    }
    /// <summary>
    /// Takes all of the items in the loot stash up to the player's max inventory, to which items will remain in the stash
    /// </summary>
    public void LootAll()
    {
        // No loot, don't bother checking rest
        if (currentLoot.Count is 0)
            return;

        Dictionary<Item, int> allItems = currentInven.GetAllItems();
        List<Item> itemsCollected = new List<Item>();
        foreach (KeyValuePair<Item, int> item in currentLoot)
        {
            // Special check if it is gold
            if (item.Key.ItemName.Equals("Gold"))
            {
                player.GetInventory().AddGold(item.Value);
                itemsCollected.Add(item.Key);
                continue;
            }

            bool? addedItem = DecipherItem(item.Key, item.Value);

            if (addedItem is null)
                break;

            // Add to the garbage list
            itemsCollected.Add(item.Key);
        }

        // Throw away all of the items that were retrieved in the current loot stash
        itemsCollected.ForEach(item => currentLoot.Remove(item));

        // Then refresh the GUIs to show the loot collected 
        FillLootingAspects(true);
    }
    /// <summary>
    /// Clears the looting transforms, both the player's inventory and looting inventory
    /// </summary>
    /// <param name="clearOnlyPlayerInven">Trigger for if just the inventory should be cleared</param>
    private void ClearLootingTransforms(bool clearOnlyPlayerInven = false)
    {
        if (clearOnlyPlayerInven)
        {
            foreach (Transform t in inventoryTransform)
                Destroy(t.gameObject);
        }
        else
        {
            foreach (Transform t in lootingTransform)
                Destroy(t.gameObject);
            foreach (Transform t in inventoryTransform)
                Destroy(t.gameObject);
        }
    }
    public void DisableSpellButtonInteractivity(Entity entity)
    {
        buttons.ForEach(b =>
        {
            Button button = b.GetComponent<Button>();
            // When the cancel button is found than a new listener replaces the current one to Re-enable the buttons when clicked
            if (b.GetComponentInChildren<TextMeshProUGUI>().text == "Cancel")
            {
                b.GetComponentInChildren<TextMeshProUGUI>().text = "Cancel Spell";
                button.onClick.RemoveAllListeners();
                button.onClick.AddListener(() =>
                {
                    ReEnableSpellButtons(entity);
                });

                button.interactable = true;
            }
            else
            {
                // Disables the buttons and grays them out
                button.interactable = false;
                b.GetComponent<Image>().color = Globals.DisabledColor;
            }
        });
    }
    /// <summary>
    /// Switches methods on the Cancel button and disables the other item buttons
    /// </summary>
    /// <param name="entity">The entity that is currently active, ally or player</param>
    public void DisableItemButtonInteractivity(Entity entity)
    {
        buttons.ForEach(b =>
        {
            Button button = b.GetComponent<Button>();
            if (b.GetComponentInChildren<TextMeshProUGUI>().text == "Cancel")
            {
                b.GetComponentInChildren<TextMeshProUGUI>().text = "Cancel Item";
                button.onClick.RemoveAllListeners();
                button.onClick.AddListener(() =>
                {
                    ReEnableItemButtons(entity);
                });

                button.interactable = true;
            }
            else
            {
                // Disable item buttons and gray them out
                button.interactable = false;
                b.GetComponent<Image>().color = Globals.DisabledColor;
            }
        });
    }
    /// <summary>
    /// Colors in the buttons and sets their interactivity if they are able to be used based on the 
    /// player's current mana pool, also switches the Cancel buttons listener method
    /// </summary>
    public void ReEnableSpellButtons(Entity entity)
    {
        // Cancel's the spell attempting to be used in the battle handler
        battleComponent.CancelSpellUse();

        List<Spell> spellList = new List<Spell>(entity.GetInventory().Spells);
        spellList.AddRange(entity.GetInventory().limitedSpells);
        for (int i = 0; i < buttons.Count; i++)
        {
            Button button = buttons[i].GetComponent<Button>();

            // Resets the Cancel button to the proper Cancel listener
            if (buttons[i].GetComponentInChildren<TextMeshProUGUI>().text == "Cancel Spell")
            {
                buttons[i].GetComponentInChildren<TextMeshProUGUI>().text = "Cancel";
                button.onClick.RemoveAllListeners();
                button.onClick.AddListener(() =>
                {
                    if (entity is not Ally)
                        Cancel(entity as Player);
                    else
                        Cancel(entity as Ally);
                });
                return;
            }

            // Re-enables the buttons before checking to be sure that the button needs to be active based on the user's mana
            button.interactable = true;
            buttons[i].GetComponent<Image>().color = Color.white;

            CheckSpellUseStatus(spellList, i, buttons[i], entity);
        }
    }
    /// <summary>
    /// Reactivates the Item Buttons for the designated entity, which should be the active ally or player,
    /// before switching back the Cancel button method and the interactibility of the rest of the item buttons
    /// </summary>
    /// <param name="entity">The current active player or ally</param>
    public void ReEnableItemButtons(Entity entity)
    {
        battleComponent.CancelItemUse();

        foreach (GameObject gObj in buttons)
        {
            Button b = gObj.GetComponent<Button>();

            // Resets the Cancel button to the proper Cancel listener
            if (gObj.GetComponentInChildren<TextMeshProUGUI>().text == "Cancel Item")
            {
                gObj.GetComponentInChildren<TextMeshProUGUI>().text = "Cancel";
                b.onClick.RemoveAllListeners();
                b.onClick.AddListener(() =>
                {
                    if (entity is not Ally)
                        Cancel(null);
                    else
                        Cancel(entity as Ally);
                });
                return;
            }

            b.interactable = true;
            b.GetComponent<Image>().color = Color.white;
        }
    }
    /// <summary>
    /// Initializes the check process that targets an enemy for information
    /// </summary>
    /// <param name="enemy">The enemy which is being analyzed</param>
    private async void BeginCheckProcess(Enemy enemy)
    {
        // Enemy component requires CheckCameraUtil
        CheckCameraUtil ccUtil = enemy.GetComponent<CheckCameraUtil>();

        checkTrackCamera.Follow = ccUtil.AcquireTrackingPoint();

        ResetUI();
        await ccUtil.StartCheckDialogue(checkTrackCamera);
        battleComponent.DisablePlayerTurn(true);
    }
    /// <summary>
    /// Injects a minion component that is deciphered into either TempAllies or TempEnemies
    /// </summary>
    /// <param name="entity">The entity component</param>
    public void InjectTempMinion(Entity entity)
    {
        // Checks if an allied minion is being added
        bool isAlly = entity is Ally;

        // Simply resize and append the entity component to the end of either
        // needed array
        if (isAlly)
        {
            if (TempAllies is null)
                TempAllies = new Ally[1];
            else
                Array.Resize(ref TempAllies, TempAllies.Length + 1);

            TempAllies[^1] = entity as Ally;
        }
        else
        {
            if (TempEnemies is null)
                TempEnemies = new Enemy[1];
            else
                Array.Resize(ref TempEnemies, TempEnemies.Length + 1);

            TempEnemies[^1] = entity as Enemy;
        }
    }
    /// <summary>
    /// Erases the entity component value from either TempAllies or TempEnemies depending on the child factor of the Entity component
    /// </summary>
    /// <param name="entity">The entity component to clear</param>
    public void DestroyTempMinion(Entity entity)
    {
        bool isAlly = entity is Ally;

        if (isAlly)
        {
            Ally allyComp = entity as Ally;
            int minionArrayLength = TempAllies.Length;

            // Resizes the ally minion array to disinclude the entity component parameter
            for (int i = 0; i < minionArrayLength; ++i)
            {
                if (TempAllies[i].GetUniqueID() == allyComp.GetUniqueID())
                {
                    for (int k = i; k < minionArrayLength - 1; ++k)
                    {
                        TempAllies[k] = TempAllies[k + 1];
                        TempAllies[k + 1] = null;
                    }

                    Array.Resize(ref TempAllies, minionArrayLength - 1);
                }
            }

            if (TempAllies.Length is 0)
                TempAllies = null;
        }
        else
        {
            Enemy enemyComp = entity as Enemy;
            int minionArrayLength = TempEnemies.Length;

            // Resizes the enemy minion array to disinclude the entity component parameter
            for (int i = 0; i < TempEnemies.Length; ++i)
            {
                if (TempEnemies[i].GetUniqueID() == enemyComp.GetUniqueID())
                {
                    for (int k = i; k < minionArrayLength - 1; ++k)
                    {
                        TempEnemies[k] = TempEnemies[k + 1];
                        TempEnemies[k + 1] = null;
                    }

                    Array.Resize(ref TempEnemies, minionArrayLength - 1);
                }
            }

            if (TempEnemies.Length is 0)
                TempEnemies = null;
        }
    }
    /// <summary>
    /// Simply just wipes out the arrays for minions
    /// </summary>
    public void ClearTempMinions()
    {
        TempAllies  = null;
        TempEnemies = null;
    }
    /// <summary>
    /// Deactivates the post battle buttons when the inventory is opened
    /// </summary>
    public void DeactivatePostBattleButtons()
    {
        foreach (GameObject button in buttons)
        {
            button.GetComponent<Button>().interactable = false;
            button.GetComponent<Image>().color = new Color(.65f, .65f, .65f, 1f);
        }
    }
    /// <summary>
    /// Reactivates the post battle buttons when the inventory is closed
    /// </summary>
    public void ReactivatePostBattleButtons()
    {
        foreach (GameObject button in buttons)
        {
            button.GetComponent<Button>().interactable = true;
            button.GetComponent<Image>().color = Color.white;
        }
    }
    public void SwitchMemberTurnText(bool status)
        => currentEntityTurnText.enabled = status;
    /// <summary>
    /// Gives any experience that was collected in this enemy Encounter
    /// </summary>
    /// <param name="player">The player component</param>
    /// <param name="allyComps">The ally components</param>
    public void GiveExperience(Player player, Ally[] allyComps)
    {
        int totalExp = 0;
        
        if (experienceGathered != null)
        {
            // Check for any experience modifiers
            foreach (int expVal in experienceGathered)
            {
                int retainedExpVal = expVal;

                if (player.GetInventory().Abilities.Contains(AbilityBrain.GetAbilityList()[26]) || player.GetInventory().limitedAbilities.Contains(AbilityBrain.GetAbilityList()[26]))
                    retainedExpVal += (int)(expVal * .25f);

                foreach (Ally ally in allyComps)
                {
                    if (ally.GetInventory().Abilities.Contains(AbilityBrain.GetAbilityList()[26]) || ally.GetInventory().limitedAbilities.Contains(AbilityBrain.GetAbilityList()[26]))
                        retainedExpVal += (int)(expVal * .25f);
                }

                totalExp += retainedExpVal;
            }
        }

        if (totalExp is not 0)
        {
            // Increase experience by the total amount and check for any level ups
            Dictionary<int, bool> levelUpMap = new Dictionary<int, bool>
            {
                { 0, player.IncreaseExperience(totalExp) }
            };

            int counter = 1;
            foreach (Ally ally in allyComps)
                levelUpMap.Add(counter++, ally.IncreaseExperience(totalExp));
        } 
    }

    private Entity revivalTarget;
    private bool canceledChoice;

    public async Task<(bool choice, Entity spellTarget)> ProvideDeadChoices(List<Entity> deadEntities)
    {
        ResetUI();

        int counter = 0;
        foreach (Entity deadEntity in deadEntities)
        {
            GameObject buttons = Instantiate(normalButton, playerField);
            deadEntity.gameObject.SetActive(true);
            buttons.GetComponentInChildren<TextMeshProUGUI>().text = deadEntity.GetName();
            buttons.GetComponent<Button>().onClick.AddListener(() =>
            {
                InjectDeadTarget(counter++, deadEntities);
            });
        }

        canceledChoice = false;
        revivalTarget = null;

        while (revivalTarget == null)
            await Task.Yield();        

        ResetUI();
        return (!canceledChoice, revivalTarget);
    }

    public void InjectDeadTarget(int indexValue, List<Entity> deadEntities)
    {
        try
        {
            revivalTarget = deadEntities[indexValue];
            deadEntities.Remove(revivalTarget);
        }
        catch 
        {
            canceledChoice = true;
        }
    }
}