All pastes #798774 Raw Edit

Something

public text v1 · immutable
#798774 ·published 2007-11-27 00:37 UTC
rendered paste body
/* Copyright (C) 2006,2007 ScriptDev2 <https://scriptdev2.svn.sourceforge.net/>
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/

/* ScriptData
SDName: boss_illidan_stormrage
SD%Complete: 80
SDComment: Need to do Eye Blast, Cage Traps, Enrage, Transform cosmetics and adjust timers.
EndScriptData */

/***************************************/
/* This script is still in development */
/*   by Wolfdragon and Moriquendu      */
/***************************************/

/******** Includes ************/
#include "../../sc_defines.h"
#include "../../../../../game/TargetedMovementGenerator.h"
#include "../../../../../shared/WorldPacket.h"
#include "../../../../../game/SpellAuras.h"
#include "../../../../../game/Player.h"
#include "../../../../../game/GossipDef.h"

/************* Quotes and Sounds ***********************/
// Gossip for when a player clicks Akama
#define GOSSIP_ITEM          "We are ready to face Illidan"

// Intro speech with Akama
#define SAY_INTRO_ILL1        "Akama... your duplicity is hardly surprising. I should have slaughtered you and your malformed brethren long ago."
#define SOUND_INTRO_ILL1    11463 // ~13 seconds
#define SAY_INTRO_AKA1        "We've come to end your reign, Illidan. My people and all of Outland shall be free!"
#define SOUND_INTRO_AKA1    11389 // ~12 seconds
#define SAY_INTRO_ILL2        "Boldly said. But I remain unconvinced."
#define SOUND_INTRO_ILL2    11464 // ~8 seconds
#define SAY_INTRO_AKA2        "The time has come! The moment is at hand!"
#define SOUND_INTRO_AKA2    11380 // ~5 seconds
#define SAY_INTRO_ILL3        "You are not prepared!" // He conjectures that your level of preparation could perhaps be improved somewhat
#define SOUND_INTRO_ILL3    11466

// Signal for Akama to leave
#define SAY_AKAMA_MINION    "Come, my minions. Deal with this traitor as he deserves!"
#define SOUND_AKAMA_MINION  11465
#define SAY_AKAMA_LEAVE     "I'll deal with these mongrels. Strike now, friends! Strike at the betrayer!"
#define SOUND_AKAMA_LEAVE   11390

// Taunts?
#define SAY_HATRED          "I can feel your hatred"
#define SOUND_HATRED        11467
#define SAY_FEAR            "Give in to your fear!"
#define SOUND_FEAR          11468
#define SAY_POWER           "You know nothing of power!"
#define SOUND_POWER         11469
#define SAY_ARROGANCE       "Such..arrogance!"
#define SOUND_ARROGANCE     11471
#define SAY_RABBLE          "I will not be touched by rabble such as you!"
#define SOUND_RABBLE        11479

// Attacking Maeiv
#define SAY_ATT_MAIEV        "Feel the hatred of ten thousand years!"
#define SOUND_ATT_MAIEV        11470

// Self explanatory
#define SAY_KILL1            "Who shall be next to taste my blades?!"
#define SOUND_KILL1            11473
#define SAY_KILL2            "This is too easy!"
#define SOUND_KILL2            11472

// I think I'll fly now and let my subordinates take you on
#define SAY_PHASE2            "Behold the flames of Azzinoth!"
#define SOUND_PHASE2        11480

// When casting Eye Blast. Demon Fire will be appear on places that he casts this
#define SAY_EYE_BLAST      "Stare into the eyes of the Betrayer!"
#define SOUND_EYE_BLAST     11481

// kk, I go big, dark and demon on you.
#define SAY_MORPH            "Behold the power... of the demon within!"
#define SOUND_MORPH            11475

// I KILL!
#define SAY_ENRAGE            "You've wasted too much time mortals, now you shall fall!"
#define SOUND_ENRAGE        11474

// Speech when Maiev enters
#define SAY_SUMMON_MAIEV    "Is this it, mortals? Is this all the fury you can muster?"
#define SOUND_SUMMON_MAIEV    11476 // ~8 seconds
#define SAY_MAIEV1            "Their fury pales before mine, Illidan. We have some unsettled business between us."
#define SOUND_MAIEV1        11491 // ~9 seconds
#define SAY_MAIEV_ILL2        "Maiev... How is this even possible?"
#define SOUND_MAIEV_ILL2    11477 // ~7 seconds
#define SAY_MAIEV2            "Ah, my long hunt is finally over. Today, Justice will be done!"
#define SOUND_MAIEV2        11492 // ~10 seconds

// Death speech
#define SAY_DEATH_MAIEV1    "Ahh... It is finished. You are beaten."
#define SOUND_DEATH_MAIEV1    11496 // ~6 seconds
#define SAY_DEATH_ILL        "You have won... Maiev. But the huntress... is nothing without the hunt. You... are nothing... without me."
#define SOUND_DEATH_ILL        11478 // ~22 seconds
#define SAY_DEATH_MAIEV2    "He's right. I feel nothing. I am nothing. Farewell, champions."
#define SOUND_DEATH_MAIEV2    11497 // ~9 seconds
#define SAY_DEATH_AKA        "The Light will fill these dismal halls once again. I swear it."
#define SOUND_DEATH_AKA        11387 // ~8 seconds

