/* Copyright (C) 2006 - 2008 ScriptDev2
* 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: 90
SDComment: Eye Blast is buggy, some workarounds for Flame Crash and Parasitic Shadowfiend, unable to summon GOs.
SDCategory: Black Temple
EndScriptData */
/******** 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
// Maiev - Taunts
#define SAY_NAISHA "That is for Naisha!"
#define SOUND_NAISHA 11493
#define SAY_BLEED "Bleed as I have bled!"
#define SOUND_BLEED 11494
#define SAY_PRISON "There shall be no prison for you this time!"
#define SOUND_PRISON 11495
#define SAY_MEET_END "Meet your end, demon!"
#define SOUND_MEET_END 11500
// 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_SUMMON_PARASITICS 41915 // Summons 2 Parasitic Shadowfiends on the target. It's supposed to be cast as soon as the Parasitic Shadowfiend debuff is gone, but the spells aren't linked :(
#define SPELL_AGONIZING_FLAMES 40932 // 4k fire damage initial to target and anyone w/i 5 yards. PHASE 3 ONLY
#define SPELL_ENRAGE 40683 // Increases damage by 50% and attack speed by 30%. 20 seconds, PHASE 5 ONLY
// Flying (Phase 2)
#define SPELL_FIREBALL 40598 // 2.5k-3.5k damage in 10 yard radius. 2 second cast time.
#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 41220 // 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_BLUE_BEAM 40225 // We'll make Illidan use this to channel Eye Blast. Don't know the right ID
#define SPELL_SHADOW_DEMON_PASSIVE 41079 // Adds the "shadowform" aura to Shadow Demons.
#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.
#define SPELL_EYE_BLAST_TRIGGER 40017 // This summons Demon Form every few seconds and deals ~20k damage in its radius
#define SPELL_EYE_BLAST 39908 // This does the blue flamey animation.
#define SPELL_FLAME_CRASH_EFFECT 40836 // Firey blue ring of circle that the other flame crash summons
#define SPELL_BLAZE_EFFECT 40610 // Green flame on the ground, triggers damage (5k) every few seconds
#define SPELL_BLAZE_SUMMON 40637 // Summons the Blaze creature
#define SPELL_DEMON_FIRE 40029 // Blue fire trail left by Eye Blast. Deals 2k per second if players stand on it.
#define SPELL_CAGED 40695 // Caged Trap triggers will cast this on Illidan if he is within 3 yards
#define SPELL_CAGE_TRAP_SUMMON 40694 // Summons a Cage Trap GO (broken) on the ground along with a Cage Trap Disturb Trigger mob (working)
#define SPELL_FLAME_BLAST 40631 // Flames of Azzinoth use this. Frontal cone AoE 7k-9k damage.
#define SPELL_CHARGE 40602 // Flames of Azzinoth charges whoever is too far from them. They enrage after this. For simplicity, we'll use the same enrage as Illidan.
#define SPELL_TELEPORT_VISUAL 41232 // Teleport visual for Maiev
/***** 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_BLADE_OF_AZZINOTH 22996
#define CREATURE_FLAME_OF_AZZINOTH 22997
#define CREATURE_MAIEV_SHADOWSONG 23197
#define CREATURE_SHADOW_DEMON 23375
#define CREATURE_TARGET_TRIGGER 17474
struct Yells
{
uint32 sound;
char* text;
char* creature;
uint32 timer, emote;
bool Talk;
};
static Yells Conversation[]=
{
{SOUND_INTRO_ILL1, SAY_INTRO_ILL1, "Illidan", 8000, 0, true},
{0, NULL, "Illidan", 5000, 396, true},
{SOUND_INTRO_AKA1, SAY_INTRO_AKA1, "Akama", 7000, 25, true},
{0, NULL, "Akama", 5000, 66, true},
{SOUND_INTRO_ILL2, SAY_INTRO_ILL2, "Illidan", 8000, 396, true},
{SOUND_INTRO_AKA2, SAY_INTRO_AKA2, "Akama", 3000, 22, true},
{0, NULL, "Akama", 2000, 15, true},
{SOUND_INTRO_ILL3, SAY_INTRO_ILL3, "Illidan", 3000, 406, true},
{0, NULL, "Empty", 1000, 0, true},
{0, NULL, "Empty", 0, 0, false},
{SOUND_SUMMON_MAIEV, SAY_SUMMON_MAIEV, "Illidan", 8000, 0, true},
{SOUND_MAIEV1, SAY_MAIEV1, "Maiev", 8000, 5, true},
{SOUND_MAIEV_ILL2, SAY_MAIEV_ILL2, "Illidan", 7000, 1, true},
{SOUND_MAIEV2, SAY_MAIEV2, "Maiev", 8000, 15, true},
{SOUND_ATT_MAIEV, SAY_ATT_MAIEV, "Illidan", 1000, 0, false},
{SOUND_DEATH_MAIEV1, SAY_DEATH_MAIEV1, "Maiev", 6000, 0, true},
{SOUND_DEATH_ILL, SAY_DEATH_ILL, "Illidan", 22000, 65, true}, // Emote death but do not kill him
{SOUND_DEATH_MAIEV2, SAY_DEATH_MAIEV2, "Maiev", 9000, 0, true},
{SOUND_DEATH_AKA, SAY_DEATH_AKA, "Akama", 8000, 0, false}
};
static Yells RandomTaunts[]=
{
{SOUND_HATRED, SAY_HATRED, "Illidan", 0, 0, false},
{SOUND_FEAR, SAY_FEAR, "Illidan", 0, 0, false},
{SOUND_POWER, SAY_POWER, "Illidan", 0, 0, false},
{SOUND_ARROGANCE, SAY_ARROGANCE, "Illidan", 0, 0, false},
{SOUND_RABBLE, SAY_RABBLE, "Illidan", 0, 0, false}
};
static Yells MaievTaunts[]=
{
{11493, "That is for Naisha!", "Maiev", 0, 0, false},
{11494, "Bleed as I have bled!", "Maiev", 0, 0, false},
{11495, "There shall be no prison for you this time!", "Maiev", 0, 0, false},
{11500, "Meet your end, demon!", "Maiev", 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}
};
static Locations EyeBlast[]=
{
{653, 321, 354},
{653, 275, 354},
{702, 272, 353},
{713, 325, 353}
};
static Locations CageTrap[]=
{
{670, 252, 353},
{699, 265, 353},
{675, 283, 355},
{655, 301, 355},
{681, 339, 353},
{656, 341, 353},
{705, 326, 354}
};
struct Animation // For the demon transformation
{
uint32 aura, unaura, timer, size, displayid, phase;
bool equip;
};
static Animation DemonTransformation[]=
{
{40511, 0, 1500, 0, 0, 6, true},
{40398, 40511, 4000, 0, 0, 6, true},
{0, 0, 3000, 1073741824, 21322, 6, false},
{40510, 40398, 3500, 0, 0, 6, false},
{0, 0, 0, 0, 0, 4, false},
{40511, 0, 1500, 0, 0, 6, false},
{40398, 40511, 4000, 0, 0, 6, false},
{0, 0, 3000, 1069547520, 21135, 6, false},
{40510, 40398, 3500, 0, 0, 6, true},
{0, 0, 0, 0, 0, 8, true}
};
/******* Functions and vars for Akama's AI ******/
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();
void EnterEvadeMode();
void BeginEvent(Player *player);
void AttackStart(Unit *who);
void DamageTaken(Unit *done_by, uint32 &damage);
void DeleteFromThreatList();
void UpdateAI(const uint32 diff);
};
/******* 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[2];
uint64 GlaiveGUID[2];
uint64 AkamaGUID;
uint64 MaievGUID;
uint64 ParasiticTargetGUID;
/** Timers **/
uint32 ShearTimer;
uint32 DrawSoulTimer;
uint32 FlameCrashTimer;
uint32 ParasiticShadowFiendTimer;
uint32 SummonParasiticTimer;
uint32 FlyTimer;
uint32 FireballTimer;
uint32 EyeBlastTimer;
uint32 DarkBarrageTimer;
uint32 LandTimer; // This is used at the end of phase 2 to signal Illidan landing after Flames are dead
uint32 AgonizingFlamesTimer;
uint32 ShadowBlastTimer;
uint32 FlameBurstTimer;
uint32 ShadowDemonTimer;
uint32 SummonTimer;
uint32 TalkTimer;
uint32 TransformTimer;
uint32 EnrageTimer;
uint32 CageTimer;
uint32 LayTrapTimer;
uint32 AnimationTimer;
uint32 TauntTimer; // This is used for his random yells
void SetVariables()
{
Phase = 1;
// 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->SetVisibility(VISIBILITY_OFF);
Flame->DealDamage(Flame, Flame->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_NORMAL, NULL, false);
}
}
FlameGUID[i] = 0;
}
if(GlaiveGUID[i])
{
if(InCombat)
{
Unit* Glaive = Unit::GetUnit((*m_creature), GlaiveGUID[i]);
if(Glaive)
{
Glaive->SetVisibility(VISIBILITY_OFF);
Glaive->DealDamage(Glaive, Glaive->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_NORMAL, NULL, false);
}
}
GlaiveGUID[i] = 0;
}
}
if(AkamaGUID)
{
Creature* Akama = ((Creature*)Unit::GetUnit((*m_creature), AkamaGUID));
if(Akama)
{
if(!Akama->isAlive())
{
Akama->Respawn();
Akama->GetMotionMaster()->TargetedHome(); // Send him home.
}
Akama->SetVisibility(VISIBILITY_ON);
Akama->SetUInt32Value(UNIT_NPC_FLAGS,1); // Make him talkable again.
((npc_akama_illidanAI*)Akama->AI())->EnterEvadeMode();
}
}
HasSummoned = false;
AkamaGUID = 0;
MaievGUID = 0;
ParasiticTargetGUID = 0;
GlobalTimer = 0;
DemonFormSequence = 0;
/** Normal Form **/
ShearTimer = 20000 + (rand()%11 * 1000); // 20 to 30 seconds
FlameCrashTimer = 30000; //30 seconds
ParasiticShadowFiendTimer = 25000; // 25 seconds
SummonParasiticTimer = 35000; // 10 seconds after ParsiticShadowFiendTimer
DrawSoulTimer = 50000; // 50 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;
LandTimer = 0;
/** Phase 3+ **/
AgonizingFlamesTimer = 35000; // Phase 3+ timers may be incorrect
ShadowBlastTimer = 3000;
FlameBurstTimer = 20000;
ShadowDemonTimer = 20000;
TransformTimer = 90000;
EnrageTimer = 40000;
CageTimer = 30000;
LayTrapTimer = CageTimer + 2000;
AnimationTimer = 0;
TauntTimer = 30000; // This timer may be off.
m_creature->SetUInt32Value(UNIT_FIELD_DISPLAYID, 21135);
m_creature->InterruptSpell(CURRENT_GENERIC_SPELL);
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_ATTACKABLE);
m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
}
void EnterEvadeMode()
{
IsTalking = false;
InCombat = false;
TalkCount = 0;
TalkTimer = 0;
m_creature->RemoveAllAuras();
m_creature->DeleteThreatList();
m_creature->CombatStop();
DoGoHome();
SetVariables();
}
void AttackStart(Unit *who)
{
if(!who || IsTalking || Phase == 2 || Phase == 4 || Phase == 6 || m_creature->HasAura(SPELL_KNEEL, 0))
return;
if (who->isTargetableForAttack() && who!= m_creature)
{
//Begin melee attack if we are within range
DoStartMeleeAttack(who);
if (!InCombat)
{
SetVariables();
InCombat = true;
}
}
}
void MoveInLineOfSight(Unit *who)
{
if (!who || m_creature->getVictim() || m_creature->HasAura(SPELL_KNEEL, 0))
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)
{
if(pInstance)
pInstance->SetData("IllidanStormrageEvent", 3); // Completed
IsTalking = false;
InCombat = false;
m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
}
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;
}
}
void DamageTaken(Unit *done_by, uint32 &damage)
{
if(damage>m_creature->GetHealth())
{
damage = 0;
m_creature->SetHealth(m_creature->GetMaxHealth()*0.01);
}
}
/** This is a workaround so that he actually does his blade animations when melee'ing **/
void DoMeleeAttackIfReadyWithAnimations()
{
//If we are within range melee the target
if( m_creature->IsWithinDistInMap(m_creature->getVictim(), ATTACK_DISTANCE))
{
//Make sure our attack is ready and we arn't currently casting
if( m_creature->isAttackReady() && !m_creature->IsNonMeleeSpellCasted(false))
{
switch(rand()%3)
{
case 0:
m_creature->HandleEmoteCommand(389);
break;
case 1:
m_creature->HandleEmoteCommand(390);
break;
case 2:
m_creature->HandleEmoteCommand(36);
break;
}
m_creature->AttackerStateUpdate(m_creature->getVictim());
m_creature->resetAttackTimer();
}
}
}
/** 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);
uint32 initial = rand()%4;
uint32 final = 0;
if(initial < 3)
final = initial+1;
float initial_X = EyeBlast[initial].x;
float initial_Y = EyeBlast[initial].y;
float initial_Z = EyeBlast[initial].z;
float final_X = EyeBlast[final].x;
float final_Y = EyeBlast[final].y;
float final_Z = EyeBlast[final].z;
Creature* BlastTrigger = NULL; // This mob will have fun running across the summit and spawning Demon Fires
BlastTrigger = m_creature->SummonCreature(CREATURE_TARGET_TRIGGER, initial_X, initial_Y, initial_Z, 0, TEMPSUMMON_TIMED_DESPAWN, 40000);
Creature* BlueFlame = NULL; // This mob just does the Blue Flame animation. It follows close behind BlastTrigger...cosmetics ftw.
BlueFlame = m_creature->SummonCreature(CREATURE_TARGET_TRIGGER, initial_X,initial_Y,initial_Z,0,TEMPSUMMON_TIMED_DESPAWN,40000);
Creature* MoveTarget = NULL; // This is the mob that BlastTrigger will run towards.
MoveTarget = m_creature->SummonCreature(CREATURE_TARGET_TRIGGER,final_X,final_Y,final_Z,0,TEMPSUMMON_TIMED_DESPAWN, 40000);
if(BlastTrigger)
{
DoCast(BlastTrigger, SPELL_BLUE_BEAM);
GlobalTimer += 15000;
BlastTrigger->SetUInt32Value(UNIT_FIELD_DISPLAYID, 11686); // Give him an empty skin so that players don't see a random infernal running around.
BlastTrigger->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); // No point letting them target the mob either ^^;;
BlastTrigger->CastSpell(BlastTrigger, SPELL_EYE_BLAST_TRIGGER, true);
if(BlueFlame)
{
BlueFlame->SetUInt32Value(UNIT_FIELD_DISPLAYID, 11686); // Same reason as BlastTrigger
BlueFlame->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); // Blah blah blah.
BlueFlame->CastSpell(BlueFlame, SPELL_EYE_BLAST, true);
//BlueFlame->GetMotionMaster()->Clear(false);
//BlueFlame->GetMotionMaster()->Mutate(new TargetedMovementGenerator(*BlastTrigger));
BlueFlame->AddThreat(BlastTrigger, 1000000.0f);
BlastTrigger->SetHealth(100000); // Just so it won't die when attacked.
BlueFlame->SetHealth(100000);
}
if(MoveTarget)
{
MoveTarget->SetUInt32Value(UNIT_FIELD_DISPLAYID, 11686); // Same reason as above two mobs...
MoveTarget->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); // You know why...
//BlastTrigger->GetMotionMaster()->Clear(false);
//BlastTrigger->GetMotionMaster()->Mutate(new TargetedMovementGenerator(*MoveTarget));
BlastTrigger->AddThreat(MoveTarget, 100000.0f);
MoveTarget->SetHealth(100000); // Same reason as BlastTrigger->SetHealth
}
}
}
/** Workaround for the Flame Burst so that it actually does damage **/
void DoFlameBurstExplosion()
{
std::list m_threatlist = m_creature->getThreatManager().getThreatList();
if(!m_threatlist.size()) return;
std::list targets;
std::list::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& m_threatlist = m_creature->getThreatManager().getThreatList();
std::list::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);
//m_creature->AddThreat(pUnit, 1.0f);
}
}
}
void Talk(uint32 count)
{
uint32 sound = Conversation[count].sound;
char* text;
if(Conversation[count].text)
text = Conversation[count].text;
TalkTimer = Conversation[count].timer;
uint32 emote = Conversation[count].emote;
IsTalking = Conversation[count].Talk;
if(Conversation[count].creature == "Illidan")
{
if(text)
DoYell(text, LANG_UNIVERSAL, NULL);
m_creature->HandleEmoteCommand(emote);
if(sound)
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)
{
if(text)
Akama->Yell(text, LANG_UNIVERSAL, NULL);
Akama->HandleEmoteCommand(emote);
if(sound)
DoPlaySoundToSet(Akama, sound);
}
}
else if(Conversation[count].creature == "Maiev")
{
if(!MaievGUID) return;
Creature* Maiev = ((Creature*)Unit::GetUnit((*m_creature), MaievGUID));
if(Maiev)
{
if(text)
Maiev->Yell(text, LANG_UNIVERSAL, NULL);
Maiev->HandleEmoteCommand(emote);
if(sound)
DoPlaySoundToSet(Maiev, sound);
}
}
else if(Conversation[count].creature == "Empty") // This is just for special cases without speech/sounds/emotes.
return;
}
void Move(float X, float Y, float Z, uint32 Time, Unit* 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 );
c->Relocate(X, Y, Z);
}
void HandleDemonTransformAnimation(uint32 count)
{
uint32 unaura = DemonTransformation[count].unaura;
uint32 aura = DemonTransformation[count].aura;
uint32 displayid = DemonTransformation[count].displayid;
AnimationTimer = DemonTransformation[count].timer;
uint32 size = DemonTransformation[count].size;
m_creature->InterruptSpell(CURRENT_GENERIC_SPELL);
if(DemonTransformation[count].phase != 8)
{
m_creature->GetMotionMaster()->Clear();
m_creature->GetMotionMaster()->Idle();
}
if(unaura)
m_creature->RemoveAurasDueToSpell(unaura);
if(aura)
DoCast(m_creature, aura, true);
if(displayid)
m_creature->SetUInt32Value(UNIT_FIELD_DISPLAYID, displayid);
if(size)
m_creature->SetUInt32Value(OBJECT_FIELD_SCALE_X, size);
if(DemonTransformation[count].equip)
{
m_creature->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_DISPLAY, 45479);
m_creature->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_DISPLAY+1, 45481);
}
else
{
m_creature->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_DISPLAY, 0);
m_creature->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_DISPLAY+1, 0);
}
if(DemonTransformation[count].phase != 8)
Phase = DemonTransformation[count].phase;
else
{
m_creature->GetMotionMaster()->Mutate(new TargetedMovementGenerator(*m_creature->getVictim()));
if(MaievGUID) Phase = 5;
else Phase = 3;
}
if(count == 7)
{
ResetThreat();
m_creature->RemoveAurasDueToSpell( SPELL_DEMON_FORM );
}
else if(count == 4)
{
ResetThreat();
DoCast(m_creature, SPELL_DEMON_FORM);
}
}
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)
{
switch(TalkCount) // This is only for specialized cases
{
case 0:
m_creature->RemoveAurasDueToSpell( SPELL_KNEEL );
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(406);
m_creature->setFaction(14);
break;
case 9:
if(AkamaGUID)
{
Creature* Akama = ((Creature*)Unit::GetUnit((*m_creature), AkamaGUID));
if(Akama)
{
Akama->GetMotionMaster()->Clear(false);
Akama->GetMotionMaster()->Mutate(new TargetedMovementGenerator(*m_creature));
m_creature->GetMotionMaster()->Clear(false);
m_creature->GetMotionMaster()->Mutate(new TargetedMovementGenerator(*m_creature));
Akama->AddThreat(m_creature, 1000000.0f);
AttackStart(Akama); // Start attacking Akama
((npc_akama_illidanAI*)Akama->AI())->IsTalking = false;
((npc_akama_illidanAI*)Akama->AI())->AttackStart(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.
m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_ATTACKABLE);
break;
case 11:
if(MaievGUID)
{
Unit* Maiev = Unit::GetUnit((*m_creature), MaievGUID);
if(Maiev)
{
Maiev->SetVisibility(VISIBILITY_ON);
Maiev->CastSpell(Maiev, SPELL_TELEPORT_VISUAL, true);
Maiev->SetUInt64Value(UNIT_FIELD_TARGET, m_creature->GetGUID());
m_creature->SetUInt64Value(UNIT_FIELD_TARGET, Maiev->GetGUID());
}
}
break;
case 14:
if(MaievGUID)
{
Creature* Maiev = ((Creature*)Unit::GetUnit((*m_creature), MaievGUID));
if(Maiev)
{
Maiev->GetMotionMaster()->Clear(false);
Maiev->GetMotionMaster()->Mutate(new TargetedMovementGenerator(*m_creature));
Maiev->AI()->AttackStart(m_creature); // Force Maiev to attack us.
Maiev->AddThreat(m_creature, 10000000.0f); // Have Maiev add a lot of threat on us so that players don't pull her off
Maiev->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
}
}
m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
m_creature->GetMotionMaster()->Mutate(new TargetedMovementGenerator(*m_creature->getVictim()));
m_creature->SetUInt64Value(UNIT_FIELD_TARGET, m_creature->getVictim()->GetGUID());
IsTalking = false;
break;
case 15:
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->GetMotionMaster()->Clear(false);
Akama->GetMotionMaster()->Mutate(new TargetedMovementGenerator(*m_creature));
}
}
break;
case 18: // Kill ourself.
m_creature->RemoveAllAuras();
m_creature->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_STATE_DEAD);
if(MaievGUID)
{
Creature* Maiev = ((Creature*)Unit::GetUnit((*m_creature), MaievGUID));
if(Maiev) // Make Maiev leave
{
Maiev->CastSpell(Maiev, SPELL_TELEPORT_VISUAL, true);
Maiev->SetVisibility(VISIBILITY_OFF); // Close enough....
Maiev->DealDamage(Maiev, Maiev->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_NORMAL, NULL, false);
}
}
IsTalking = false;
m_creature->DealDamage(m_creature, m_creature->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_NORMAL, NULL, false); // Now we kill ourself
break;
}
Talk(TalkCount); // This function does most of the talking
TalkCount++;
}else TalkTimer -= diff;
}
// This is placed outside the victim check so that it can tick even if Illidan is talking or transforming or whatnot.
if(SummonParasiticTimer < diff)
{
if(ParasiticTargetGUID && (ParasiticTargetGUID != MaievGUID))
{
Unit* target = NULL;
target = Unit::GetUnit((*m_creature), ParasiticTargetGUID);
if(target && target->isAlive()) // Only on living targets.
DoCast(target, SPELL_SUMMON_PARASITICS, true);
ParasiticTargetGUID = 0;
}
SummonParasiticTimer = ParasiticShadowFiendTimer + 10000;
}else SummonParasiticTimer -= 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;
// If we are 'caged', then we shouldn't do anything such as cast spells or transform into Demon Form.
if(m_creature->HasAura(SPELL_CAGED, 0))
{
EnrageTimer = 40000; // Just so that he doesn't immediately enrage after he stops being caged.
CageTimer = 30000;
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->HandleEmoteCommand(EMOTE_ONESHOT_LIFTOFF);
m_creature->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_DISPLAY, 0);
m_creature->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_DISPLAY+1, 0);
m_creature->GetMotionMaster()->Clear(false);
}
/** Signal to summon Maiev **/
if(((m_creature->GetHealth()*100 / m_creature->GetMaxHealth()) < 30) && (!MaievGUID))
{
m_creature->setEmoteState(EMOTE_STATE_NONE);
m_creature->InterruptSpell(CURRENT_GENERIC_SPELL);
Creature* Maiev = NULL;
Maiev = m_creature->SummonCreature(CREATURE_MAIEV_SHADOWSONG, m_creature->GetPositionX() + 10, m_creature->GetPositionY() + 5, m_creature->GetPositionZ(), 0, TEMPSUMMON_DEAD_DESPAWN, 0);
if(Maiev)
{
m_creature->GetMotionMaster()->Clear(false);
m_creature->GetMotionMaster()->Idle();
m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
DoCast(m_creature, SPELL_SHADOW_PRISON);
TalkCount = 10;
IsTalking = true;
Maiev->SetVisibility(VISIBILITY_OFF); // Leave her invisible until she has to talk
MaievGUID = Maiev->GetGUID();
}
}
/** Time for the death speech **/
if((m_creature->GetHealth()*100 / m_creature->GetMaxHealth() < 1) && (!IsTalking))
{
DoCast(m_creature, SPELL_DEATH);
m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
m_creature->GetMotionMaster()->Clear(false);
m_creature->GetMotionMaster()->Idle();
if(MaievGUID)
{
Creature* Maiev = ((Creature*)Unit::GetUnit((*m_creature), MaievGUID));
if(Maiev)
{
Maiev->CombatStop();
Maiev->GetMotionMaster()->Clear(false);
Maiev->GetMotionMaster()->Idle();
}
}
// Since we killed Akama before, summon him now.
Creature* Akama = DoSpawnCreature(22990, 10, 10, 0, 0, TEMPSUMMON_TIMED_DESPAWN, 120000);
if(Akama)
{
((npc_akama_illidanAI*)Akama->AI())->RunAway = true; // Since we are resummoning him, his vars are at the default. That means he'll yell the Minions speech out. We have to avoid that like this
AkamaGUID = Akama->GetGUID();
Akama->SetVisibility(VISIBILITY_OFF);
Akama->SetUInt32Value(UNIT_NPC_FLAGS, 0); // So they don't make him restart the event ~~
}
IsTalking = true;
TalkCount++;
}
/***** 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 = 32000;
}else TauntTimer -= diff;
if(GlobalTimer < diff) // Global Timer so that spells do not overlap.
{
if(ShearTimer < diff)
{
DoCast(m_creature->getVictim(), SPELL_SHEAR);
ShearTimer = 25000 + (rand()%16 * 1000);
GlobalTimer += 2000;
}else ShearTimer -= diff;
if(FlameCrashTimer < diff)
{
// It spawns multiple flames sometimes. Therefore, we'll do this manually.
// DoCast(m_creature->getVictim(), SPELL_FLAME_CRASH);
m_creature->HandleEmoteCommand(402);
Creature* FlameCrash = DoSpawnCreature(23336, 0, 0, 0, 0, TEMPSUMMON_TIMED_DESPAWN, 40000);
FlameCrashTimer = 35000;
GlobalTimer += 2000;
}else FlameCrashTimer -= diff;
if(ParasiticShadowFiendTimer < diff)
{
Unit* target = NULL;
target = SelectUnit(SELECT_TARGET_RANDOM,1);
if(target && target->isAlive())
{
DoCast(target, SPELL_PARASITIC_SHADOWFIEND);
ParasiticTargetGUID = target->GetGUID();
SummonParasiticTimer = 10000;
}
ParasiticShadowFiendTimer = 40000;
}else ParasiticShadowFiendTimer -= diff;
if(DrawSoulTimer < diff)
{
DoCast(m_creature->getVictim(), SPELL_DRAW_SOUL);
DrawSoulTimer = 55000;
GlobalTimer = 3000;
}else DrawSoulTimer -= diff;
}else GlobalTimer -= diff;
DoMeleeAttackIfReadyWithAnimations();
}
/*** Phase 2 ***/
if(Phase == 2)
{
// Check if we have summoned or not.
if(!HasSummoned)
{
if(SummonTimer < diff)
{
Creature* Flame1 = NULL;
Creature* Flame2 = NULL;
Creature* Glaive1 = NULL;
Creature* Glaive2 = NULL;
// Summon Glaives.
Glaive1 = m_creature->SummonCreature(CREATURE_BLADE_OF_AZZINOTH, X_GLAIVE1, Y_GLAIVE, Z_GLAIVE, 0, TEMPSUMMON_CORPSE_DESPAWN, 0);
Glaive2 = m_creature->SummonCreature(CREATURE_BLADE_OF_AZZINOTH, 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();
Glaive1->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
Flame1 = m_creature->SummonCreature(22997, X_GLAIVE1-5, Y_GLAIVE, Z_GLAIVE, 0, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 2000);
if(Flame1)
{
Flame1->SetUInt32Value(OBJECT_FIELD_SCALE_X, 1073741824); // Make the Flame bigger
Flame1->setFaction(m_creature->getFaction());
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();
Glaive2->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
Flame2 = m_creature->SummonCreature(22997, X_GLAIVE2+5, Y_GLAIVE, Z_GLAIVE, 0, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 2000);
if(Flame2)
{
Flame2->SetUInt32Value(OBJECT_FIELD_SCALE_X, 1073741824); // BIG Flame
Flame2->setFaction(m_creature->getFaction());
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(!m_creature->GetMotionMaster()->empty())
m_creature->GetMotionMaster()->Clear(false);
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, false);
GlaiveGUID[i] = 0;
LandTimer = 10000;
m_creature->InterruptSpell(CURRENT_GENERIC_SPELL);
}
}
if(LandTimer)
{
if(LandTimer < diff)
{
m_creature->SetHover(false);
m_creature->HandleEmoteCommand(EMOTE_ONESHOT_LAND);
Phase = 3;
m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
m_creature->GetMotionMaster()->Mutate(new TargetedMovementGenerator(*m_creature->getVictim()));
m_creature->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_DISPLAY, 45479);
m_creature->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_DISPLAY+1, 45481);
}else LandTimer -= diff;
return; // Do not continue past this point if LandTimer is not 0 and we are in phase 2.
}
}
}
if(GlobalTimer < diff)
{
if(FlyTimer < diff)
{
m_creature->InterruptSpell(CURRENT_GENERIC_SPELL);
uint32 random = rand()%5;
Move(Flight[random].x, Flight[random].y, Flight[random].z, 3000, m_creature);
FlyTimer = 15000;
GlobalTimer = 1000;
}else FlyTimer -= diff;
if(FireballTimer < diff)
{
m_creature->InterruptSpell(CURRENT_GENERIC_SPELL);
DoCast(SelectUnit(SELECT_TARGET_RANDOM, 0), SPELL_FIREBALL);
FireballTimer = 7000;
GlobalTimer += 1500;
}else FireballTimer -= diff;
if(DarkBarrageTimer < diff)
{
m_creature->InterruptSpell(CURRENT_GENERIC_SPELL);
DoCast(SelectUnit(SELECT_TARGET_RANDOM, 0), SPELL_DARK_BARRAGE);
DarkBarrageTimer = 41000;
GlobalTimer += 9000;
}else DarkBarrageTimer -= diff;
if(EyeBlastTimer < diff)
{
// Does not work properly
CastEyeBlast();
EyeBlastTimer = 30000;
}else EyeBlastTimer -= diff;
}else GlobalTimer -= diff;
}
/** Phase 3,5 spells only**/
if(Phase == 3 || Phase == 5)
{
if(GlobalTimer < diff)
{
if(AgonizingFlamesTimer < diff)
{
DoCast(m_creature->getVictim(), SPELL_AGONIZING_FLAMES);
AgonizingFlamesTimer = 60000;
GlobalTimer += 1500;
}else AgonizingFlamesTimer -= diff;
}else GlobalTimer -= diff;
if(TransformTimer < diff)
{
Phase = 6; // Transform sequence
DemonFormSequence = 0;
AnimationTimer = 0;
DoYell(SAY_MORPH, LANG_UNIVERSAL, NULL);
DoPlaySoundToSet(m_creature, SOUND_MORPH);
TransformTimer = 60000;
ShadowDemonTimer = 22000;
m_creature->GetMotionMaster()->Clear(false); // 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(false);
m_creature->GetMotionMaster()->Idle();
}
if(TransformTimer < diff)
{
Phase = 6;
DemonFormSequence = 5;
AnimationTimer = 100;
TransformTimer = 60000;
}else TransformTimer -= diff;
if(ShadowDemonTimer < diff)
{
m_creature->InterruptSpell(CURRENT_GENERIC_SPELL);
Creature* ShadowDemon = NULL;
for(uint8 i = 0; i < 4; i++)
{
Unit* target = NULL;
target = SelectUnit(SELECT_TARGET_RANDOM,0);
if(target && target->GetTypeId() == TYPEID_PLAYER) // only on players.
{
ShadowDemon = DoSpawnCreature(CREATURE_SHADOW_DEMON, 0,0,0,0,TEMPSUMMON_CORPSE_DESPAWN,0);
if(ShadowDemon)
{
ShadowDemon->AI()->AttackStart(target);
ShadowDemon->AddThreat(target, 5000000.0f);
}
}
}
ShadowDemonTimer = 60000;
}else ShadowDemonTimer -= diff;
if(GlobalTimer < diff)
{
if(ShadowBlastTimer < diff)
{
Unit* target = SelectUnit(SELECT_TARGET_TOPAGGRO, 0);
if(target)
{
m_creature->SetUInt64Value(UNIT_FIELD_TARGET, target->GetGUID());
DoCast(SelectUnit(SELECT_TARGET_TOPAGGRO, 0), SPELL_SHADOW_BLAST);
}
ShadowBlastTimer = 4000;
GlobalTimer += 1500;
}else ShadowBlastTimer -= diff;
if(FlameBurstTimer < diff)
{
DoCast(m_creature, SPELL_FLAME_BURST);
FlameBurstTimer = 22000;
DoFlameBurstExplosion();
GlobalTimer += 1000;
}else FlameBurstTimer -= diff;
}else GlobalTimer -= diff;
}
/** Phase 5 timers. Enrage spell **/
if(Phase == 5)
{
if(EnrageTimer < diff)
{
DoCast(m_creature, SPELL_ENRAGE);
EnrageTimer = 40000;
CageTimer = 30000;
TransformTimer += 10000;
}else EnrageTimer -= diff;
if(CageTimer < diff)
{
if(MaievGUID)
{
Unit* Maiev = Unit::GetUnit((*m_creature), MaievGUID);
if(!Maiev) return;
uint32 random = rand()%7;
float X = CageTrap[random].x;
float Y = CageTrap[random].y;
float Z = CageTrap[random].z;
Move(X, Y, Z, 0, Maiev);
Maiev->CastSpell(Maiev, SPELL_TELEPORT_VISUAL, true);
Maiev->CastSpell(Maiev, SPELL_CAGE_TRAP_SUMMON, false);
}
CageTimer = 15000;
}else CageTimer -= diff;
}
if(Phase == 6) // Demonic Transformation
{
if(AnimationTimer < diff)
{
HandleDemonTransformAnimation(DemonFormSequence);
DemonFormSequence++;
}else AnimationTimer -= diff;
}
}
};
void npc_akama_illidanAI::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
m_creature->SetVisibility(VISIBILITY_ON);
}
void npc_akama_illidanAI::EnterEvadeMode()
{
SetVariables();
m_creature->DeleteThreatList();
m_creature->RemoveAllAuras();
m_creature->CombatStop();
DoGoHome();
}
void npc_akama_illidanAI::BeginEvent(Player *player)
{
InCombat = true;
if(pInstance)
IllidanGUID = pInstance->GetData64("IllidanStormrage");
if(IllidanGUID)
{
Creature* Illidan = ((Creature*)Unit::GetUnit((*m_creature), IllidanGUID));
if(Illidan)
{
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())->InCombat = true; // Set Illidan in combat
((boss_illidan_stormrageAI*)Illidan->AI())->AkamaGUID = m_creature->GetGUID();
m_creature->SetUInt64Value(UNIT_FIELD_TARGET, Illidan->GetGUID());
if(player)
Illidan->AddThreat(player, 1000.0f);
IsTalking = true; // Prevent Akama from starting to attack him
InCombat = true;
m_creature->SetUInt32Value(UNIT_NPC_FLAGS, 0); // Prevent players from talking again
Illidan->GetMotionMaster()->Clear(false);
Illidan->GetMotionMaster()->Idle();
m_creature->GetMotionMaster()->Clear(false);
m_creature->GetMotionMaster()->Idle();
}
}
}
void npc_akama_illidanAI::AttackStart(Unit *who)
{
if((!who) || IsTalking)
return;
if(who->isTargetableForAttack() && who!= m_creature)
{
DoStartMeleeAttack(who);
if(!InCombat)
{
InCombat = true;
}
}
}
void npc_akama_illidanAI::DamageTaken(Unit *done_by, uint32 &damage)
{
if(damage > m_creature->GetHealth() && (done_by->GetGUID() != m_creature->GetGUID()))
{
damage = 0;
DoCast(m_creature, SPELL_HEALING_POTION);
}
}
void npc_akama_illidanAI::DeleteFromThreatList()
{
if(!IllidanGUID) return; // If we do not have Illidan's GUID, do not proceed
Creature* Illidan = ((Creature*)Unit::GetUnit((*m_creature), IllidanGUID)); // Create a pointer to Illidan
if(!Illidan) return; // No use to continue if Illidan does not exist
std::list i_threatlist = Illidan->getThreatManager().getThreatList();
if(!i_threatlist.size()) return;// Threatlist is empty, do not proceed.
std::list::iterator itr = i_threatlist.begin();
std::advance(itr, 0);
for( ; itr != i_threatlist.end(); ++itr)
{
if((*itr)->getUnitGuid() == m_creature->GetGUID()) // Loop through threatlist till our GUID is found in it.
{
(*itr)->removeReference(); // Delete ourself from his threatlist.
break; // No need to continue anymore.
}
}
}
void npc_akama_illidanAI::UpdateAI(const uint32 diff)
{
if(IllidanGUID)
{
Creature* Illidan = ((Creature*)Unit::GetUnit((*m_creature), IllidanGUID));
if(Illidan)
{
if(Illidan->IsInEvadeMode() && !m_creature->IsInEvadeMode())
EnterEvadeMode();
if(((Illidan->GetHealth()*100 / Illidan->GetMaxHealth()) < 85) && (!RunAway))
{
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:
m_creature->SetVisibility(VISIBILITY_OFF);
IsTalking = true;
TalkTimer = 2000;
TalkCount = 3;
break;
case 3:
DeleteFromThreatList();
m_creature->DealDamage(m_creature, m_creature->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_NORMAL, NULL, false);
break;
}
}else TalkTimer -= diff;
}
}
}else
{
if(pInstance)
IllidanGUID = pInstance->GetData64("IllidanStormrage");
}
// If we don't have a target, or is talking, or has run away, return
if(!m_creature->SelectHostilTarget() || !m_creature->getVictim() || IsTalking || RunAway) 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(player);
}
return true;
}
bool GossipHello_npc_akama_at_illidan(Player *player, Creature *_Creature)
{
player->ADD_GOSSIP_ITEM(0, GOSSIP_ITEM, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF);
player->PlayerTalkClass->SendGossipMenu(10465, _Creature->GetGUID());
return true;
}
struct MANGOS_DLL_SPEC boss_maievAI : public ScriptedAI
{
boss_maievAI(Creature *c) : ScriptedAI(c)
{
pInstance = ((ScriptedInstance*)c->GetMap()->GetInstanceData());
SetVariables();
};
bool InCombat;
uint32 TauntTimer;
uint64 IllidanGUID;
ScriptedInstance* pInstance;
void SetVariables()
{
InCombat = false;
TauntTimer = 12000;
IllidanGUID = 0;
}
void EnterEvadeMode()
{
SetVariables();
m_creature->RemoveAllAuras();
m_creature->DeleteThreatList();
m_creature->CombatStop();
DoGoHome();
}
void AttackStart(Unit *who)
{
if(!who)
return;
if(who->isTargetableForAttack() && who!= m_creature)
{
DoStartMeleeAttack(who);
if(!InCombat)
{
InCombat = true;
}
}
}
void DamageTaken(Unit *done_by, uint32 &damage)
{
damage = 0;
}
/** Similar workaround as Illian's attack anims **/
void DoMeleeAttackIfReadyWithAnimations()
{
//If we are within range melee the target
if( m_creature->IsWithinDistInMap(m_creature->getVictim(), ATTACK_DISTANCE))
{
//Make sure our attack is ready and we arn't currently casting
if( m_creature->isAttackReady() && !m_creature->IsNonMeleeSpellCasted(false))
{
m_creature->HandleEmoteCommand(36);
//m_creature->AttackerStateUpdate(m_creature->getVictim()); // Causes problems when Illidan aggroes her; they fall under the map.
m_creature->resetAttackTimer();
}
}
}
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 UpdateAI(const uint32 diff)
{
// Return if we don't have a target
if(!m_creature->SelectHostilTarget() || !m_creature->getVictim())
return;
if(!IllidanGUID)
{
if(pInstance)
{
IllidanGUID = pInstance->GetData64("IllidanStormrage");
}
}else
{
Unit* Illidan = NULL;
Illidan = Unit::GetUnit((*m_creature), IllidanGUID);
if(Illidan && (!Illidan->isAlive() || ((Illidan->GetHealth()*100 / Illidan->GetMaxHealth()) < 2) || (Illidan->getThreatManager().getThreatList().empty())))
return; // Cease all action if Illidan is dead or in the death phase or has no aggro target
}
if(TauntTimer < diff)
{
uint32 random = rand()%4;
char* text = MaievTaunts[random].text;
uint32 sound = MaievTaunts[random].sound;
DoYell(text, LANG_UNIVERSAL, NULL);
DoPlaySoundToSet(m_creature, sound);
TauntTimer = 22000 + rand()%21 * 1000;
}else TauntTimer -= diff;
DoMeleeAttackIfReadyWithAnimations();
}
};
struct MANGOS_DLL_DECL cage_trap_triggerAI : public ScriptedAI
{
cage_trap_triggerAI(Creature *c) : ScriptedAI(c) {EnterEvadeMode();}
uint32 DespawnTimer;
bool HasCaged;
void EnterEvadeMode()
{
HasCaged = false;
DespawnTimer = 0;
m_creature->SetUInt32Value(OBJECT_FIELD_SCALE_X, 1036831949);
m_creature->SetUInt32Value(UNIT_FIELD_DISPLAYID, 15882);
m_creature->RemoveAllAuras();
m_creature->DeleteThreatList();
m_creature->CombatStop();
DoGoHome();
}
void AttackStart(Unit *who){ return; }
void MoveInLineOfSight(Unit *who)
{
if(who && (who->GetTypeId() != TYPEID_PLAYER))
{
if(who->GetEntry() == 22917) // Check if who is Illidan
{
if((!HasCaged) && (!who->HasAura(SPELL_CAGED, 0)) && m_creature->IsWithinDistInMap(who, 3))
{
HasCaged = true;
who->CastSpell(who, SPELL_CAGED, true);
DespawnTimer = 5000;
if(who->HasAura(SPELL_ENRAGE, 0))
who->RemoveAurasDueToSpell(SPELL_ENRAGE); // Dispel his enrage
}
}
}
}
void UpdateAI(const uint32 diff)
{
if(DespawnTimer)
{
if(DespawnTimer < diff)
{
m_creature->SetVisibility(VISIBILITY_OFF); // So that players don't see the sparkly effect when we die.
m_creature->DealDamage(m_creature, m_creature->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_NORMAL, NULL, false);
}else DespawnTimer -= diff;
}
}
};
//This is used to sort the players by distance in preparation for being charged by the flames.
struct TargetDistanceOrder : public std::binary_function
{
const Unit* MainTarget;
TargetDistanceOrder(const Unit* Target) : MainTarget(Target) {};
// functor for operator ">"
bool operator()(const Unit* _Left, const Unit* _Right) const
{
return (MainTarget->GetDistanceSq(_Left) > MainTarget->GetDistanceSq(_Right));
}
};
struct MANGOS_DLL_DECL flame_of_azzinothAI : public ScriptedAI
{
flame_of_azzinothAI(Creature *c) : ScriptedAI(c) {SetVariables();}
uint32 FlameBlastTimer;
uint32 SummonBlazeTimer;
uint32 ChargeTimer;
bool InCombat;
void SetVariables()
{
FlameBlastTimer = 15000;
SummonBlazeTimer = 10000;
ChargeTimer = 5000;
}
void EnterEvadeMode()
{
InCombat = false;
m_creature->RemoveAllAuras();
m_creature->DeleteThreatList();
m_creature->CombatStop();
DoGoHome();
}
void AttackStart(Unit *who)
{
if(!who)
return;
if(who->isTargetableForAttack() && who!= m_creature)
{
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 Charge()
{
// Get the Threat List
std::list m_threatlist = m_creature->getThreatManager().getThreatList();
if(!m_threatlist.size()) return; // He doesn't have anyone in his threatlist, useless to continue
std::list targets;
std::list::iterator itr = m_threatlist.begin();
std::advance(itr, 0);
for( ; itr!= m_threatlist.end(); ++itr) //store the threat list in a different container
{
Unit *target = Unit::GetUnit(*m_creature, (*itr)->getUnitGuid());
if(target && target->isAlive() && target->GetTypeId() == TYPEID_PLAYER ) //only on alive players
targets.push_back( target);
}
//Sort the list of players
targets.sort(TargetDistanceOrder(m_creature));
//Resize so we only get the furthest target
targets.resize(1);
Unit* target = (*targets.begin());
if(target && (!m_creature->IsWithinDistInMap(target, 40)))
{
DoCast(m_creature, SPELL_ENRAGE, true);
DoCast(target, SPELL_CHARGE);
}
}
void UpdateAI(const uint32 diff)
{
// Return if we don't have a target
if(!m_creature->SelectHostilTarget() || !m_creature->getVictim())
return;
if(FlameBlastTimer < diff)
{
DoCast(m_creature->getVictim(), SPELL_FLAME_BLAST);
FlameBlastTimer = 30000;
}else FlameBlastTimer -= diff;
if(SummonBlazeTimer < diff)
{
m_creature->HandleEmoteCommand(51); // Pretty much just to indicate that there's a blaze coming
DoCast(m_creature, SPELL_BLAZE_SUMMON);
SummonBlazeTimer = 20000;
}else SummonBlazeTimer -= diff;
if(ChargeTimer < diff)
{
Charge();
ChargeTimer = 5000;
}else ChargeTimer -= diff;
DoMeleeAttackIfReady();
}
};
struct MANGOS_DLL_DECL shadow_demonAI : public ScriptedAI
{
shadow_demonAI(Creature *c) : ScriptedAI(c) {EnterEvadeMode();}
uint64 TargetGUID;
bool InCombat;
bool HasCast;
void EnterEvadeMode()
{
TargetGUID = 0;
InCombat = false;
HasCast = false;
m_creature->RemoveAllAuras();
m_creature->DeleteThreatList();
m_creature->CombatStop();
DoGoHome();
}
void AttackStart(Unit *who)
{
if(!who)
return;
if(who->isTargetableForAttack() && who!= m_creature)
{
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)
{
if(TargetGUID)
{
Unit* target = Unit::GetUnit((*m_creature), TargetGUID);
if(target)
target->RemoveAurasDueToSpell(SPELL_PARALYZE);
}
}
void UpdateAI(const uint32 diff)
{
if(!m_creature->SelectHostilTarget() || !m_creature->getVictim()) return;
if(m_creature->getVictim()->GetTypeId() != TYPEID_PLAYER) return; // Only cast the below on players.
if(!HasCast)
{
TargetGUID = m_creature->getVictim()->GetGUID();
m_creature->AddThreat(m_creature->getVictim(), 10000000.0f);
DoCast(m_creature, SPELL_SHADOW_DEMON_PASSIVE, true);
DoCast(m_creature->getVictim(), SPELL_PURPLE_BEAM, true);
DoCast(m_creature->getVictim(), SPELL_PARALYZE, true);
HasCast = true;
}
if(m_creature->IsWithinDistInMap(m_creature->getVictim(), 3))
{
// Kill our target if we're very close.
m_creature->DealDamage(m_creature->getVictim(), m_creature->getVictim()->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_NORMAL, NULL, false);
HasCast = false; // Just in case we aggro someone else after this
}
}
};
struct MANGOS_DLL_DECL flamecrashAI : public ScriptedAI
{
flamecrashAI(Creature *c) : ScriptedAI(c) {EnterEvadeMode();}
uint32 FlameCrashTimer;
uint32 DespawnTimer;
void EnterEvadeMode()
{
FlameCrashTimer = 3000 +rand()%5000;
DespawnTimer = 60000;
m_creature->RemoveAllAuras();
m_creature->DeleteThreatList();
m_creature->CombatStop();
DoGoHome();
}
void AttackStart(Unit *who){ return; }
void MoveInLineOfSight(Unit *who){ return; }
void UpdateAI(const uint32 diff)
{
if(FlameCrashTimer < diff)
{
DoCast(m_creature, SPELL_FLAME_CRASH_EFFECT);
FlameCrashTimer = 15000;
}else FlameCrashTimer -= diff;
if(DespawnTimer < diff)
{
m_creature->SetVisibility(VISIBILITY_OFF); // So that players don't see the sparkly effect when we die.
m_creature->DealDamage(m_creature, m_creature->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_NORMAL, NULL, false);
}else DespawnTimer -= diff;
}
};
struct MANGOS_DLL_DECL demonfireAI : public ScriptedAI
{
demonfireAI(Creature *c) : ScriptedAI(c) {EnterEvadeMode();}
uint32 DemonFireTimer;
uint32 DespawnTimer;
void EnterEvadeMode()
{
DemonFireTimer = 0;
DespawnTimer = 60000;
m_creature->RemoveAllAuras();
m_creature->DeleteThreatList();
m_creature->CombatStop();
DoGoHome();
}
void AttackStart(Unit *who){ return; }
void MoveInLineOfSight(Unit *who){ return; }
void UpdateAI(const uint32 diff)
{
if(DemonFireTimer < diff)
{
DoCast(m_creature, SPELL_DEMON_FIRE);
DemonFireTimer = 30000;
}else DemonFireTimer -= diff;
if(DespawnTimer < diff)
{
m_creature->SetVisibility(VISIBILITY_OFF);
m_creature->DealDamage(m_creature, m_creature->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_NORMAL, NULL, false);
}else DespawnTimer -= diff;
}
};
struct MANGOS_DLL_DECL blazeAI : public ScriptedAI
{
blazeAI(Creature *c) : ScriptedAI(c) {EnterEvadeMode();}
uint32 BlazeTimer;
uint32 DespawnTimer;
void EnterEvadeMode()
{
BlazeTimer = 2000;
DespawnTimer = 30000;
m_creature->RemoveAllAuras();
m_creature->DeleteThreatList();
m_creature->CombatStop();
DoGoHome();
}
void AttackStart(Unit *who){ return; }
void MoveInLineOfSight(Unit *who){ return; }
void UpdateAI(const uint32 diff)
{
if(BlazeTimer < diff)
{
DoCast(m_creature, SPELL_BLAZE_EFFECT);
BlazeTimer = 15000;
}else BlazeTimer -= diff;
if(DespawnTimer < diff)
{
m_creature->SetVisibility(VISIBILITY_OFF);
m_creature->DealDamage(m_creature, m_creature->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_NORMAL, NULL, false);
}else DespawnTimer -= diff;
}
};
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);
}
CreatureAI* GetAI_boss_maiev(Creature *_Creature)
{
return new boss_maievAI (_Creature);
}
CreatureAI* GetAI_mob_flame_of_azzinoth(Creature *_Creature)
{
return new flame_of_azzinothAI (_Creature);
}
CreatureAI* GetAI_cage_trap_trigger(Creature *_Creature)
{
return new cage_trap_triggerAI (_Creature);
}
CreatureAI* GetAI_shadow_demon(Creature *_Creature)
{
return new shadow_demonAI (_Creature);
}
CreatureAI* GetAI_flamecrash(Creature *_Creature)
{
return new flamecrashAI (_Creature);
}
CreatureAI* GetAI_demonfire(Creature *_Creature)
{
return new demonfireAI (_Creature);
}
CreatureAI* GetAI_blaze(Creature *_Creature)
{
return new blazeAI (_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 = "npc_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;
newscript = new Script;
newscript->Name = "boss_maiev_shadowsong";
newscript->GetAI = GetAI_boss_maiev;
m_scripts[nrscripts++] = newscript;
newscript = new Script;
newscript->Name = "mob_flame_of_azzinoth";
newscript->GetAI = GetAI_mob_flame_of_azzinoth;
m_scripts[nrscripts++] = newscript;
newscript = new Script;
newscript->Name="mob_cage_trap_trigger";
newscript->GetAI = GetAI_cage_trap_trigger;
m_scripts[nrscripts++] = newscript;
newscript = new Script;
newscript->Name = "mob_shadow_demon";
newscript->GetAI = GetAI_shadow_demon;
m_scripts[nrscripts++] = newscript;
newscript = new Script;
newscript->Name="mob_flame_crash";
newscript->GetAI = GetAI_flamecrash;
m_scripts[nrscripts++] = newscript;
newscript = new Script;
newscript->Name="mob_demon_fire";
newscript->GetAI = GetAI_demonfire;
m_scripts[nrscripts++] = newscript;
newscript = new Script;
newscript->Name="mob_blaze";
newscript->GetAI = GetAI_blaze;
m_scripts[nrscripts++] = newscript;
}