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
// 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)
// 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.
// 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.
/***** 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
/******* The AI *******/
struct MANGOS_DLL_SPEC boss_illidan_stormrageAI : public ScriptedAI
{
boss_illidan_stormrageAI(Creature* c) : ScriptedAI(c)
{
SetVariables();
}
/** Generic **/
bool InCombat;
bool IsTalking;
uint32 Phase;
uint32 GlobalTimer;
uint32 TalkCount;
/** GUIDs **/
uint64 FlameGUID[1];
uint64 GlaiveGUID[1];
uint64 AkamaGUID;
uint64 MaievGUID;
/** Timers **/
uint32 ShearTimer;
uint32 DrawSoulTimer;
uint32 FlameCrashTimer;
uint32 ParasiticShadowFiendTimer;
uint32 FireballTimer;
uint32 EyeBlastTimer;
uint32 DarkBarrageTimer;
uint32 AgonizingFlamesTimer;
uint32 ShadowBlastTimer;
uint32 FlameBurstTimer;
uint32 ShadowDemonTimer;
uint32 SummonTimer;
uint32 TalkTimer;
uint32 TransformTimer;
uint32 EnrageTimer;
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;
AkamaGUID = 0;
MaievGUID = 0;
GlobalTimer = 0;
TalkCount = 0;
TalkTimer = 0;
// Kneel when not in combat
//DoCast(m_creature, SPELL_KNEEL);
/** 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 **/
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 = 30000;
ShadowDemonTimer = 35000;
TransformTimer = 60000;
EnrageTimer = 15000;
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)
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.
}
/** This will handle the cast of eye blast **/
void CastEyeBlast()
{
DoYell(SAY_EYE_BLAST, LANG_UNIVERSAL, NULL);
DoPlaySoundToSet(m_creature, SOUND_EYE_BLAST);
}
void SetGUID(char *Identifier, uint64 guid)
{
if(!Identifier || !guid) return;
if(Identifier == "Akama") DoYell("AKAMA!", LANG_UNIVERSAL, NULL); AkamaGUID = guid;
if(Identifier == "Maiev") DoYell("MAIEV", LANG_UNIVERSAL, NULL); MaievGUID = guid;
}
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)
{
case 0:
DoYell(SAY_INTRO_ILL1, LANG_UNIVERSAL, NULL);
DoPlaySoundToSet(m_creature, SOUND_INTRO_ILL1);
TalkTimer = 13000;
TalkCount = 1;
break;
case 1:
if(AkamaGUID)
{
Creature* Akama = ((Creature*)Unit::GetUnit((*m_creature), AkamaGUID));
if(Akama)
{
Akama->Yell(SAY_INTRO_AKA1, LANG_UNIVERSAL, NULL);
DoPlaySoundToSet(Akama, SOUND_INTRO_AKA1);
TalkTimer = 12000;
TalkCount = 2;
}
}
break;
case 2:
DoYell(SAY_INTRO_ILL2, LANG_UNIVERSAL, NULL);
DoPlaySoundToSet(m_creature, SOUND_INTRO_ILL2);
TalkTimer = 8000;
TalkCount = 3;
break;
case 3:
if(AkamaGUID)
{
Creature* Akama = ((Creature*)Unit::GetUnit((*m_creature), AkamaGUID));
if(Akama)
{
Akama->Yell(SAY_INTRO_AKA2, LANG_UNIVERSAL, NULL);
DoPlaySoundToSet(Akama, SOUND_INTRO_AKA2);
TalkTimer = 5000;
TalkCount = 4;
}
}
break;
case 4:
DoYell(SAY_INTRO_ILL3, LANG_UNIVERSAL, NULL);
DoPlaySoundToSet(m_creature, SOUND_INTRO_ILL3);
m_creature->setFaction(14); // Hostile
IsTalking = false;
break;
case 5:
DoYell(SAY_SUMMON_MAIEV, LANG_UNIVERSAL, NULL);
DoPlaySoundToSet(m_creature, SOUND_SUMMON_MAIEV);
TalkTimer = 8000;
TalkCount = 6;
break;
case 6:
if(MaievGUID)
{
Creature* Maiev = ((Creature*)Unit::GetUnit((*m_creature), MaievGUID));
if(Maiev)
{
Maiev->Yell(SAY_MAIEV1, LANG_UNIVERSAL, NULL);
DoPlaySoundToSet(Maiev, SOUND_MAIEV1);
TalkTimer = 9000;
TalkCount = 7;
}
}
break;
case 7:
DoYell(SAY_MAIEV_ILL2, LANG_UNIVERSAL, NULL);
DoPlaySoundToSet(m_creature, SOUND_MAIEV_ILL2);
TalkTimer = 7000;
TalkCount = 8;
break;
case 8:
if(MaievGUID)
{
Creature* Maiev = ((Creature*)Unit::GetUnit((*m_creature), MaievGUID));
if(Maiev)
{
Maiev->Yell(SAY_MAIEV2, LANG_UNIVERSAL, NULL);
DoPlaySoundToSet(Maiev, SOUND_MAIEV2);
TalkTimer = 10000;
TalkCount = 9;
}
}
break;
case 9:
DoYell(SAY_ATT_MAIEV, LANG_UNIVERSAL, NULL);
DoPlaySoundToSet(m_creature, SOUND_ATT_MAIEV);
if(MaievGUID)
m_creature->Attack(Unit::GetUnit((*m_creature), MaievGUID));
IsTalking = false;
break;
case 10:
if(MaievGUID)
{
Creature* Maiev = ((Creature*)Unit::GetUnit((*m_creature), MaievGUID));
if(Maiev && Maiev->isAlive())
{
Maiev->Yell(SAY_DEATH_MAIEV1, LANG_UNIVERSAL, NULL);
DoPlaySoundToSet(Maiev, SOUND_DEATH_MAIEV1);
TalkTimer = 6000;
TalkCount = 11;
}
}
break;
case 11:
DoYell(SAY_DEATH_ILL, LANG_UNIVERSAL, NULL);
DoPlaySoundToSet(m_creature, SOUND_DEATH_ILL);
TalkTimer = 22000;
TalkCount = 12;
break;
case 12:
if(MaievGUID)
{
Creature* Maiev = ((Creature*)Unit::GetUnit((*m_creature), MaievGUID));
if(Maiev && Maiev->isAlive())
{
Maiev->Yell(SAY_DEATH_MAIEV2, LANG_UNIVERSAL, NULL);
DoPlaySoundToSet(Maiev, SOUND_DEATH_MAIEV2);
TalkTimer = 9000;
TalkCount = 13;
}
}
break;
case 13:
if(AkamaGUID)
{
Creature* Akama = ((Creature*)Unit::GetUnit((*m_creature), AkamaGUID));
if(Akama && Akama->isAlive())
{
Akama->Relocate(m_creature->GetPositionX()+5, m_creature->GetPositionY()+5, m_creature->GetPositionZ());
Akama->SendMonsterMove(m_creature->GetPositionX()+5, m_creature->GetPositionY()+5, m_creature->GetPositionZ(), 0, false, 100);
m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
Akama->Yell(SAY_DEATH_AKA, LANG_UNIVERSAL, NULL);
DoPlaySoundToSet(Akama, SOUND_DEATH_AKA);
m_creature->DealDamage(m_creature, m_creature->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_NORMAL, NULL, 0, false);
}
}
break;
}
}else TalkTimer -= diff;
}
// If we don't have a target, return.
if(!m_creature->SelectHostilTarget() || !m_creature->getVictim() || IsTalking) return;
// Remove Kneel spell if in combat
if(InCombat && m_creature->HasAura(SPELL_KNEEL, 0)) m_creature->RemoveAllAuras();
/** 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 = 5;
MaievGUID = Maiev->GetGUID();
}
}
/** 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);
IsTalking = true;
TalkCount = 10;
}
/***** Spells for Phase 1, 3 and 5 (Normal Form) ******/
if(Phase == 1 || Phase == 3 || Phase == 5)
{
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(SummonTimer)
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)
{
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)
{
FlameGUID[1] = Flame2->GetGUID();
Glaive2->CastSpell(Flame2, SPELL_GREEN_BEAM, true);
}
}
SummonTimer = 0;
}else SummonTimer -= diff;
// Check if we are hovering. Recast if we are not.
if(!m_creature->isHover()) m_creature->SetHover(true);
// 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(FireballTimer < diff)
{
DoCast(SelectUnit(SELECT_TARGET_RANDOM, 0), SPELL_FIREBALL);
FireballTimer = 5000;
GlobalTimer += 1500;
}else FireballTimer -= diff;
if(DarkBarrageTimer < diff)
{
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)
{
//TODO: Transformation scene
DoYell(SAY_MORPH, LANG_UNIVERSAL, NULL);
DoPlaySoundToSet(m_creature, SOUND_MORPH);
DoCast(m_creature, SPELL_DEMON_FORM);
TransformTimer = 60000;
Phase = 4;
(*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)
{
//TODO: Transformation scene
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 = 60000;
}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);
//ShadowDemon->CastSpell(target, SPELL_PARALYZE);
}
}
}
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;
}else GlobalTimer -= diff;
}
/** Phase 5 timers. Enrage spell **/
if(Phase == 5)
{
if(EnrageTimer < diff)
{
// DoCast(m_creature, SPELL_ENRAGE);
EnrageTimer = 15000;
}else EnrageTimer -= 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;
/* GUIDs */
uint64 IllidanGUID;
/* Generic */
bool InCombat;
bool IsTalking;
void SetVariables()
{
if(pInstance) pInstance->SetData("IllidanStormrageEvent", 0); // Not started
IllidanGUID = 0;
InCombat = false;
IsTalking = 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
uint32 TalkCount = ((boss_illidan_stormrageAI*)Illidan->AI())->TalkCount;
((boss_illidan_stormrageAI*)Illidan->AI())->IsTalking = true; // Begin Talking
((boss_illidan_stormrageAI*)Illidan->AI())->SetGUID("Akama", m_creature->GetGUID()); // Allow communication between Akama and Illidan scripts
IsTalking = true; // Prevent Akama from starting to attack him
Illidan->SetInFront(m_creature); // Face each other
DoFaceTarget(Illidan);
m_creature->SetUInt32Value(UNIT_NPC_FLAGS, 0); // Prevent players from talking again
}
}
}
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(damage > m_creature->GetHealth())
{
damage = 0;
m_creature->SetHealth(1);
}
}
void UpdateAI(const uint32 diff)
{
if(IllidanGUID)
{
Creature* Illidan = ((Creature*)Unit::GetUnit((*m_creature), IllidanGUID));
if(Illidan)
{
if(!((boss_illidan_stormrageAI*)Illidan->AI())->IsTalking)
IsTalking = false;
}
}
// If we don't have a target, return.
if(!m_creature->SelectHostilTarget() || !m_creature->getVictim() || IsTalking) return;
if((m_creature->GetHealth()*100 / m_creature->GetMaxHealth()) < 30)
DoCast(m_creature, SPELL_HEALING_POTION);
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_stormrage()
{
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;
}