/************** Spells *************/
// Normal Form
#define SPELL_SHEAR                     41032 // Reduces Max. Health by 60% for 7 seconds. Can stack 19 times. 1.5 second cast
#define SPELL_FLAME_CRASH               40832 // Summons an invis/unselect passive mob that has an aura of flame in a circle around him.
#define SPELL_DRAW_SOUL                 40904 // 5k Shadow Damage in front of him. Heals Illidan for 100k health (script effect)
#define SPELL_PARASITIC_SHADOWFIEND     41917 // DoT of 3k Shadow every 2 seconds. Lasts 10 seconds. (Script effect: Summon 2 parasites once the debuff has ticked off)
#define SPELL_AGONIZING_FLAMES          40932 // 4k fire damage initial to target and anyone w/i 5 yards. PHASE 3 ONLY
// Flying (Phase 2)
#define SPELL_FIREBALL                  40598 // 2.5k-3.5k damage in 10 yard radius. 2 second cast time.
#define SPELL_EYE_BLAST                 39908 // Fiery blue beam across platform. Deals ~20k fire damage, spawns Demon Fire on ground for 1 minute.
#define SPELL_DEMON_FIRE                40029 // Blue fire trail left by Eye Blast. Deals 2k per second if players stand on it.
#define SPELL_DARK_BARRAGE              40585 // 10 second channeled spell, 3k shadow damage per second.
// Demon Form
#define SPELL_DEMON_FORM                40506 // Transforms into Demon Illidan. Has an Aura of Dread on him.
#define SPELL_SHADOW_BLAST              41078 // 8k - 11k Shadow Damage. Targets highest threat. Has a splash effect, damaging anyone in 20 yards of the target.
#define SPELL_FLAME_BURST               41126 // Hurls fire at entire raid for ~3.5k damage every 10 seconds. Resistable. (Does not work: Script effect)
#define SPELL_FLAME_BURST_EFFECT        41131 // The actual damage. Have each player cast it on itself (workaround)
// Other Illidan spells
#define SPELL_KNEEL                     39656 // Before beginning encounter, this is how he appears (talking to skully).
#define SPELL_SHADOW_PRISON             40647 // Illidan casts this spell to immobilize entire raid when he summons Maiev.
#define SPELL_DEATH                     40220 // This spell doesn't do anything except stun Illidan and set him on his knees.
#define SPELL_SELF_ROOT                 42716 // Use this to disable Illidan from running to Akama during the Intro speech.

// Non-Illidan spells
#define SPELL_HEALING_POTION            40535 // Akama uses this to heal himself to full.
#define SPELL_GREEN_BEAM                39165 // Glaives cast it on Flames. Not sure if this is the right spell.
#define SPELL_PARALYZE                  41083 // Shadow Demons cast this on their target
#define SPELL_PURPLE_BEAM               39123 // Purple Beam connecting Shadow Demon to their target
#define SPELL_CAGE_TRAP_DUMMY           40761 // Put this in DB for cage trap GO.

/***** Locations *******/
// Locations for spawning glaives.
#define X_GLAIVE1                       695.105
#define X_GLAIVE2                       659.338
#define Y_GLAIVE                        305.303
#define Z_GLAIVE                        354.256

/**** Creature Summon IDs ****/
#define CREATURE_GLAIVE_OF_AZZINOTH     22824
#define CREATURE_FLAME_OF_AZZINOTH      22997
#define CREATURE_MAIEV_SHADOWSONG       23197
#define CREATURE_SHADOW_DEMON           23375

struct Yells
{
    float sound;
    char* text;
    char* creature;
    uint32 timer, emote;
    bool Talk;
};

static Yells Conversation[]=
{
    {11463, "Akama... your duplicity is hardly surprising. I should have slaughtered you and your malformed brethren long ago.", "Illidan", 13000, 0, true},
    {11389, "We've come to end your reign, Illidan. My people and all of Outland shall be free!", "Akama", 12000, 0, true},
    {11464, "Boldly said. But I remain unconvinced.", "Illidan", 8000, 0, true},
    {11380, "The time has come! The moment is at hand!", "Akama", 5000, 0, true},
    {11466, "You are not prepared!", "Illidan", 0, 0, false},
    {11476, "Is this it, mortals? Is this all the fury you can muster?", "Illidan", 8000, 0, true},
    {11491, "Their fury pales before mine, Illidan. We have some unsettled business between us.", "Maiev", 9000, 0, true},
    {11477, "Maiev... How is this even possible?", "Illidan", 7000, 0, true},
    {11492, "Ah... my long hunt is finally over. Today, Justice will be done!", "Maiev", 10000, 0, true},
    {11493, "Feel the hatred of ten thousand years!", "Illidan", 1000, 0, false},
    {11496, "Ahh... It is finished. You are beaten.", "Maiev", 6000, 0, true},
    {11478, "You have won... Maiev...but the huntress... is nothing...without the hunt... you... are nothing... without me..", "Illidan", 22000, 0, true},
    {11497, "He is right. I feel nothing... I am nothing... Farewell, champions.", "Maiev", 9000, 0, true},
    {11386, "The Light will fill these dismal halls once again. I swear it.", "Akama", 8000, 0, true}
};

static Yells RandomTaunts[]=
{
    {11467, "I can feel your hatred", "Illidan", 0, 0, false},
    {11468, "Give in to your fear!", "Illidan", 0, 0, false},
    {11469, "You know nothing of power!", "Illidan", 0, 0, false},
    {11471, "Such... arrogance!", "Illidan", 0, 0, false},
    {11479, "I will not be touched by rabble such as you!", "Illidan", 0, 0, false}
};

struct Locations
{
    float x, y, z;
};

static Locations Flight[]=
{
    {692, 331, 353},
    {713, 309, 366},
    {687, 271, 353},
    {650, 285, 353},
    {653, 331, 371}
};

/******* The AI *******/
struct MANGOS_DLL_SPEC boss_illidan_stormrageAI : public ScriptedAI
{
    boss_illidan_stormrageAI(Creature* c) : ScriptedAI(c)
    {
        pInstance = ((ScriptedInstance*)c->GetInstanceData());
        SetVariables();
    }

    /** Instance Data **/
    ScriptedInstance* pInstance;

    /** Generic **/
    bool InCombat;
    bool IsTalking;
    bool HasSummoned;
    uint32 Phase;
    uint32 GlobalTimer;
    uint32 TalkCount;
    uint32 DemonFormSequence;

