void JustReachedHome() override
 {
     if (m_pInstance)
     {
         if (m_pInstance->GetData(TYPE_FACTION_CHAMPIONS) != FAIL)
             m_pInstance->SetData(TYPE_FACTION_CHAMPIONS, FAIL);
     }
 }
    void Aggro(Unit* /*pWho*/) override
    {
        DoScriptText(SAY_AGGRO, m_creature);
        DoCastSpellIfCan(m_creature, SPELL_SURGE_OF_LIGHT);

        if (m_pInstance && m_pInstance->GetData(TYPE_TWIN_VALKYR) != IN_PROGRESS)
            m_pInstance->SetData(TYPE_TWIN_VALKYR, IN_PROGRESS);
    }
    void JustDied(Unit* /*pKiller*/) override
    {
        DoScriptText(SAY_DEATH, m_creature);

        if (m_pInstance && m_pInstance->GetData(TYPE_TWIN_VALKYR) != DONE)
            m_pInstance->SetData(TYPE_TWIN_VALKYR, DONE);

        DoCastSpellIfCan(m_creature, SPELL_CLEAR_VALKYR_ESSENCE, CAST_TRIGGERED);
        DoCastSpellIfCan(m_creature, SPELL_CLEAR_VALKYR_TOUCH, CAST_TRIGGERED);
    }
 void Aggro(Unit* pWho) override
 {
     if (m_pInstance)
     {
         if (m_pInstance->GetData(TYPE_FACTION_CHAMPIONS) != IN_PROGRESS)
         {
             m_pInstance->SetData(TYPE_FACTION_CHAMPIONS, IN_PROGRESS);
             m_pInstance->DoSetCrusadersInCombat(pWho);
         }
     }
 }
    void EnterEvadeMode() override
    {
        if (m_pInstance && m_pInstance->GetData(TYPE_TWIN_VALKYR) != FAIL)
            m_pInstance->SetData(TYPE_TWIN_VALKYR, FAIL);

        DoCastSpellIfCan(m_creature, SPELL_CLEAR_VALKYR_ESSENCE, CAST_TRIGGERED);
        DoCastSpellIfCan(m_creature, SPELL_CLEAR_VALKYR_TOUCH, CAST_TRIGGERED);

        // cleanup handled by creature linking
        m_creature->ForcedDespawn();
    }
    void UpdateAI(const uint32 uiDiff) override
    {
        if (!m_creature->SelectHostileTarget() || !m_creature->getVictim())
            return;

        if (m_uiTwinSpikeTimer < uiDiff)
        {
            if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_TWIN_SPIKE_DARK) == CAST_OK)
                m_uiTwinSpikeTimer = 10000;
        }
        else
            m_uiTwinSpikeTimer -= uiDiff;

        // heroic abilities
        if (m_pInstance && m_pInstance->IsHeroicDifficulty())
        {
            if (m_uiTouchTimer < uiDiff)
            {
                if (DoCastSpellIfCan(m_creature, SPELL_DARK_TOUCH) == CAST_OK)
                    m_uiTouchTimer = 20000;
            }
            else
                m_uiTouchTimer -= uiDiff;
        }

        DoMeleeAttackIfReady();
    }
    void JustSummoned(Creature* pSummoned) override
    {
        switch (pSummoned->GetEntry())
        {
            case NPC_GORMOK:     m_uiPhase = PHASE_GORMOK;  break;
            case NPC_DREADSCALE: m_uiPhase = PHASE_WORMS;   break;
            case NPC_ICEHOWL:    m_uiPhase = PHASE_ICEHOWL; break;
            case NPC_ACIDMAW:
                // Cast emerge and delayed set in combat?
                pSummoned->SetInCombatWithZone();
                m_aSummonedBossGuid[3] = pSummoned->GetObjectGuid();
                return;
        }

        m_aSummonedBossGuid[m_uiPhase] = pSummoned->GetObjectGuid();

        pSummoned->SetWalk(false);
        pSummoned->GetMotionMaster()->MovePoint(m_uiPhase, aMovePositions[m_uiPhase][0], aMovePositions[m_uiPhase][1], aMovePositions[m_uiPhase][2], false);

        // Next beasts are summoned only for heroic modes
        if (m_creature->GetMap()->GetDifficulty() == RAID_DIFFICULTY_10MAN_HEROIC || m_creature->GetMap()->GetDifficulty() == RAID_DIFFICULTY_25MAN_HEROIC)
            m_uiNextBeastTimer = 150 * IN_MILLISECONDS;     // 2 min 30

        m_uiAttackDelayTimer = 10000;

        if (m_pInstance)
            m_pInstance->DoOpenMainGate(10000);
    }
    void JustDied(Unit* /*pKiller*/) override
    {
        DoScriptText(SAY_DEATH, m_creature);

        if (m_pInstance)
            m_pInstance->SetData(TYPE_ANUBARAK, DONE);
    }
    void KilledUnit(Unit* pVictim) override
    {
        if (!m_pInstance)
            return;

        Creature* pSpeaker = m_pInstance->GetSingleCreatureFromStorage(m_pInstance->GetPlayerTeam() == ALLIANCE ? NPC_GARROSH : NPC_VARIAN);
        if (!pSpeaker)
            return;

        switch (urand(0, 3))
        {
            case 0: DoScriptText(m_pInstance->GetPlayerTeam() == ALLIANCE ? SAY_GARROSH_PVP_A_SLAY_1 : SAY_VARIAN_PVP_H_SLAY_1, pSpeaker); break;
            case 1: DoScriptText(m_pInstance->GetPlayerTeam() == ALLIANCE ? SAY_GARROSH_PVP_A_SLAY_2 : SAY_VARIAN_PVP_H_SLAY_2, pSpeaker); break;
            case 2: DoScriptText(m_pInstance->GetPlayerTeam() == ALLIANCE ? SAY_GARROSH_PVP_A_SLAY_3 : SAY_VARIAN_PVP_H_SLAY_3, pSpeaker); break;
            case 3: DoScriptText(m_pInstance->GetPlayerTeam() == ALLIANCE ? SAY_GARROSH_PVP_A_SLAY_4 : SAY_VARIAN_PVP_H_SLAY_4, pSpeaker); break;
        }
    }
    // Only for Dreadscale and Icehowl
    void DoSummonNextBeast(uint32 uiBeastEntry)
    {
        if (uiBeastEntry == NPC_DREADSCALE)
        {
            if (Creature* pTirion = m_pInstance->GetSingleCreatureFromStorage(NPC_TIRION_A))
                DoScriptText(SAY_TIRION_BEAST_2, pTirion);

            m_creature->SummonCreature(NPC_DREADSCALE, aSpawnPositions[2][0], aSpawnPositions[2][1], aSpawnPositions[2][2], aSpawnPositions[2][3], TEMPSUMMON_DEAD_DESPAWN, 0);
        }
        else
        {
            if (Creature* pTirion = m_pInstance->GetSingleCreatureFromStorage(NPC_TIRION_A))
                DoScriptText(SAY_TIRION_BEAST_3, pTirion);

            m_creature->SummonCreature(NPC_ICEHOWL, aSpawnPositions[4][0], aSpawnPositions[4][1], aSpawnPositions[4][2], aSpawnPositions[4][3], TEMPSUMMON_DEAD_DESPAWN, 0);
        }
    }
    void SummonedCreatureJustDied(Creature* pSummoned) override
    {
        if (!m_pInstance)
            return;

        switch (pSummoned->GetEntry())
        {
            case NPC_GORMOK:
                if (m_uiPhase == PHASE_GORMOK)
                    DoSummonNextBeast(NPC_DREADSCALE);
                break;

            case NPC_DREADSCALE:
            case NPC_ACIDMAW:
                if (m_bFirstWormDied && m_uiPhase == PHASE_WORMS)
                {
                    DoSummonNextBeast(NPC_ICEHOWL);

                    // cast achiev spell if timer is still running
                    if (m_uiWormAchievTimer)
                    {
                        m_creature->CastSpell(m_creature, SPELL_JORMUNGAR_ACHIEV_CREDIT, TRIGGERED_OLD_TRIGGERED);
                        m_uiWormAchievTimer = 0;
                    }
                }
                else
                {
                    m_bFirstWormDied = true;

                    // jormungar brother enrages
                    if (Creature* pWorm = m_pInstance->GetSingleCreatureFromStorage(pSummoned->GetEntry() == NPC_ACIDMAW ? NPC_DREADSCALE : NPC_ACIDMAW))
                    {
                        pWorm->CastSpell(pWorm, SPELL_JORMUNGAR_ENRAGE, TRIGGERED_OLD_TRIGGERED);
                        DoScriptText(EMOTE_JORMUNGAR_ENRAGE, pWorm);
                        m_uiWormAchievTimer = 10000;
                    }
                }
                break;

            case NPC_ICEHOWL:
                m_pInstance->SetData(TYPE_NORTHREND_BEASTS, DONE);
                m_creature->ForcedDespawn();
                break;
        }
    }
 void Aggro(Unit* /*pWho*/) override
 {
     // trigger the controller combat
     if (m_pInstance)
     {
         if (Creature* pStalker = m_pInstance->GetSingleCreatureFromStorage(NPC_BEASTS_COMBAT_STALKER))
             pStalker->SetInCombatWithZone();
     }
 }
    void EnterEvadeMode() override
    {
        if (m_pInstance)
            m_pInstance->SetData(TYPE_NORTHREND_BEASTS, FAIL);

        for (uint8 i = 0; i < 4; ++i)
        {
            if (Creature* pBoss = m_creature->GetMap()->GetCreature(m_aSummonedBossGuid[i]))
                pBoss->ForcedDespawn();
        }

        m_creature->ForcedDespawn();
    }
    void Reset() override
    {
        // get the list of summoned stalkers and move to a randome one
        if (m_pInstance)
            m_pInstance->GetStalkersGUIDVector(m_vStalkersGuids);

        if (m_vStalkersGuids.empty())
            return;

        m_creature->SetWalk(false);
        if (Creature* pStalker = m_creature->GetMap()->GetCreature(m_vStalkersGuids[urand(0, m_vStalkersGuids.size() - 1)]))
            m_creature->GetMotionMaster()->MovePoint(1, pStalker->GetPositionX(), pStalker->GetPositionY(), pStalker->GetPositionZ());
    }
    void Reset() override
    {
        DoCastSpellIfCan(m_creature, SPELL_VALKYR_TWINS_HITTING_YA);

        m_uiTwinSpikeTimer      = 7000;
        m_uiTouchTimer          = 10000;
        m_uiSpecialAbilityTimer = 45000;
        m_uiSummonTimer         = 25000;
        m_uiBerserkTimer        = 8 * MINUTE * IN_MILLISECONDS;

        // always start with light twin pact
        m_bIsLightTwin          = true;
        m_bIsVortex             = false;

        if (m_pInstance && m_pInstance->IsHeroicDifficulty())
            m_uiBerserkTimer    = 6 * MINUTE * IN_MILLISECONDS;
    }
    void Aggro(Unit* /*pWho*/) override
    {
        DoScriptText(SAY_AGGRO, m_creature);

        // Summon the spheres on random points
        for (uint8 i = 0; i < MAX_FROSTSPHERES; ++i)
        {
            if (Creature* pTemp = m_creature->SummonCreature(NPC_FROSTSPHERE, aFrostSphereSpawnPositions[i][0], aFrostSphereSpawnPositions[i][1], aFrostSphereSpawnPositions[i][2], 0, TEMPSUMMON_DEAD_DESPAWN, 0))
                m_vSpheresGuidVector[i] = pTemp->GetObjectGuid();
        }

        // It's not clear if these should be spawned by DB or summoned
        for (uint8 i = 0; i < MAX_BURROWS; ++i)
            m_creature->SummonCreature(NPC_BURROW, aBurrowSpawnPositions[i][0], aBurrowSpawnPositions[i][1], aBurrowSpawnPositions[i][2], aBurrowSpawnPositions[i][3], TEMPSUMMON_DEAD_DESPAWN, 0);

        if (m_pInstance)
            m_pInstance->SetData(TYPE_ANUBARAK, IN_PROGRESS);
    }
    // function that handles the special ability for both twins
    bool DoCastSpecialAbility()
    {
        if (!m_pInstance)
            return false;

        // choose the caster; it always alternates
        Unit* pCaster = NULL;
        uint32 uiSpell = 0;
        uint32 uiShieldSpell = 0;

        if (m_bIsLightTwin)
            pCaster = m_creature;
        else
        {
            Creature* pEydis = m_pInstance->GetSingleCreatureFromStorage(NPC_EYDIS);
            if (!pEydis)
                return false;

            pCaster = pEydis;
        }

        if (!pCaster)
            return false;

        // select and cast ability
        if (m_bIsVortex)
        {
            uiSpell = m_bIsLightTwin ? SPELL_LIGHT_VORTEX : SPELL_DARK_VORTEX;
            pCaster->CastSpell(pCaster, uiSpell, TRIGGERED_NONE);
            DoScriptText(m_bIsLightTwin ? SAY_TO_WHITE : SAY_TO_BLACK, pCaster);
        }
        else
        {
            uiSpell = m_bIsLightTwin ? SPELL_TWINS_PACT_LIGHT : SPELL_TWINS_PACT_DARK;
            uiShieldSpell = m_bIsLightTwin ? SPELL_SHIELD_OF_LIGHTS : SPELL_SHIELD_OF_DARKNESS;
            pCaster->CastSpell(pCaster, uiSpell, TRIGGERED_NONE);
            pCaster->CastSpell(pCaster, uiShieldSpell, TRIGGERED_OLD_TRIGGERED);
            DoScriptText(SAY_COLORSWITCH, pCaster);
        }

        m_bIsVortex = urand(0, 1) ? true : false;
        m_bIsLightTwin = !m_bIsLightTwin;
        return true;
    }
    void SpellHit(Unit* /*pCaster*/, const SpellEntry* pSpell) override
    {
        if (pSpell->Id == SPELL_SUBMERGE)
        {
            m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);

            // Extra check here, because AnubArak must be submerged by default
            if (m_Phase != PHASE_SUBMERGING)
                return;

            m_Phase = PHASE_UNDERGROUND;

            // Refresh spheres only on normal difficulty
            if (m_pInstance && !m_pInstance->IsHeroicDifficulty())
                DoRefreshSpheres();

            DoCastSpellIfCan(m_creature, SPELL_CLEAR_ALL_DEBUFFS, CAST_TRIGGERED);
            DoCastSpellIfCan(m_creature, SPELL_SUMMON_SPIKES, CAST_TRIGGERED);
            DoCastSpellIfCan(m_creature, SPELL_SUMMON_SCARAB, CAST_TRIGGERED);
        }
    }
    void UpdateAI(const uint32 uiDiff) override
    {
        if (m_uiNextBeastTimer)
        {
            if (m_uiNextBeastTimer <= uiDiff)
            {
                if (m_uiPhase == PHASE_GORMOK)
                    DoSummonNextBeast(NPC_DREADSCALE);
                else if (m_uiPhase == PHASE_WORMS)
                    DoSummonNextBeast(NPC_ICEHOWL);

                m_uiNextBeastTimer = 0;
            }
            else
                m_uiNextBeastTimer -= uiDiff;
        }

        if (m_uiAttackDelayTimer)
        {
            if (m_uiAttackDelayTimer <= uiDiff)
            {
                // for worm phase, summon brother on aggro
                if (m_uiPhase == PHASE_WORMS)
                {
                    m_creature->SummonCreature(NPC_ACIDMAW, aSpawnPositions[3][0], aSpawnPositions[3][1], aSpawnPositions[3][2], aSpawnPositions[3][3], TEMPSUMMON_DEAD_DESPAWN, 0);
                    m_uiWormPhaseTimer = 45000;
                }

                // start combat
                if (Creature* pBeast = m_creature->GetMap()->GetCreature(m_aSummonedBossGuid[m_uiPhase]))
                {
                    pBeast->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_OOC_NOT_ATTACKABLE);

                    // first boss doesn't automatically attack
                    if (pBeast->GetEntry() != NPC_GORMOK)
                        pBeast->SetInCombatWithZone();
                }

                m_uiAttackDelayTimer = 0;
            }
            else
                m_uiAttackDelayTimer -= uiDiff;
        }

        if (m_uiBerserkTimer)
        {
            if (m_uiBerserkTimer < uiDiff)
            {
                for (uint8 i = 0; i < 4; ++i)
                {
                    Creature* pBoss = m_creature->GetMap()->GetCreature(m_aSummonedBossGuid[i]);
                    if (pBoss && pBoss->isAlive())
                        pBoss->CastSpell(pBoss, SPELL_BERSERK, TRIGGERED_OLD_TRIGGERED);
                }
            }
            else
                m_uiBerserkTimer -= uiDiff;
        }

        // jormungars phase switch control
        if (m_uiWormPhaseTimer)
        {
            if (m_uiWormPhaseTimer <= uiDiff)
            {
                if (!m_pInstance)
                    return;

                ++m_uiWormPhaseStage;

                switch (m_uiWormPhaseStage)
                {
                    // submerge worms
                    case 1:
                        if (Creature* pWorm = m_pInstance->GetSingleCreatureFromStorage(NPC_ACIDMAW))
                        {
                            if (pWorm->isAlive())
                                SendAIEvent(AI_EVENT_CUSTOM_A, m_creature, pWorm);
                        }
                        if (Creature* pWorm = m_pInstance->GetSingleCreatureFromStorage(NPC_DREADSCALE))
                        {
                            if (pWorm->isAlive())
                                SendAIEvent(AI_EVENT_CUSTOM_A, m_creature, pWorm);
                        }

                        m_uiWormPhaseTimer = 4000;
                        break;

                    // change places
                    case 2:
                        float fX, fY, fZ;
                        if (Creature* pWorm = m_pInstance->GetSingleCreatureFromStorage(NPC_ACIDMAW))
                        {
                            if (pWorm->isAlive())
                            {
                                m_creature->GetRandomPoint(m_creature->GetPositionX(), m_creature->GetPositionY(), m_creature->GetPositionZ(), 45.0f, fX, fY, fZ);
                                pWorm->MonsterMoveWithSpeed(fX, fY, fZ, 7.7f);
                            }
                        }
                        if (Creature* pWorm = m_pInstance->GetSingleCreatureFromStorage(NPC_DREADSCALE))
                        {
                            if (pWorm->isAlive())
                            {
                                m_creature->GetRandomPoint(m_creature->GetPositionX(), m_creature->GetPositionY(), m_creature->GetPositionZ(), 45.0f, fX, fY, fZ);
                                pWorm->MonsterMoveWithSpeed(fX, fY, fZ, 7.7f);
                            }
                        }

                        m_uiWormPhaseTimer = 6000;
                        break;

                    // emerge and change phase
                    case 3:
                        if (Creature* pWorm = m_pInstance->GetSingleCreatureFromStorage(NPC_ACIDMAW))
                        {
                            if (pWorm->isAlive())
                                SendAIEvent(AI_EVENT_CUSTOM_B, m_creature, pWorm);
                        }
                        if (Creature* pWorm = m_pInstance->GetSingleCreatureFromStorage(NPC_DREADSCALE))
                        {
                            if (pWorm->isAlive())
                                SendAIEvent(AI_EVENT_CUSTOM_B, m_creature, pWorm);
                        }

                        m_uiWormPhaseStage = 0;
                        m_uiWormPhaseTimer = 45000;
                        break;
                }
            }
            else
                m_uiWormPhaseTimer -= uiDiff;
        }

        // jormungars achiev timer
        if (m_uiWormAchievTimer)
        {
            if (m_uiWormAchievTimer <= uiDiff)
                m_uiWormAchievTimer = 0;
            else
                m_uiWormAchievTimer -= uiDiff;
        }

        m_creature->SelectHostileTarget();
    }
    void UpdateAI(const uint32 uiDiff) override
    {
        if (!m_creature->SelectHostileTarget() || !m_creature->getVictim())
            return;

        // special ability spell
        if (m_uiSpecialAbilityTimer < uiDiff)
        {
            if (DoCastSpecialAbility())
                m_uiSpecialAbilityTimer = 45000;
        }
        else
            m_uiSpecialAbilityTimer -= uiDiff;

        if (m_uiSummonTimer < uiDiff)
        {
            DoCastSpellIfCan(m_creature, SPELL_LIGHT_BULLET_SUMMON_TRIGGER, CAST_TRIGGERED);
            DoCastSpellIfCan(m_creature, SPELL_DARK_BULLET_SUMMON_TRIGGER, CAST_TRIGGERED);
            m_uiSummonTimer = 30000;
        }
        else
            m_uiSummonTimer -= uiDiff;

        // berserk spell
        if (m_uiBerserkTimer)
        {
            if (m_uiBerserkTimer <= uiDiff)
            {
                // handle berserk for both twins
                if (DoCastSpellIfCan(m_creature, SPELL_BERSERK) == CAST_OK)
                {
                    if (m_pInstance)
                    {
                        if (Creature* pEydis = m_pInstance->GetSingleCreatureFromStorage(NPC_EYDIS))
                        {
                            pEydis->CastSpell(pEydis, SPELL_BERSERK, TRIGGERED_OLD_TRIGGERED);
                            DoScriptText(SAY_BERSERK, pEydis);
                        }
                    }

                    DoScriptText(SAY_BERSERK, m_creature);
                    m_uiBerserkTimer = 0;
                }
            }
            else
                m_uiBerserkTimer -= uiDiff;
        }

        if (m_uiTwinSpikeTimer < uiDiff)
        {
            if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_TWIN_SPIKE_LIGHT) == CAST_OK)
                m_uiTwinSpikeTimer = 10000;
        }
        else
            m_uiTwinSpikeTimer -= uiDiff;

        // heroic abilities
        if (m_pInstance && m_pInstance->IsHeroicDifficulty())
        {
            if (m_uiTouchTimer < uiDiff)
            {
                if (DoCastSpellIfCan(m_creature, SPELL_LIGHT_TOUCH) == CAST_OK)
                    m_uiTouchTimer = 20000;
            }
            else
                m_uiTouchTimer -= uiDiff;
        }

        DoMeleeAttackIfReady();
    }
    void UpdateAI(const uint32 uiDiff) override
    {
        if (!m_creature->SelectHostileTarget() || !m_creature->getVictim())
            return;

        if (m_bIsFuriousCharge)
        {
            if (m_uiFuriosChargeTimer < uiDiff)
            {
                switch (m_uiFuriousChargeStage)
                {
                    case 0:
                        // pick a target
                        if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0, uint32(0), SELECT_FLAG_PLAYER | SELECT_FLAG_IN_LOS))
                        {
                            DoScriptText(EMOTE_MASSIVE_CRASH, m_creature, pTarget);
                            m_creature->SummonCreature(NPC_FURIOUS_CHARGE_STALKER, pTarget->GetPositionX(), pTarget->GetPositionY(), pTarget->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN, 35000);
                        }

                        // apply surge of adrenaline
                        if (m_pInstance && !m_pInstance->IsHeroicDifficulty())
                            DoApplySurgeOfAdrenaline();

                        m_uiFuriosChargeTimer = 1000;
                        break;

                    case 1:
                        // roar at target
                        if (Creature* pTarget = m_creature->GetMap()->GetCreature(m_chargeStalkerGuid))
                            DoCastSpellIfCan(pTarget, SPELL_ROAR);

                        m_uiFuriosChargeTimer = 2000;
                        break;

                    case 2:
                        // jump back and prepare to charge
                        if (Creature* pTarget = m_creature->GetMap()->GetCreature(m_chargeStalkerGuid))
                            DoCastSpellIfCan(pTarget, SPELL_JUMP_BACK);

                        m_uiFuriosChargeTimer = 2000;
                        break;

                    case 3:
                        // charge to the target
                        m_creature->SetSpeedRate(MOVE_RUN, m_fSpeedRate * 4);
                        if (Creature* pTarget = m_creature->GetMap()->GetCreature(m_chargeStalkerGuid))
                            m_creature->GetMotionMaster()->MovePoint(POINT_ID_CHARGE_END, pTarget->GetPositionX(), pTarget->GetPositionY(), pTarget->GetPositionZ());

                        m_uiFuriosChargeTimer = 99999;
                        break;
                }
                ++m_uiFuriousChargeStage;
            }
            else
                m_uiFuriosChargeTimer -= uiDiff;

            // no other actions during charge
            return;
        }

        if (m_uiMassiveCrashTimer < uiDiff)
        {
            SetCombatMovement(false);
            m_creature->InterruptNonMeleeSpells(false);
            m_creature->GetMotionMaster()->Clear();
            m_creature->GetMotionMaster()->MoveJump(aSpawnPositions[0][0], aSpawnPositions[0][1], aSpawnPositions[1][2], 2 * m_creature->GetSpeed(MOVE_RUN), 10.0f, POINT_ID_CHARGE_BEGIN);

            m_bIsFuriousCharge      = true;
            m_uiFuriousChargeStage  = 0;
            m_uiFuriosChargeTimer   = 99999;
            m_uiMassiveCrashTimer   = urand(40000, 45000);
        }
        else
            m_uiMassiveCrashTimer -= uiDiff;

        if (m_uiWhirlTimer < uiDiff)
        {
            if (DoCastSpellIfCan(m_creature, SPELL_WHIRL) == CAST_OK)
                m_uiWhirlTimer = urand(15000, 20000);
        }
        else
            m_uiWhirlTimer -= uiDiff;

        if (m_uiArticBreathTimer < uiDiff)
        {
            if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_ARCTIC_BREATH) == CAST_OK)
                m_uiArticBreathTimer = urand(25000, 30000);
        }
        else
            m_uiArticBreathTimer -= uiDiff;

        if (m_uiFerociousButtTimer < uiDiff)
        {
            if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_FEROCIOUS_BUTT) == CAST_OK)
                m_uiFerociousButtTimer = 15000;
        }
        else
            m_uiFerociousButtTimer -= uiDiff;

        DoMeleeAttackIfReady();
    }
 void Aggro(Unit* /*pWho*/) override
 {
     if (m_pInstance)
         m_pInstance->SetData(TYPE_NORTHREND_BEASTS, IN_PROGRESS);
 }
 void JustReachedHome() override
 {
     if (m_pInstance)
         m_pInstance->SetData(TYPE_ANUBARAK, FAIL);
 }
    void UpdateAI(const uint32 uiDiff) override
    {
        if (!m_creature->SelectHostileTarget() || !m_creature->getVictim())
            return;

        // Call specific virtual function
        if (!UpdateCrusaderAI(uiDiff))
            return;

        if (m_uiAbilityTimer < uiDiff)
        {
            uint8 uiIndex = urand(0, m_uiMaxAbilities - 1);
            uint32 uiMinHealth = m_pAbilityArray[uiIndex].m_uiMinHealth;
            uint8 uiTargetType = m_pAbilityArray[uiIndex].m_uiTargetType;

            SelectFlags spellSelectFlag = m_pAbilityArray[uiIndex].m_selectFlag;

            // check timers and health condition
            // only cast spells that have timers expired
            // also check for health percentage for self cast spells
            if (m_uiSpellTimer[uiIndex] || (uiTargetType == TARGET_TYPE_SELF && uiMinHealth && m_creature->GetHealthPercent() > uiMinHealth))
            {
                 m_uiAbilityTimer = 2000;
                 return;
            }
            else
            {
                uint32 uiSpellId = m_pAbilityArray[uiIndex].m_uiSpellId;

                // special case for heroism / bloodlust
                if (uiSpellId == SPELL_HEROISM && m_pInstance && m_pInstance->GetPlayerTeam() == ALLIANCE)
                    uiSpellId = SPELL_BLOODLUST;

                if (CanUseSpecialAbility(uiSpellId, uiTargetType, spellSelectFlag, uiMinHealth))
                {
                    m_uiSpellTimer[uiIndex] = m_pAbilityArray[uiIndex].m_uiCooldown;
                    m_uiAbilityTimer = urand(2000, 6000);
                }
                else
                    m_uiAbilityTimer = 2000;
            }
        }
        else
            m_uiAbilityTimer -= uiDiff;

        // spell cooldown
        for (uint8 i = 0; i < m_uiMaxAbilities; ++i)
        {
            if (m_uiSpellTimer[i])
            {
                if (m_uiSpellTimer[i] <= uiDiff)
                    m_uiSpellTimer[i] = 0;
                else
                    m_uiSpellTimer[i] -= uiDiff;
            }
        }

        // Change target
        if (m_uiResetThreatTimer < uiDiff)
        {
            if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 1))
            {
                DoResetThreat();
                AttackStart(pTarget);
                m_uiResetThreatTimer = urand(5000, 15000);
            }
        }
        else
            m_uiResetThreatTimer -= uiDiff;

        // CC check for PVP trinket
        if (m_uiIsCCTimer < uiDiff)
        {
            if (m_creature->isFrozen() || m_creature->hasUnitState(UNIT_STAT_CAN_NOT_REACT))
            {
                // Pvp trinket only in heroic mode
                if (m_pInstance && m_pInstance->IsHeroicDifficulty() && !m_uiTrinketCooldownTimer)
                {
                    if (DoCastSpellIfCan(m_creature, SPELL_PVP_TRINKET, CAST_TRIGGERED) == CAST_OK)
                        m_uiTrinketCooldownTimer = 120000;
                }

                SendAIEventAround(AI_EVENT_GOT_CCED, NULL, 0, CRUSADER_AIEVENT_THROW_RADIUS);
                SendAIEvent(AI_EVENT_GOT_CCED, NULL, m_creature);
                m_uiIsCCTimer = 5000;
            }
            else
                m_uiIsCCTimer = 2000;
        }
        else
            m_uiIsCCTimer -= uiDiff;

        // trinket cooldown
        if (m_uiTrinketCooldownTimer)
        {
            if (m_uiTrinketCooldownTimer <= uiDiff)
                m_uiTrinketCooldownTimer = 0;
            else
                m_uiTrinketCooldownTimer -= uiDiff;
        }

        DoMeleeAttackIfReady();
    }
    void UpdateAI(const uint32 uiDiff) override
    {
        if (!m_creature->SelectHostileTarget() || !m_creature->getVictim())
            return;

        switch (m_Phase)
        {
            case PHASE_GROUND:

                // Switch to underground phase on timer
                if (m_PhaseSwitchTimer < uiDiff)
                {
                    if (DoCastSpellIfCan(m_creature, SPELL_SUBMERGE) == CAST_OK)
                    {
                        DoScriptText(SAY_SUBMERGE, m_creature);
                        DoScriptText(EMOTE_BURROW, m_creature);
                        m_PhaseSwitchTimer = 63000;
                        m_Phase = PHASE_SUBMERGING;
                        return;
                    }
                }
                else
                    m_PhaseSwitchTimer -= uiDiff;

                // Switch to phase 3 when below 30%
                if (m_creature->GetHealthPercent() <= 30.0f)
                {
                    if (DoCastSpellIfCan(m_creature, SPELL_LEECHING_SWARM) == CAST_OK)
                    {
                        DoScriptText(SAY_LEECHING_SWARM, m_creature);
                        DoScriptText(EMOTE_LEECHING_SWARM, m_creature);
                        m_Phase = PHASE_LEECHING_SWARM;
                    }
                }

                // No break - the spells are used in both phase 1 and 3
            case PHASE_LEECHING_SWARM:

                if (m_uiFreezingSlashTimer < uiDiff)
                {
                    if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_FREEZING_SLASH) == CAST_OK)
                        m_uiFreezingSlashTimer = 20000;
                }
                else
                    m_uiFreezingSlashTimer -= uiDiff;

                if (m_uiPenetratingColdTimer < uiDiff)
                {
                    if (DoCastSpellIfCan(m_creature, SPELL_PENETRATING_COLD) == CAST_OK)
                        m_uiPenetratingColdTimer = 15000;
                }
                else
                    m_uiPenetratingColdTimer -= uiDiff;

                // The Borrowers are summoned in Ground phase only on normal mode or during Ground and Swarm phase on heroic mode
                if (m_Phase == PHASE_GROUND || (m_pInstance && m_pInstance->IsHeroicDifficulty()))
                {
                    if (m_uiBurrowerSummonTimer < uiDiff)
                    {
                        // The number of targets is handled in core, based on difficulty
                        if (DoCastSpellIfCan(m_creature, SPELL_SUMMON_NERUBIAN_BURROWER) == CAST_OK)
                            m_uiBurrowerSummonTimer = 45000;
                    }
                    else
                        m_uiBurrowerSummonTimer -= uiDiff;
                }

                DoMeleeAttackIfReady();

                break;

            case PHASE_UNDERGROUND:

                // Underground phase is finished
                if (m_PhaseSwitchTimer < uiDiff)
                {
                    DoCastSpellIfCan(m_creature, SPELL_EMERGE, CAST_TRIGGERED);
                    DoCastSpellIfCan(m_creature, SPELL_TELEPORT_TO_SPIKE, CAST_TRIGGERED);
                    DoScriptText(EMOTE_EMERGE, m_creature);
                    DoDespawnPursuingSpikes();

                    m_creature->RemoveAurasDueToSpell(SPELL_SUBMERGE);
                    m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);

                    // Refresh spheres only on normal difficulty
                    if (m_pInstance && !m_pInstance->IsHeroicDifficulty())
                        DoRefreshSpheres();

                    m_PhaseSwitchTimer = 80000;
                    m_Phase = PHASE_GROUND;
                }
                else
                    m_PhaseSwitchTimer -= uiDiff;

                break;
            case PHASE_SUBMERGING:                          // Do nothing, but continue berserk timer
                break;
        }

        if (m_uiBerserkTimer)
        {
            if (m_uiBerserkTimer <= uiDiff)
            {
                if (m_Phase != PHASE_UNDERGROUND)
                {
                    if (DoCastSpellIfCan(m_creature, SPELL_BERSERK) == CAST_OK)
                    {
                        DoScriptText(SAY_BERSERK, m_creature);
                        m_uiBerserkTimer = 0;
                    }
                }
            }
            else
                m_uiBerserkTimer -= uiDiff;
        }
    }