/**
         * @brief Run through all enemies and decide what actions to take. (Should only be called after the player has made their turn)
         * */
        public void DecideEnemyTurns()
        {
            for (int i = 0; i < EnemyEntities.Count; ++i)
            {
                // Randomly pick a party member to attack
                PartyEntity targetPlayer = GetPartyEntityBySlot((ePartySlot)Random.Range(0, PartyMembers.Length));

                // Invalid target, find first conscious party member instead
                if (targetPlayer.CurrentStatus == eStatusEffect.UNCONSCIOUS)
                {
                    foreach (var party in PartyEntities)
                    {
                        if (party.CurrentStatus != eStatusEffect.UNCONSCIOUS)
                        {
                            targetPlayer = party;
                        }
                    }
                }

                EnemyEntity senderEnemy = EnemyEntities[i];

                _commandList.Add(new TECF.EntityCommand
                {
                    cmdType = TECF.eCommandType.ATTACK,
                    sender  = senderEnemy,
                    target  = targetPlayer
                });
            }
        }
        void OnRunThroughCommands(IEventInfo a_info)
        {
            // Sort list by sender turn order (highest to lowest)
            _commandList.Sort((a, b) => - (CalcTurnVal(a.sender.BattleProfile.Speed).CompareTo(CalcTurnVal(b.sender.BattleProfile.Speed))));

            // Go through command list and execute appropriate actions
            foreach (var cmd in _commandList)
            {
                switch (cmd.cmdType)
                {
                case TECF.eCommandType.ATTACK:
                    /// Get ready function
                    PartyEntity party          = cmd.sender as PartyEntity;
                    UnityAction partyReadyFunc = null;

                    // Party is attacking, ready them
                    if (party != null)
                    {
                        partyReadyFunc = () =>
                        {
                            EventManager.TriggerEvent("OnPartyReady", new PartyInfo {
                                partySlot = party.partySlot
                            });
                        };
                    }
                    // Enemy is attacking, unready all other party members
                    else
                    {
                        partyReadyFunc = () =>
                        {
                            EventManager.TriggerEvent("PartyUnready", new PartyInfo {
                                partySlot = ePartySlot.NONE
                            });
                        };
                    }

                    /// Attacking dialog
                    DialogManager.Instance.AddToQueue(new DialogInfo
                    {
                        dialogType         = eDialogType.ATTACKING,
                        senderEntity       = cmd.sender,
                        targetEntity       = cmd.target,
                        endDialogFuncDelay = ActionLineSwitchRate,
                        startDialogFunc    = partyReadyFunc
                    });

                    /// 1. Check for miss
                    int missNum    = Random.Range(0, 100);
                    int missChance = Mathf.RoundToInt(ChanceToMiss * 100);

                    // Missed attack
                    if (missNum <= missChance)
                    {
                        DialogManager.Instance.AddToQueue(new DialogInfo
                        {
                            dialogType         = TECF.eDialogType.MISS,
                            senderEntity       = cmd.sender,
                            targetEntity       = cmd.target,
                            endDialogFuncDelay = ActionLineSwitchRate
                        });

                        // No need to check other steps
                        break;
                    }

                    /// 2. Check for dodge
                    int dodgeNum    = Random.Range(0, 100);
                    int dodgeChance = Mathf.RoundToInt(((2 * cmd.target.BattleProfile.Speed - cmd.sender.BattleProfile.Speed) / 500f) * 100);

                    // Dodge success
                    if (dodgeNum <= dodgeChance)
                    {
                        DialogManager.Instance.AddToQueue(new DialogInfo
                        {
                            dialogType         = TECF.eDialogType.DODGED,
                            senderEntity       = cmd.sender,
                            targetEntity       = cmd.target,
                            endDialogFuncDelay = ActionLineSwitchRate
                        });

                        // No need to check other steps
                        break;
                    }

                    /// 3. Confirmed hit, calculate damage
                    int attackDmg = Mathf.RoundToInt(CalcDmgVal(eStatusEffect.NORMAL, cmd.sender, cmd.target));

                    /// 4. Check for critical hit
                    int critNum          = Random.Range(0, 100);
                    int firstCritChance  = Mathf.RoundToInt((cmd.sender.BattleProfile.Guts / 500f) * 100);
                    int secondCritChance = Mathf.RoundToInt((1f / 20f) * 100);
                    int critChance       = Mathf.Max(firstCritChance, secondCritChance);

                    // Crit success
                    if (critNum <= critChance)
                    {
                        DialogManager.Instance.AddToQueue(new DialogInfo
                        {
                            dialogType   = TECF.eDialogType.CRITICAL_HIT,
                            senderEntity = cmd.sender,
                            targetEntity = cmd.target
                        });

                        attackDmg *= CriticalHitModifier;
                    }

                    /// 5. Send damage to the target after dialog finishes
                    DialogManager.Instance.AddToQueue(new DialogInfo
                    {
                        strData         = attackDmg.ToString(),
                        dialogType      = TECF.eDialogType.DAMAGED,
                        senderEntity    = cmd.sender,
                        targetEntity    = cmd.target,
                        startDialogFunc = () =>
                        {
                            EventManager.TriggerEvent("TakeDamage", new DamageInfo
                            {
                                dmg          = attackDmg,
                                senderEntity = cmd.sender,
                                targetEntity = cmd.target,
                                statusEffect = eStatusEffect.NORMAL
                            });
                        },
                        endDialogFuncDelay = ActionLineSwitchRate
                    });

                    break;

                default:
                    break;
                }
            }

            // Gone through all commands, clear the list
            _commandList.Clear();

            // Activate action phase dialog
            EventManager.TriggerEvent("RunDialog", new DialogRunInfo
            {
                onDialogCompleteFunc = () => { EventManager.TriggerEvent("EndActionPhase"); }
            });
        }
        private void Start()
        {
            CurrPartySlot = ePartySlot.NONE;

            /// Priority enemy
            BattleProfile priorityEnemy = Enemies[0];  // Enemy in first slot influences visuals and audio of whole battle

            Debug.Assert(priorityEnemy, "BATTLEMANAGER::No enemies set!");

            // Set enemy background
            ReferenceManager.Instance.enemyBG.sprite = priorityEnemy.BattleBackground;

            // Add enemy audio to main system and secondary systems
            ReferenceManager.Instance.mainAudio.AudioFiles.AddRange(priorityEnemy.BattleSFX);
            ReferenceManager.Instance.secondaryAudio.AudioFiles.AddRange(priorityEnemy.BattleSFX);

            // Start battle music, playing intro first if there is one
            AudioClip introClip = ReferenceManager.Instance.mainAudio.HasClip("INTRO");

            if (introClip)
            {
                // Play intro and then play main loop after it
                ReferenceManager.Instance.mainAudio.SetLooping(false);
                ReferenceManager.Instance.mainAudio.PlayClip("{\"alias\":\"INTRO\",\"volume\":1}");

                ReferenceManager.Instance.secondaryAudio.SetLooping(true);
                ReferenceManager.Instance.secondaryAudio.PlayClipWithDelay("{\"alias\":\"LOOP\",\"volume\":1}", introClip.length, true);
            }
            else if (ReferenceManager.Instance.mainAudio.HasClip("LOOP"))
            {
                ReferenceManager.Instance.mainAudio.SetLooping(true);
                ReferenceManager.Instance.mainAudio.PlayClip("{\"alias\":\"LOOP\",\"volume\":1}");
            }

            /// Enemies
            for (int i = 0; i < Enemies.Length; ++i)
            {
                GameObject  eObj = Instantiate(EnemyBlueprint);
                EnemyEntity eEe  = eObj.GetComponent <EnemyEntity>();

                // Set to relevant slot
                eEe.enemySlot = (eEnemySlot)i;

                // Set type
                eEe.EntityType = eEntityType.ENEMY;

                // Assign battle profile
                eEe.BattleProfile = Enemies[i];

                // Keep track of enemy entity
                EnemyEntities.Add(eEe);

                eObj.transform.SetParent(ReferenceManager.Instance.enemyPanel.transform);
            }

            /// Party members
            for (int i = 0; i < PartyMembers.Length; ++i)
            {
                GameObject  pmObj = Instantiate(PartyBlueprint);
                PartyEntity pmPe  = pmObj.GetComponentInChildren <PartyEntity>();

                // Assign battle profile
                pmPe.BattleProfile = PartyMembers[i];

                // Set type
                pmPe.EntityType = eEntityType.PARTY;

                // Set to relevant slot
                pmPe.partySlot = (ePartySlot)i;

                // Keep track of party entity
                PartyEntities.Add(pmPe);

                pmObj.transform.SetParent(ReferenceManager.Instance.partyPanel.transform);
            }
        }