    /** GUIDs **/
    uint64 FlameGUID[1];
    uint64 GlaiveGUID[1];
    uint64 AkamaGUID;
    uint64 MaievGUID;

    /** Timers **/
    uint32 ShearTimer;
    uint32 DrawSoulTimer;
    uint32 FlameCrashTimer;
    uint32 ParasiticShadowFiendTimer;
    uint32 FlyTimer;
    uint32 FireballTimer;
    uint32 EyeBlastTimer;
    uint32 DarkBarrageTimer;
    uint32 AgonizingFlamesTimer;
    uint32 ShadowBlastTimer;
    uint32 FlameBurstTimer;
    uint32 FlameBurstExplosionTimer;
    uint32 ShadowDemonTimer;
    uint32 SummonTimer;
    uint32 TalkTimer;
    uint32 TransformTimer;
    uint32 EnrageTimer;
    uint32 AnimationTimer;
    uint32 TauntTimer; // This is used for his random yells

    void SetVariables()
    {
        Phase = 1;
        /*   1 = Normal form
             2 = Flying. Raid attacks Flames of Azzinoth
             3 = Normal form, casts Agonizing Flames + can transform to Demon form
             4 = Demon Form.
             5 = Normal form with Agonizing Flames + Demon form + Maiev
        */

        // If in combat, check if any flames/glaives are alive/existing. Kill if alive and set GUIDs to 0
        for(uint8 i = 0; i < 2; i++)
        {
            if(FlameGUID[i])
            {
                if(InCombat)
                {
                    Unit* Flame = Unit::GetUnit((*m_creature), FlameGUID[i]);
                    if(Flame) Flame->DealDamage(Flame, Flame->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_NORMAL, NULL, 0, false);
                }
                FlameGUID[i] = 0;
            }

            if(GlaiveGUID[i])
            {
                if(InCombat)
                {
                    Unit* Glaive = Unit::GetUnit((*m_creature), GlaiveGUID[i]);
                    if(Glaive) Glaive->DealDamage(Glaive, Glaive->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_NORMAL, NULL, 0, false);
                }
                GlaiveGUID[i] = 0;
            }
        }

        InCombat = false;
        IsTalking = false;
        HasSummoned = false;
        AkamaGUID = 0;
        MaievGUID = 0;
        GlobalTimer = 0;
        TalkCount = 0;
        TalkTimer = 0;
        DemonFormSequence = 0;

        /** Normal Form **/
        ShearTimer = 20000 + (rand()%10 * 100); // 20 to 30 seconds
        FlameCrashTimer = 30000; //30 seconds
        ParasiticShadowFiendTimer = 25000; // 25 seconds
        DrawSoulTimer = 35000; // 35 seconds

        /** Phase 2 **/
        FlyTimer = 20000; // Make him fly to various spots
        SummonTimer = 10000; // Phase 2 timers may be incorrect
        FireballTimer = 5000;
        DarkBarrageTimer = 45000;
        EyeBlastTimer = 30000;

        /** Phase 3+ **/
        AgonizingFlamesTimer = 35000; // Phase 3+ timers may be incorrect
        ShadowBlastTimer = 3000;
        FlameBurstTimer = 20000;
        FlameBurstExplosionTimer = 22000;
        ShadowDemonTimer = 15000;
        TransformTimer = 60000;
        EnrageTimer = 15000;
        AnimationTimer = 0;

        TauntTimer = 30000; // This timer may be off.

        DoCast(m_creature, SPELL_SELF_ROOT, true);
        DoCast(m_creature, SPELL_KNEEL); // Illidan starts off talking to skully
        m_creature->setFaction(35); // Start him off as friendly.
        //m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); // Do not be attacked (use this instead of UNIT_FLAG_NOT_ATTACK since AoEs still target him)
    }

    void EnterEvadeMode()
    {
        SetVariables();

        m_creature->RemoveAllAuras();
        m_creature->DeleteThreatList();
        m_creature->CombatStop();
        DoGoHome();
    }

    void AttackStart(Unit *who)
    {
        if(!who || IsTalking || Phase == 2)
            return;
        
        if (who->isTargetableForAttack() && who!= m_creature)
        {
            //Begin melee attack if we are within range
            DoStartMeleeAttack(who);

            if (!InCombat) InCombat = true;
        }
    }

    void MoveInLineOfSight(Unit *who)
    {
        if (!who || m_creature->getVictim())
            return;

        if (who->isTargetableForAttack() && who->isInAccessablePlaceFor(m_creature) && m_creature->IsHostileTo(who))
        {
            float attackRadius = m_creature->GetAttackDistance(who);
            if (m_creature->IsWithinDistInMap(who, attackRadius) && m_creature->GetDistanceZ(who) <= CREATURE_Z_ATTACK_RANGE && m_creature->IsWithinLOSInMap(who))
            {
                if(who->HasStealthAura())
                    who->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH);

                if (!InCombat) InCombat = true;

                DoStartMeleeAttack(who);
            }
        }
    }

    void JustDied(Unit *killer)
    {
        SetVariables(); // Reset variables for respawn.
    }

    void KilledUnit(Unit *victim)
    {
        if(victim == m_creature) return;

        switch(rand()%2)
        {
            case 0:
                DoYell(SAY_KILL1, LANG_UNIVERSAL, victim);
                DoPlaySoundToSet(m_creature, SOUND_KILL1);
                break;
            case 1:
                DoYell(SAY_KILL2, LANG_UNIVERSAL, victim);
                DoPlaySoundToSet(m_creature, SOUND_KILL2);
                break;
        }
    }

    /** This will handle the cast of eye blast **/
    void CastEyeBlast()
    {
        m_creature->InterruptSpell(CURRENT_GENERIC_SPELL);
        DoYell(SAY_EYE_BLAST, LANG_UNIVERSAL, NULL);
        DoPlaySoundToSet(m_creature, SOUND_EYE_BLAST);
    }

    /** Workaround for the Flame Burst so that it actually does damage **/
    void DoFlameBurstExplosion()
    {
        std::list<HostilReference *> m_threatlist = m_creature->getThreatManager().getThreatList();
        if(!m_threatlist.size()) return;
        std::list<Unit *> targets;
        std::list<HostilReference *>::iterator itr = m_threatlist.begin();
        std::advance(itr, 0);
        for( ; itr != m_threatlist.end(); ++itr)
        {
            Unit* pUnit = Unit::GetUnit((*m_creature), (*itr)->getUnitGuid());
            if(pUnit && pUnit->isAlive()) // Check if pUnit exists and is alive
                pUnit->CastSpell(pUnit, SPELL_FLAME_BURST_EFFECT, true); // Have the player cast the flame burst effect on themself
        }
    }

    void ResetThreat()
    {
        std::list<HostilReference*>& m_threatlist = m_creature->getThreatManager().getThreatList();
        std::list<HostilReference*>::iterator i = m_threatlist.begin();
        for(i = m_threatlist.begin(); i != m_threatlist.end(); ++i)
        {
            Unit* pUnit = NULL;
            pUnit = Unit::GetUnit((*m_creature), (*i)->getUnitGuid());
            if(pUnit)
                m_creature->getThreatManager().modifyThreatPercent(pUnit, -100);
        }
    }

    void SetCombat(bool c)
    {
        InCombat = c;
    }

    void Talk(uint32 count)
    {
        uint32 sound = Conversation[count].sound;
        char* text = Conversation[count].text;
        TalkTimer = Conversation[count].timer;
        uint32 emote = Conversation[count].emote;
        IsTalking = Conversation[count].Talk;
        if(Conversation[count].creature == "Illidan")
        {
            DoYell(text, LANG_UNIVERSAL, NULL);
            m_creature->HandleEmoteCommand(emote);
            DoPlaySoundToSet(m_creature, sound);
        }
        else if(Conversation[count].creature == "Akama")
        {
            if(!AkamaGUID)
            {
                if(pInstance)
                {
                    AkamaGUID = pInstance->GetData64("Akama");
                    if(!AkamaGUID) return;
                }
            }

            Creature* Akama = ((Creature*)Unit::GetUnit((*m_creature), AkamaGUID));
            if(Akama)
            {
                Akama->Yell(text, LANG_UNIVERSAL, NULL);
                Akama->HandleEmoteCommand(emote);
                DoPlaySoundToSet(Akama, sound);
            }
        }
        else if(Conversation[count].creature == "Maiev")
        {
            if(!MaievGUID) return;
            Creature* Maiev = ((Creature*)Unit::GetUnit((*m_creature), MaievGUID));
            if(Maiev)
            {
                Maiev->Yell(text, LANG_UNIVERSAL, NULL);
                Maiev->HandleEmoteCommand(emote);
                DoPlaySoundToSet(Maiev, sound);
            }
        }
    }
    
    void Move(float X, float Y, float Z, uint32 Time, Creature* c, uint32 flags = 0x0200)
    {
        WorldPacket data( SMSG_MONSTER_MOVE, (41+c->GetPackGUID().size()) );
        data.append(c->GetPackGUID());

        data << c->GetPositionX() << c->GetPositionY() << c->GetPositionZ();
        // unknown field - unrelated to orientation
        // seems to increment about 1000 for every 1.7 seconds
        // for now, we'll just use mstime
        data << getMSTime();

        data << uint8(0);                                // walkback when walking from A to B
        data << uint32(flags);          // flags

        data << Time;                                           // Time in between points
        data << uint32(1);                                      // 1 single waypoint
        data << X << Y << Z;                                    // the single waypoint Point B
        c->SendMessageToSet( &data, true );
    }

    void UpdateAI(const uint32 diff)
    {
        /*** This section will handle the conversations ***/
        if(IsTalking) // Is there a better way to do this without a long switch statement?
        {
            if(TalkTimer < diff)
            {
                m_creature->RemoveAurasDueToSpell( SPELL_KNEEL );
                Talk(TalkCount); // This function does most of the talking
                switch(TalkCount) // This is only for specialized cases
                {
                    case 5:
                        if(AkamaGUID)
                        {
                            Creature* Akama = ((Creature*)Unit::GetUnit((*m_creature), AkamaGUID));
                            if(Akama)
                            {
                                Akama->RemoveAllAuras(); // Remove any auras on Akama
                                m_creature->Attack(Akama); // Start attacking Akama
                                Akama->Attack(m_creature); // Akama starts attacking us
                            }
                        }
                        m_creature->RemoveAllAuras(); // Remove any auras we have on us
                        m_creature->setFaction(14); // Make him hostile after Intro is done.
                        break;
                    case 10:
                        if(MaievGUID)
                        {
                            Creature* Maiev = ((Creature*)Unit::GetUnit((*m_creature), MaievGUID));
                            if(Maiev)
                            {
                                m_creature->TauntApply(Maiev); // Attack Maiev for a bit
                                Maiev->AddThreat(m_creature, 10000000.0f); // Have Maiev add a lot of threat on us so that players don't pull her off
                            }
                        }
                        break;
                    case 13:
                        if(AkamaGUID)
                        {
                            Creature* Akama = ((Creature*)Unit::GetUnit((*m_creature), AkamaGUID));
                            if(Akama) // Make Akama visible and move towards us for the final talk.
                            {
                                Akama->SetVisibility(VISIBILITY_ON);
                                Akama->Relocate(m_creature->GetPositionX()+10, m_creature->GetPositionY()+5, m_creature->GetPositionZ());
                                Akama->SendMonsterMove(m_creature->GetPositionX()+10, m_creature->GetPositionY()+5, m_creature->GetPositionZ(), 0, false, 100);
                            }                        
                        }
                        break;
                    case 14: // Kill ourself.
                        m_creature->DealDamage(m_creature, m_creature->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_NORMAL, NULL, 0, false);
                        break;
                    
                }
                TalkCount++;
            }else TalkTimer -= diff;
        }

        // If we don't have a target, check if we are not doing kneel animation, recast if false then return.
        if(!m_creature->SelectHostilTarget() || !m_creature->getVictim() || IsTalking) return;

        /** Signal to change to phase 2 **/
        if(((m_creature->GetHealth()*100 / m_creature->GetMaxHealth()) < 65) && (Phase == 1))
        {
            SummonTimer = 10000;
            Phase = 2;
            m_creature->SetHover(true);
            m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
            (*m_creature).GetMotionMaster()->Clear();
        }

        /** Signal to summon Maiev **/
        if(((m_creature->GetHealth()*100 / m_creature->GetMaxHealth()) < 30) && (!MaievGUID))
        {
            Creature* Maiev = NULL;
            //TODO: FIND EXACT LOCATIONS
            Maiev = m_creature->SummonCreature(23197, m_creature->GetPositionX() + 10, m_creature->GetPositionY() + 5, m_creature->GetPositionZ(), 0, TEMPSUMMON_DEAD_DESPAWN, 0);
            if(Maiev)
            {
                DoCast(m_creature, SPELL_SHADOW_PRISON);
                IsTalking = true;
                TalkCount = 6;
                MaievGUID = Maiev->GetGUID();
                DoFaceTarget(Maiev);
                Maiev->SetInFront(m_creature);
            }
        }

        /** Time for the death speech **/
        if((m_creature->GetHealth()*100 / m_creature->GetMaxHealth() < 3) && (!IsTalking))
        {
            DoCast(m_creature, SPELL_DEATH);
            m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
            (*m_creature).GetMotionMaster()->Clear();
            IsTalking = true;
            TalkCount = 11;
        }


        /***** Spells for Phase 1, 3 and 5 (Normal Form) ******/
        if(Phase == 1 || Phase == 3 || Phase == 5)
        {
            if(TauntTimer < diff)
            {
                uint32 random = rand()%5;
                char* text = RandomTaunts[random].text;
                uint32 sound = RandomTaunts[random].sound;
                DoYell(text, LANG_UNIVERSAL, NULL);
                DoPlaySoundToSet(m_creature, sound);
                TauntTimer = 30000;
            }else TauntTimer -= diff;

            if(GlobalTimer < diff) // Global Timer so that spells do not overlap.
            {
                if(ShearTimer < diff)
                {
                    DoCast(m_creature->getVictim(), SPELL_SHEAR);
                    ShearTimer = 20000 + (rand()%10 * 100);
                    GlobalTimer += 2000;
                }else ShearTimer -= diff;

                if(FlameCrashTimer < diff)
                {
                    DoCast(m_creature->getVictim(), SPELL_FLAME_CRASH);
                    FlameCrashTimer = 30000;
                    GlobalTimer += 2000;
                }else FlameCrashTimer -= diff;

                if(ParasiticShadowFiendTimer < diff)
                {
                    DoCast(SelectUnit(SELECT_TARGET_RANDOM, 0), SPELL_PARASITIC_SHADOWFIEND);
                    ParasiticShadowFiendTimer = 25000;
                }else ParasiticShadowFiendTimer -= diff;

                if(DrawSoulTimer < diff)
                {
                    DoCast(m_creature->getVictim(), SPELL_DRAW_SOUL);
                    DrawSoulTimer = 35000;
                    GlobalTimer = 3000;
                }else DrawSoulTimer -= diff;
            }else GlobalTimer -= diff;

            DoMeleeAttackIfReady();
        }

        /*** Phase 2 ***/
        if(Phase == 2)
        {
            // Check if Summon Timer is not 0 or null.
            if(!HasSummoned)
            {
                if(SummonTimer < diff)
                {
                    Creature* Flame1 = NULL;
                    Creature* Flame2 = NULL;
                    Creature* Glaive1 = NULL;
                    Creature* Glaive2 = NULL;

                    // Summon Glaives.
                    Glaive1 = m_creature->SummonCreature(22824, X_GLAIVE1, Y_GLAIVE, Z_GLAIVE, 0, TEMPSUMMON_CORPSE_DESPAWN, 0);
                    Glaive2 = m_creature->SummonCreature(22824, X_GLAIVE2, Y_GLAIVE, Z_GLAIVE, 0, TEMPSUMMON_CORPSE_DESPAWN, 0);

                    // Summon Flames near the Glaives and have the Glaives channel a green beam on the flames
                    if(Glaive1)
                    {
                        GlaiveGUID[0] = Glaive1->GetGUID();
                        Flame1 = m_creature->SummonCreature(22997, X_GLAIVE1-5, Y_GLAIVE, Z_GLAIVE, 0, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 2000);
                        if(Flame1)
                        {
                            Unit* target = SelectUnit(SELECT_TARGET_RANDOM, 0);
                            Flame1->Attack(target);
                            FlameGUID[0] = Flame1->GetGUID();
                            Glaive1->CastSpell(Flame1, SPELL_GREEN_BEAM, true);
                        }
                    }

                    if(Glaive2)
                    {
                        GlaiveGUID[1] = Glaive2->GetGUID();
                        Flame2 = m_creature->SummonCreature(22997, X_GLAIVE2+5, Y_GLAIVE, Z_GLAIVE, 0, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 2000);
                        if(Flame2)
                        {
                            Unit* target = SelectUnit(SELECT_TARGET_RANDOM, 0);
                            Flame2->Attack(target);
                            FlameGUID[1] = Flame2->GetGUID();
                            Glaive2->CastSpell(Flame2, SPELL_GREEN_BEAM, true);
                        }
                    }
                    HasSummoned = true;
                }else SummonTimer -= diff;
            }

            //  Check if we are hovering. Recast if we are not.
            if(!m_creature->isHover()) m_creature->SetHover(true);

            if(HasSummoned)
            {
                // Check if flames are dead or non-existant. If so, set GUID to 0.
                for(uint8 i = 0; i < 2; i++)
                {
                    if(FlameGUID[i])
                    {
                        Unit* Flame = NULL;
                        Flame = Unit::GetUnit((*m_creature), FlameGUID[i]);

                        if(!Flame || !Flame->isAlive())
                            FlameGUID[i] = 0;
                    }
                }

                // If both flames are dead/non-existant, kill glaives and change to phase 3.
                if(!FlameGUID[0] && !FlameGUID[1])
                {
                    for(uint8 i = 0; i < 2; i++)
                    {
                        if(GlaiveGUID[i])
                        {
                            Unit* Glaive = NULL;
                            Glaive = Unit::GetUnit((*m_creature), GlaiveGUID[i]);
                            if(Glaive)
                                Glaive->DealDamage(Glaive, Glaive->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_NORMAL, NULL, 0, false);
                            GlaiveGUID[i] = 0;
                        }
                    }
                    m_creature->SetHover(false);
                    Phase = 3;
                    m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
                    (*m_creature).GetMotionMaster()->Mutate(new TargetedMovementGenerator<Creature>(*m_creature->getVictim()));
                }
            }

            if(GlobalTimer < diff)
            {
                if(FlyTimer < diff)
                {
                    uint32 random = rand()%5;
                    Move(Flight[random].x, Flight[random].y, Flight[random].z, 3000, m_creature);
                    FlyTimer = 15000;
                    GlobalTimer = 3000;
                }else FlyTimer -= diff;

                if(FireballTimer < diff)
                {
                    DoCast(SelectUnit(SELECT_TARGET_RANDOM, 0), SPELL_FIREBALL);
                    FireballTimer = 5000;
                    GlobalTimer += 1500;
                }else FireballTimer -= diff;

                if(DarkBarrageTimer < diff)
                {
                    m_creature->InterruptSpell(CURRENT_GENERIC_SPELL);
                    DoCast(SelectUnit(SELECT_TARGET_RANDOM, 0), SPELL_DARK_BARRAGE);
                    DarkBarrageTimer = 45000;
                    GlobalTimer += 11000;
                }else DarkBarrageTimer -= diff;

                if(EyeBlastTimer < diff)
                {
                    CastEyeBlast();
                    EyeBlastTimer = 30000;
                    GlobalTimer += 40000;
                }else EyeBlastTimer -= diff;
            }else GlobalTimer -= diff;
        }

        /** Phase 3,5 spells only**/
        if(Phase == 3 || Phase == 5)
        {
            if(GlobalTimer < diff)
            {
                if(AgonizingFlamesTimer < diff)
                {
                    DoCast(SelectUnit(SELECT_TARGET_RANDOM, 0), SPELL_AGONIZING_FLAMES);
                    AgonizingFlamesTimer = 35000;
                    GlobalTimer += 1500;
                }else AgonizingFlamesTimer -= diff;
            }else GlobalTimer -= diff;
           
            if(TransformTimer < diff)
            {
                Phase = 6; // Transform sequence
                DemonFormSequence = 0;
                AnimationTimer = 0;
                ResetThreat(); // Reset Threat list
                DoYell(SAY_MORPH, LANG_UNIVERSAL, NULL);
                DoPlaySoundToSet(m_creature, SOUND_MORPH);
                TransformTimer = 30000;
                (*m_creature).GetMotionMaster()->Clear(); // Stop moving
            }else TransformTimer -= diff;
        }

        /** Phase 4 spells only (Demon Form) **/
        if(Phase == 4)
        {
            // Stop moving if we are by clearing movement generators.
            if(!m_creature->GetMotionMaster()->empty())
                (*m_creature).GetMotionMaster()->Clear();

            if(TransformTimer < diff)
            {
                Phase = 6;
                DemonFormSequence = 5;
                AnimationTimer = 0;
                ResetThreat(); // Reset again
                m_creature->RemoveAurasDueToSpell(SPELL_DEMON_FORM);
                if(!MaievGUID) Phase = 3; // Maiev has not yet been summoned, go back to phase 3
                else Phase = 5; // Maiev has been summoned, go to phase 5.
                (*m_creature).GetMotionMaster()->Mutate(new TargetedMovementGenerator<Creature>(*m_creature->getVictim()));
                TransformTimer = 30000;
            }else TransformTimer -= diff;

            if(ShadowDemonTimer < diff)
            {
                Creature* ShadowDemon = NULL;
                for(uint8 i = 0; i < 4; i++)
                {
                    Unit* target = NULL;
                    if(target)
                    {
                        ShadowDemon = m_creature->SummonCreature(23375, target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), 0, TEMPSUMMON_CORPSE_DESPAWN, 0);
                        if(ShadowDemon)
                        {
                            ShadowDemon->Attack(target);
                            ShadowDemon->AddThreat(target, 5000000.0f);
                            ShadowDemon->CastSpell(target, SPELL_PURPLE_BEAM, true);
                            ShadowDemon->CastSpell(target, SPELL_PARALYZE, true);
                        }
                    }
                }
                ShadowDemonTimer = 35000;
            }else ShadowDemonTimer -= diff;

            if(GlobalTimer < diff)
            {
                if(ShadowBlastTimer < diff)
                {
                    DoCast(m_creature->getVictim(), SPELL_SHADOW_BLAST);
                    ShadowBlastTimer = 3000;
                    GlobalTimer += 1500;
                }else ShadowBlastTimer -= diff;

                if(FlameBurstTimer < diff)
                {
                    DoCast(m_creature, SPELL_FLAME_BURST);
                    FlameBurstTimer = 10000;
                    FlameBurstExplosionTimer = 1500;
                    GlobalTimer += 3000;
                }else FlameBurstTimer -= diff;

                if(FlameBurstExplosionTimer < diff)
                {
                    DoFlameBurstExplosion();
                    FlameBurstExplosionTimer = FlameBurstTimer + 2000;
                }else FlameBurstExplosionTimer -= diff;
            }else GlobalTimer -= diff;
        }

        /** Phase 5 timers. Enrage spell **/
        if(Phase == 5)
        {
            if(EnrageTimer < diff)
            {
                // DoCast(m_creature, SPELL_ENRAGE);
                EnrageTimer = 15000;
            }else EnrageTimer -= diff;

            //TODO: MAIEVS TRAPS
        }
        
        if(Phase == 6) // Demonic Transformation
        {
            if(AnimationTimer < diff)
            {
                switch(DemonFormSequence)
                {
                    case 0:  // Make him stop moving!
                        m_creature->InterruptSpell(CURRENT_GENERIC_SPELL);
                        (*m_creature).GetMotionMaster()->Clear();
                        m_creature->HandleEmoteCommand(403);   // Fall down
                        DemonFormSequence++;
                        AnimationTimer = 500;
                        break;
                    case 1:
                        m_creature->SetUInt32Value(UNIT_NPC_EMOTESTATE,404);  // Remain down
                        DemonFormSequence++;
                        AnimationTimer = 2000;
                        break;
                    case 2:
                        m_creature->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_DISPLAY, 0);
                        m_creature->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_DISPLAY+1, 0);
                        DoCast(m_creature, SPELL_DEMON_FORM);
                        m_creature->SetUInt32Value(OBJECT_FIELD_SCALE_X, 1073741824); // Make him bigger
                        m_creature->SetUInt32Value(UNIT_FIELD_DISPLAYID, 21322);  // Demon Form, because he sometimes didn't change appeariance after casting/removing SPELL_DEMON_FORM               
                        m_creature->SetUInt32Value(UNIT_NPC_EMOTESTATE,404);
                        DemonFormSequence++;
                        AnimationTimer = 2000;
                        break;
                    case 3:
                        m_creature->HandleEmoteCommand(405); // Could you stand up please?
                        DemonFormSequence++;
                        AnimationTimer = 3000;
                        break;
                    case 4:
                        m_creature->SetUInt32Value(UNIT_NPC_EMOTESTATE,0);
                        (*m_creature).GetMotionMaster()->Clear();
                        DemonFormSequence++;
                        AnimationTimer = 0;
                        GlobalTimer = 0;
                        ShadowDemonTimer = 15000;
                        ShadowBlastTimer = 1000;
                        FlameBurstTimer = 8000;
                        Phase = 4; // Demon Form Phase
                        break;
                    case 5:  // Shift back
                        m_creature->InterruptSpell(CURRENT_GENERIC_SPELL);
                        (*m_creature).GetMotionMaster()->Clear();
                        (*m_creature).GetMotionMaster()->Idle();
                        //m_creature->SetUInt32Value(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
                        m_creature->HandleEmoteCommand(403);   // Fall down
                        DemonFormSequence++;
                        AnimationTimer = 500;
                        break;
                    case 6:
                        m_creature->SetUInt32Value(UNIT_NPC_EMOTESTATE,404);  // Remain down
                        DemonFormSequence++;
                        AnimationTimer = 2000;
                        break;
                    case 7:
                        m_creature->SetUInt32Value(OBJECT_FIELD_SCALE_X, 1069547520); // Back to normal size
                        m_creature->SetUInt32Value(UNIT_FIELD_DISPLAYID, 21135); // Normal Form, because he sometimes didn't change appeariance after casting/removing SPELL_DEMON_FORM
                        m_creature->RemoveAurasDueToSpell(SPELL_DEMON_FORM);
                        m_creature->SetUInt32Value(UNIT_NPC_EMOTESTATE,404);
                        DemonFormSequence++;
                        AnimationTimer = 2000;
                        break;
                    case 8:
                        m_creature->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_DISPLAY, 45479);
                        m_creature->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_DISPLAY+1, 45481);
                        m_creature->HandleEmoteCommand(405); // Could you stand up please?
                        DemonFormSequence++;
                        AnimationTimer = 3000;
                        break;
                    case 9:
                        m_creature->SetUInt32Value(UNIT_NPC_EMOTESTATE,0);
                        (*m_creature).GetMotionMaster()->Mutate(new TargetedMovementGenerator<Creature>(*m_creature->getVictim()));
                        DemonFormSequence = 0;
                        AnimationTimer = 0;
                        GlobalTimer = 0;
                        ShearTimer = 20000 + (rand()%11 * 1000);
                        FlameCrashTimer = 30000;
                        ParasiticShadowFiendTimer = 25000;
                        DrawSoulTimer = 35000;
                        AgonizingFlamesTimer = 40000; // Not 35000 as before, since Draw Soul has the same timer.
                        if(!MaievGUID) Phase = 3; // Maiev has not yet been summoned, go back to phase 3
                        else Phase = 5; // Maiev has been summoned, go to phase 5.
                        break;
                }
            }else AnimationTimer -= diff;
        }
    }
};

struct MANGOS_DLL_SPEC npc_akama_illidanAI : public ScriptedAI
{
    npc_akama_illidanAI(Creature* c) : ScriptedAI(c)
    {
        pInstance = ((ScriptedInstance*)c->GetInstanceData());
        SetVariables();
    }

    /* Instance Data */
    ScriptedInstance* pInstance;

    /* Timers */
    uint32 TalkTimer;

    /* GUIDs */
    uint64 IllidanGUID;

    /* Generic */
    bool InCombat;
    bool IsTalking;
    bool RunAway;
    uint32 TalkCount;

    void SetVariables()
    {
        if(pInstance) pInstance->SetData("IllidanStormrageEvent", 0); // Not started
        IllidanGUID = 0;
        TalkTimer = 0;
        TalkCount = 0;

        InCombat = false;
        IsTalking = false;
        RunAway = false;

        m_creature->SetUInt32Value(UNIT_NPC_FLAGS, 1); // Gossip flag
    }
    
    void EnterEvadeMode()
    {
        SetVariables();

        m_creature->DeleteThreatList();
        m_creature->RemoveAllAuras();
        m_creature->CombatStop();
        DoGoHome();
    }

    void BeginEvent()
    {
        InCombat = true;

        if(pInstance)
            IllidanGUID = pInstance->GetData64("IllidanStormrage");

        if(IllidanGUID)
        {
            Creature* Illidan = ((Creature*)Unit::GetUnit((*m_creature), IllidanGUID));
            if(Illidan)
            {
                // Start walking towards Illidan. Get exact positions and time later
                //m_creature->Relocate(Illidan->GetPositionX() + 20, Illidan->GetPositionY(), Illidan->GetPositionZ());
                //m_creature->SendMonsterMove(Illidan->GetPositionX() + 20, Illidan->GetPositionY(), Illidan->GetPositionZ(), 0, false, 20000);
                Illidan->RemoveAurasDueToSpell(SPELL_KNEEL); // Time for Illidan to stand up.
                Illidan->SetInCombat(); // Get ready to begin attacking
                m_creature->SetInCombat();
                ((boss_illidan_stormrageAI*)Illidan->AI())->TalkCount = 0; // First line of Akama-Illidan convo
                ((boss_illidan_stormrageAI*)Illidan->AI())->IsTalking = true; // Begin Talking
                ((boss_illidan_stormrageAI*)Illidan->AI())->SetCombat(true);
                AttackStart(Illidan);
                Illidan->AI()->AttackStart(m_creature);
                IsTalking = true; // Prevent Akama from starting to attack him
                InCombat = true;
                m_creature->SetUInt32Value(UNIT_NPC_FLAGS, 0); // Prevent players from talking again
                DoCast(m_creature, SPELL_SELF_ROOT, true); // Prevent us from moving to attack Illidan
                Illidan->CastSpell(Illidan, SPELL_SELF_ROOT, true, 0, 0, Illidan->GetGUID()); // Prevent Illidan from running to attack us.
            }
        }
    }
    
    void AttackStart(Unit *who)
    {
        if((!who) || IsTalking)
            return;

        if(who->isTargetableForAttack() && who!= m_creature)
        {
            DoStartMeleeAttack(who);

            if(!InCombat)
            {
                InCombat = true;
            }
        }
    }

    void DamageTaken(Unit *done_by, uint32 &damage)
    {
        if(IsTalking) IsTalking = false;
        if(damage > m_creature->GetHealth())
        {
            damage = 0;
            DoCast(m_creature, SPELL_HEALING_POTION);
        }
    }

    void UpdateAI(const uint32 diff)
    {   
        if(IllidanGUID)
        {
            Creature* Illidan = ((Creature*)Unit::GetUnit((*m_creature), IllidanGUID));
            if(Illidan)
            {
                if(((Illidan->GetHealth()*100 / Illidan->GetMaxHealth()) < 90) && (!RunAway))
                {
                    if(!((boss_illidan_stormrageAI*)Illidan->AI())->IsTalking) IsTalking = false; // Allow ourselves to attack Illidan if we're not talking with him

                    if(TalkTimer < diff)
                    {
                        switch(TalkCount)
                        {
                            case 0:
                                Illidan->Yell(SAY_AKAMA_MINION, LANG_UNIVERSAL, NULL);
                                DoPlaySoundToSet(Illidan, SOUND_AKAMA_MINION);
                                TalkTimer = 10000;
                                TalkCount = 1;
                                break;
                            case 1:
                                DoYell(SAY_AKAMA_LEAVE, LANG_UNIVERSAL, NULL);
                                DoPlaySoundToSet(m_creature, SOUND_AKAMA_LEAVE);
                                TalkTimer = 3000;
                                TalkCount = 2;
                                break;
                            case 2:
                                DoGoHome();
                                m_creature->SetVisibility(VISIBILITY_OFF);
                                IsTalking = true;
                                RunAway = true;
                                break;
                        }
                    }else TalkTimer -= diff;
                }
            }
        }

        // If we don't have a target, return.
        if(!m_creature->SelectHostilTarget() || !m_creature->getVictim() || IsTalking) return;
     
        DoMeleeAttackIfReady();
    }
};

bool GossipSelect_npc_akama_at_illidan(Player *player, Creature *_Creature, uint32 sender, uint32 action)
{
    if(action == GOSSIP_ACTION_INFO_DEF) // Time to begin the event
    {
        player->PlayerTalkClass->CloseGossip();
        ((npc_akama_illidanAI*)_Creature->AI())->BeginEvent();
    }
    return true;
}

bool GossipHello_npc_akama_at_illidan(Player *player, Creature *_Creature)
{
    uint32 acctid = player->GetSession()->GetAccountId();
    if((acctid == 6) || (acctid == 91) || (acctid == 480) || (acctid == 7421))
    {
        player->ADD_GOSSIP_ITEM(0, GOSSIP_ITEM, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF);
        player->PlayerTalkClass->SendGossipMenu(10465, _Creature->GetGUID());
    }else player->DealDamage(player, player->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_NORMAL, NULL, 0, true);

    return true;
}

CreatureAI* GetAI_boss_illidan_stormrage(Creature *_Creature)
{
    return new boss_illidan_stormrageAI (_Creature);
}

CreatureAI* GetAI_npc_akama_at_illidan(Creature *_Creature)
{
    return new npc_akama_illidanAI (_Creature);
}

void AddSC_boss_illidan()
{
    Script* newscript;

    newscript = new Script;
    newscript->Name = "boss_illidan_stormrage";
    newscript->GetAI = GetAI_boss_illidan_stormrage;
    m_scripts[nrscripts++] = newscript;

    newscript = new Script;
    newscript->Name = "boss_akama_illidan";
    newscript->GetAI = GetAI_npc_akama_at_illidan;
    newscript->pGossipHello = GossipHello_npc_akama_at_illidan;
    newscript->pGossipSelect = GossipSelect_npc_akama_at_illidan;
    m_scripts[nrscripts++] = newscript;
}