aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorKeader <keader.android@gmail.com>2017-02-05 12:45:29 -0300
committerGitHub <noreply@github.com>2017-02-05 12:45:29 -0300
commit8731975187694d1989af93f9569b591d4ebd767b (patch)
tree34cae866e3686a9a927cea462a4ad03c9a1d817b /src
parent7c7b877c3fc0292f33f54f4e8b514be3bf8514a6 (diff)
Core/Scripts: Illidan Stormrage Rewrite (#18963)
Closes #5018
Diffstat (limited to 'src')
-rw-r--r--src/server/scripts/Outland/BlackTemple/black_temple.h48
-rw-r--r--src/server/scripts/Outland/BlackTemple/boss_illidan.cpp3747
-rw-r--r--src/server/scripts/Outland/BlackTemple/instance_black_temple.cpp35
3 files changed, 2101 insertions, 1729 deletions
diff --git a/src/server/scripts/Outland/BlackTemple/black_temple.h b/src/server/scripts/Outland/BlackTemple/black_temple.h
index cd3ee42e3b8..8a2cb69d603 100644
--- a/src/server/scripts/Outland/BlackTemple/black_temple.h
+++ b/src/server/scripts/Outland/BlackTemple/black_temple.h
@@ -38,22 +38,23 @@ enum DataTypes
// Additional Data
DATA_AKAMA_SHADE = 9,
- DATA_AKAMA = 10,
- DATA_GATHIOS_THE_SHATTERER = 11,
- DATA_HIGH_NETHERMANCER_ZEREVOR = 12,
- DATA_LADY_MALANDE = 13,
- DATA_VERAS_DARKSHADOW = 14,
- DATA_BLOOD_ELF_COUNCIL_VOICE = 15,
+ DATA_AKAMA = 10,
+ DATA_MAIEV = 11,
+ DATA_GO_ILLIDAN_GATE = 12,
+ DATA_BLACK_TEMPLE_TRIGGER = 13,
- DATA_GO_ILLIDAN_GATE = 16,
+ DATA_GATHIOS_THE_SHATTERER = 14,
+ DATA_HIGH_NETHERMANCER_ZEREVOR = 15,
+ DATA_LADY_MALANDE = 16,
+ DATA_VERAS_DARKSHADOW = 17,
+ DATA_BLOOD_ELF_COUNCIL_VOICE = 18,
- DATA_BLACK_TEMPLE_TRIGGER = 17,
- DATA_GO_DEN_OF_MORTAL_DOOR = 18,
+ DATA_GO_DEN_OF_MORTAL_DOOR = 19,
- DATA_ESSENCE_OF_SUFFERING = 19,
- DATA_ESSENCE_OF_DESIRE = 20,
- DATA_ESSENCE_OF_ANGER = 21
+ DATA_ESSENCE_OF_SUFFERING = 20,
+ DATA_ESSENCE_OF_DESIRE = 21,
+ DATA_ESSENCE_OF_ANGER = 22
};
enum TriggerEmotes
@@ -93,7 +94,17 @@ enum CreatureIds
NPC_ASHTONGUE_PRIMALIST = 22847,
NPC_ASHTONGUE_STORMCALLER = 22846,
NPC_ASHTONGUE_FERAL_SPIRIT = 22849,
- NPC_STORM_FURY = 22848
+ NPC_STORM_FURY = 22848,
+ NPC_SPIRIT_OF_UDALO = 23410,
+ NPC_SPIRIT_OF_OLUM = 23411,
+ NPC_FLAME_OF_AZZINOTH = 22997,
+ NPC_BLADE_OF_AZZINOTH = 22996,
+ NPC_MAIEV_SHADOWSONG = 23197,
+ NPC_ILLIDAN_DB_TARGET = 23070,
+ NPC_ILLIDARI_ELITE = 23226,
+ NPC_GLAIVE_TARGET = 23448,
+ NPC_GLAIVE_WORLD_TRIGGER = 22515,
+ NPC_DEMON_FIRE = 23069
};
enum GameObjectIds
@@ -111,13 +122,18 @@ enum GameObjectIds
GO_COUNCIL_DOOR_2 = 186152,
GO_ILLIDAN_GATE = 185905,
GO_ILLIDAN_DOOR_R = 186261,
- GO_ILLIDAN_DOOR_L = 186262
+ GO_ILLIDAN_DOOR_L = 186262,
+ GO_ILLIDAN_CAGE_TRAP = 185916
};
-enum BlackTempleFactions
+enum BlackTempleMisc
{
ASHTONGUE_FACTION_FRIEND = 1820,
- AKAMA_FACTION_COMBAT = 1868
+ AKAMA_FACTION_COMBAT = 1868,
+ AKAMA_INTRO = 1,
+ AKAMA_FIGHT = 2,
+ ACTION_ACTIVE_AKAMA_INTRO = 3,
+ ACTION_OPEN_DOOR = 4
};
template<class AI>
diff --git a/src/server/scripts/Outland/BlackTemple/boss_illidan.cpp b/src/server/scripts/Outland/BlackTemple/boss_illidan.cpp
index 71d0e12911d..39fc20eea28 100644
--- a/src/server/scripts/Outland/BlackTemple/boss_illidan.cpp
+++ b/src/server/scripts/Outland/BlackTemple/boss_illidan.cpp
@@ -1,6 +1,5 @@
/*
* Copyright (C) 2008-2017 TrinityCore <http://www.trinitycore.org/>
- * Copyright (C) 2006-2009 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
@@ -16,13 +15,6 @@
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-/* ScriptData
-SDName: boss_illidan_stormrage
-SD%Complete: 90
-SDComment: Somewhat of a workaround for Parasitic Shadowfiend, unable to summon GOs for Cage Trap.
-SDCategory: Black Temple
-EndScriptData */
-
#include "ScriptMgr.h"
#include "ScriptedCreature.h"
#include "ScriptedGossip.h"
@@ -30,17 +22,12 @@ EndScriptData */
#include "black_temple.h"
#include "Player.h"
#include "SpellInfo.h"
+#include "SpellScript.h"
+#include "SpellAuraEffects.h"
+#include "GridNotifiersImpl.h"
-// Other defines
-#define CENTER_X 676.740f
-#define CENTER_Y 305.297f
-#define CENTER_Z 353.192f
-
-enum Say
+enum IllidanSay
{
- // Akama
- SAY_AKAMA_BEWARE = 0,
- SAY_AKAMA_LEAVE = 1,
// Illidan
SAY_ILLIDAN_MINION = 0,
SAY_ILLIDAN_KILL = 1,
@@ -50,424 +37,404 @@ enum Say
SAY_ILLIDAN_MORPH = 5,
SAY_ILLIDAN_ENRAGE = 6,
SAY_ILLIDAN_TAUNT = 7,
+ SAY_ILLIDAN_DUPLICITY = 8,
+ SAY_ILLIDAN_UNCONVINCED = 9,
+ SAY_ILLIDAN_PREPARED = 10,
+ SAY_ILLIDAN_SHADOW_PRISON = 11,
+ SAY_ILLIDAN_CONFRONT_MAIEV = 12,
+ SAY_ILLIDAN_FRENZY = 13,
+ SAY_ILLIDAN_DEFEATED = 14,
+
// Maiev Shadowsong
SAY_MAIEV_SHADOWSONG_TAUNT = 0,
+ SAY_MAIEV_SHADOWSONG_APPEAR = 1,
+ SAY_MAIEV_SHADOWSONG_JUSTICE = 2,
+ SAY_MAIEV_SHADOWSONG_TRAP = 3,
+ SAY_MAIEV_SHADOWSONG_DOWN = 4,
+ SAY_MAIEV_SHADOWSONG_FINISHED = 5,
+ SAY_MAIEV_SHADOWSONG_OUTRO = 6,
+ SAY_MAIEV_SHADOWSONG_FAREWELL = 7,
+
// Flame of Azzinoth
- EMOTE_AZZINOTH_GAZE = 0
-};
+ EMOTE_AZZINOTH_GAZE = 0,
-enum Spells
-// Normal Form
-{
- SPELL_SHEAR = 37335, // 41032 is bugged, cannot be block/dodge/parry// Reduces Max. Health by 60% for 7 seconds. Can stack 19 times. 1.5f second cast
- SPELL_FLAME_CRASH = 40832,
- SPELL_DRAW_SOUL = 40904,
- SPELL_PARASITIC_SHADOWFIEND = 41917,
- SPELL_PARASITIC_SHADOWFIEND2 = 41914,
- SPELL_SUMMON_PARASITICS = 41915,
- SPELL_AGONIZING_FLAMES = 40932,
- SPELL_ENRAGE = 40683,
-// Flying (Phase 2)
- SPELL_THROW_GLAIVE = 39635,
- SPELL_THROW_GLAIVE2 = 39849, // Animation for the spell above
- SPELL_GLAIVE_RETURNS = 39873,
- SPELL_FIREBALL = 40598,
- SPELL_DARK_BARRAGE = 40585,
-// Demon Form
- SPELL_DEMON_TRANSFORM_1 = 40511,
- SPELL_DEMON_TRANSFORM_2 = 40398,
- SPELL_DEMON_TRANSFORM_3 = 40510,
- SPELL_DEMON_FORM = 40506,
- SPELL_SHADOW_BLAST = 41078,
- SPELL_FLAME_BURST = 41126,
- SPELL_FLAME_BURST_EFFECT = 41131, // The actual damage. Have each player cast it on itself (workaround)
-// Other Illidan spells
- SPELL_KNEEL = 39656, // Before beginning encounter, this is how he appears (talking to skully).
- SPELL_SHADOW_PRISON = 40647,
- SPELL_DEATH = 41220,
- SPELL_BERSERK = 45078,
- SPELL_DUAL_WIELD = 42459,
- SPELL_SUMMON_MAIEV = 40403,
-// Phase Normal spells
- SPELL_FLAME_CRASH_EFFECT = 40836,
- SPELL_SUMMON_SHADOWDEMON = 41117,
- SPELL_SHADOWFIEND_PASSIVE = 41913,
- SPELL_SHADOW_DEMON_PASSIVE = 41079,
- SPELL_CONSUME_SOUL = 41080,
- SPELL_PARALYZE = 41083,
- SPELL_PURPLE_BEAM = 39123,
-// Phase Flight spells
- SPELL_AZZINOTH_CHANNEL = 39857, // Glaives cast it on Flames. Not sure if this is the right spell.
- SPELL_EYE_BLAST_TRIGGER = 40017,
- SPELL_EYE_BLAST = 39908,
- SPELL_BLAZE_EFFECT = 40610,
- SPELL_BLAZE_SUMMON = 40637,
- SPELL_DEMON_FIRE = 40029,
- SPELL_FLAME_BLAST = 40631,
- SPELL_CHARGE = 41581,
- SPELL_FLAME_ENRAGE = 45078,
-// Akama spells
- SPELL_AKAMA_DOOR_CHANNEL = 41268,
- SPELL_DEATHSWORN_DOOR_CHANNEL = 41269,
- SPELL_AKAMA_DOOR_FAIL = 41271, // Not sure where this is really used...
- SPELL_HEALING_POTION = 40535,
- SPELL_CHAIN_LIGHTNING = 40536,
-// Maiev spells
- SPELL_CAGE_TRAP_DUMMY = 40761, // Put this in DB for cage trap GO.
- SPELL_CAGED = 40695,
- SPELL_CAGE_TRAP_SUMMON = 40694, // Summons a Cage Trap GO (bugged) on the ground along with a Cage Trap Disturb Trigger mob (working)
- SPELL_CAGE_TRAP_BEAM = 40713,
- SPELL_TELEPORT_VISUAL = 41232,
- SPELL_SHADOW_STRIKE = 40685,
- SPELL_THROW_DAGGER = 41152,
- SPELL_FAN_BLADES = 39954 // bugged visual
+ // Akama
+ SAY_AKAMA_DOOR = 0,
+ SAY_AKAMA_ALONE = 1,
+ SAY_AKAMA_SALUTE = 2,
+ SAY_AKAMA_BETRAYER = 3,
+ SAY_AKAMA_FREE = 4,
+ SAY_AKAMA_TIME_HAS_COME = 5,
+ SAY_AKAMA_MINIONS = 6,
+ SAY_AKAMA_LIGHT = 7,
+ SAY_AKAMA_FINISH = 8,
+
+ // Spirits
+ SAY_SPIRIT_ALONE = 0,
+
+ // Direct Sounds
+ ILLIDAN_TAKEOFF_SOUND_ID = 11479,
+ ILLIDAN_WARGLAIVE_SOUND_ID = 11480,
+ WARGLAIVE_SPAWN_SOUND_ID = 11689
};
-enum Misc
+enum IllidanSpells
{
- FLAME_ENRAGE_DISTANCE = 30,
- FLAME_CHARGE_DISTANCE = 50,
+ // Akama
+ SPELL_AKAMA_DOOR_CHANNEL = 41268,
+ SPELL_AKAMA_DOOR_FAIL = 41271,
+ SPELL_HEALING_POTION = 40535,
+ SPELL_CHAIN_LIGHTNING = 40536,
+ SPELL_AKAMA_TELEPORT = 41077,
+ SPELL_AKAMA_DESPAWN = 41242,
- EQUIP_ID_MAIN_HAND = 32837,
- EQUIP_ID_OFF_HAND = 32838,
- EQUIP_ID_MAIN_HAND_MAIEV = 44850,
+ // Spirits
+ SPELL_DEATHSWORN_DOOR_CHANNEL = 41269,
- MODEL_INVISIBLE = 11686,
- MODEL_ILLIDAN = 21135,
- MODEL_BLADE = 21431
-};
+ // Door Trigger
+ SPELL_ARCANE_EXPLOSION = 35426,
-/**** Creature Summon and Recognition IDs ****/
-enum CreatureEntry
-{
- EMPTY = 0,
- AKAMA = 22990,
- ILLIDAN_STORMRAGE = 22917,
- BLADE_OF_AZZINOTH = 22996,
- FLAME_OF_AZZINOTH = 22997,
- MAIEV_SHADOWSONG = 23197,
- SHADOW_DEMON = 23375,
- DEMON_FIRE = 23069,
- FLAME_CRASH = 23336,
- ILLIDAN_DOOR_TRIGGER = 23412,
- SPIRIT_OF_OLUM = 23411,
- SPIRIT_OF_UDALO = 23410,
- ILLIDARI_ELITE = 23226,
- PARASITIC_SHADOWFIEND = 23498,
- CAGE_TRAP_TRIGGER = 23292
+ // Blade of Azzinoth
+ SPELL_BIRTH = 40031,
+ SPELL_SUMMON_TEAR_OF_AZZINOTH = 39855,
+ SPELL_AZZINOTH_CHANNEL = 39857,
+ SPELL_GLAIVE_RETURNS = 39873,
+
+ // Flame of Azzinoth
+ SPELL_FLAME_TEAR_OF_AZZINOTH = 39856,
+ SPELL_CHARGE = 42003,
+ SPELL_FLAME_BLAST = 40631,
+ SPELL_UNCAGED_WRATH = 39869,
+
+ // Maiev
+ SPELL_TELEPORT_VISUAL = 41236,
+ SPELL_CAGE_TRAP_SUMMON = 40694,
+ SPELL_SHADOW_STRIKE = 40685,
+ SPELL_THROW_DAGGER = 41152,
+ SPELL_MAIEV_DOWN = 40409,
+
+ // Cage Trap Disturb Trigger
+ SPELL_CAGE_TRAP_PERIODIC = 40761,
+
+ // Shadow Demon
+ SPELL_SHADOW_DEMON_PASSIVE = 41079,
+ SPELL_FIND_TARGET = 41081,
+ SPELL_PARALYZE = 41083,
+ SPELL_CONSUME_SOUL = 41080,
+
+ // Player
+ SPELL_SUMMON_PARASITIC_SHADOWFIENDS = 41915,
+ SPELL_BLAZE_SUMMON = 40637,
+
+ // Illidan DB Target
+ SPELL_EYE_BLAST_TRIGGER = 40017,
+
+ // Cage Trap Summon Spells
+ SPELL_SUMMON_CAGE_TRAP_1 = 40696,
+ SPELL_SUMMON_CAGE_TRAP_2 = 40697,
+ SPELL_SUMMON_CAGE_TRAP_3 = 40698,
+ SPELL_SUMMON_CAGE_TRAP_4 = 40699,
+ SPELL_SUMMON_CAGE_TRAP_5 = 40700,
+ SPELL_SUMMON_CAGE_TRAP_6 = 40701,
+ SPELL_SUMMON_CAGE_TRAP_7 = 40702,
+ SPELL_SUMMON_CAGE_TRAP_8 = 40703,
+
+ // Glaive Target
+ SPELL_RANGE_MARKER = 41997,
+ SPELL_SUMMON_GLAIVE = 41466,
+
+ // Illidan
+ SPELL_FLAME_CRASH = 40832,
+ SPELL_SHEAR = 41032,
+ SPELL_DRAW_SOUL = 40904,
+ SPELL_DRAW_SOUL_HEAL = 40903,
+ SPELL_PARASITIC_SHADOWFIEND = 41917,
+ SPELL_AGONIZING_FLAMES = 40932,
+ SPELL_AGONIZING_FLAMES_SELECTOR = 40834,
+ SPELL_FRENZY = 40683,
+ SPELL_THROW_GLAIVE = 39849,
+ SPELL_THROW_GLAIVE2 = 39635,
+ SPELL_FIREBALL = 40598,
+ SPELL_DARK_BARRAGE = 40585,
+ SPELL_DEMON_TRANSFORM_1 = 40511,
+ SPELL_DEMON_TRANSFORM_2 = 40398,
+ SPELL_DEMON_TRANSFORM_3 = 40510,
+ SPELL_DEMON_FORM = 40506,
+ SPELL_AURA_OF_DREAD = 41142,
+ SPELL_SHADOW_BLAST = 41078,
+ SPELL_FLAME_BURST = 41126,
+ SPELL_FLAME_BURST_EFFECT = 41131,
+ SPELL_KNEEL = 39656,
+ SPELL_SHADOW_PRISON = 40647,
+ SPELL_EMOTE_TALK_QUESTION = 41616,
+ SPELL_BERSERK = 45078,
+ SPELL_SUMMON_MAIEV = 40403,
+ SPELL_TELEPORT_MAIEV = 41221,
+ SPELL_CLEAR_ALL_DEBUFFS = 34098,
+ SPELL_DEATH = 41218,
+ SPELL_QUIET_SUICIDE = 3617,
+ SPELL_SUMMON_SHADOWDEMON = 41117,
+ SPELL_CAGED_TRAP_TELEPORT = 40693,
+ SPELL_CAGE_TRAP = 40760,
+ SPELL_CAGED_DEBUFF = 40695,
+ SPELL_EYE_BLAST = 39908
};
-/*** Phase Names ***/
-enum PhaseIllidan
-{
- PHASE_ILLIDAN_NULL = 0,
- PHASE_NORMAL = 1,
- PHASE_FLIGHT = 2,
- PHASE_NORMAL_2 = 3,
- PHASE_DEMON = 4,
- PHASE_NORMAL_MAIEV = 5,
- PHASE_TALK_SEQUENCE = 6,
- PHASE_FLIGHT_SEQUENCE = 7,
- PHASE_TRANSFORM_SEQUENCE = 8,
- PHASE_ILLIDAN_MAX = 9
-}; // Maiev uses the same phase
-
-enum PhaseAkama
+enum IllidanMisc
{
- PHASE_AKAMA_NULL = 0,
- PHASE_CHANNEL = 1,
- PHASE_WALK = 2,
- PHASE_TALK = 3,
- PHASE_FIGHT_ILLIDAN = 4,
- PHASE_FIGHT_MINIONS = 5,
- PHASE_RETURN = 6
+ GOSSIP_START_INTRO = 0,
+ GOSSIP_START_FIGHT = 1,
+ SUMMON_GROUP = 1,
+ DATA_AKAMA_TELEPORT_POSITION = 0,
+ MAX_MINIONS_NUMBER = 10,
+ SPELL_GLAIVE_VISUAL_KIT = 7668
};
-enum EventIllidan
+enum IllidanActions
{
- EVENT_NULL = 0,
- EVENT_BERSERK = 1,
- // normal phase
- EVENT_TAUNT = 2,
- EVENT_SHEAR = 3,
- EVENT_FLAME_CRASH = 4,
- EVENT_PARASITIC_SHADOWFIEND = 5,
- EVENT_PARASITE_CHECK = 6,
- EVENT_DRAW_SOUL = 7,
- EVENT_AGONIZING_FLAMES = 8,
- EVENT_TRANSFORM_NORMAL = 9,
- EVENT_ENRAGE = 10,
- // flight phase
- EVENT_FIREBALL = 2,
- EVENT_DARK_BARRAGE = 3,
- EVENT_EYE_BLAST = 4,
- EVENT_MOVE_POINT = 5,
- // demon phase
- EVENT_SHADOW_BLAST = 2,
- EVENT_FLAME_BURST = 3,
- EVENT_SHADOWDEMON = 4,
- EVENT_TRANSFORM_DEMON = 5,
- // sequence phase
- EVENT_TALK_SEQUENCE = 2,
- EVENT_FLIGHT_SEQUENCE = 2,
- EVENT_TRANSFORM_SEQUENCE = 2
+ ACTION_START_ENCOUNTER = 5,
+ ACTION_FREE,
+ ACTION_INTRO_DONE,
+ ACTION_START_MINIONS,
+ ACTION_START_MINIONS_WEAVE,
+ ACTION_START_PHASE_2,
+ ACTION_FLAME_DEAD,
+ ACTION_FINALIZE_AIR_PHASE,
+ ACTION_START_PHASE_4,
+ ACTION_ILLIDAN_CAGED,
+ ACTION_START_OUTRO,
+ ACTION_MAIEV_DOWN_FADE
};
-enum EventMaiev
+enum IllidanPhases
{
- EVENT_MAIEV_NULL = 0,
- EVENT_MAIEV_STEALTH = 1,
- EVENT_MAIEV_TAUNT = 2,
- EVENT_MAIEV_SHADOW_STRIKE = 3,
- EVENT_MAIEV_THROW_DAGGER = 4,
- EVENT_MAIEV_TRAP = 4
+ PHASE_INTRO = 1,
+ PHASE_1,
+ PHASE_MINIONS,
+ PHASE_2,
+ PHASE_3,
+ PHASE_4
};
-static const EventIllidan MaxTimer[9] =
+enum IllidanSplineMovement
{
- EVENT_NULL,
- EVENT_DRAW_SOUL,
- EVENT_MOVE_POINT,
- EVENT_TRANSFORM_NORMAL,
- EVENT_TRANSFORM_DEMON,
- EVENT_ENRAGE,
- EVENT_TALK_SEQUENCE,
- EVENT_FLIGHT_SEQUENCE,
- EVENT_TRANSFORM_SEQUENCE
+ SPLINE_ILLIDARI_COUNCIL = 1,
+ SPLINE_STAIRS = 2,
+ SPLINE_ILLIDAN_ROOM = 3,
+ SPLINE_FACE_ILLIDAN = 4,
+ SPLINE_TELEPORT = 5,
+ SPLINE_MINIONS = 6,
+ SPLINE_MOVE_BACK = 7
};
-
-/* ################## TO DO CONVERT THIS UGLINESS TO CREATURE TEXT ##################
-
-SET @AKAMA := 23089;
-SET @ILLIDAN := 22917;
-SET @MAIEV := 23197;
-DELETE FROM `creature_text` WHERE `entry`=@AKAMA AND `groupid` IN (2,3,4);
-DELETE FROM `creature_text` WHERE `entry`=@ILLIDAN AND `groupid` IN (8,9,10,11,12,13,14);
-DELETE FROM `creature_text` WHERE `entry`=@MAIEV AND `groupid` IN (1,2,3,4);
-INSERT INTO `creature_text` (`entry`,`groupid`,`id`,`text`,`type`,`language`,`probability`,`emote`,`duration`,`sound`,`comment`) VALUES
-(@ILLIDAN,8,0, "Akama... your duplicity is hardly surprising. I should have slaughtered you and your malformed brethren long ago.",14,0,100,0,0,11463, 'Illidan SAY_XXXXXXXXXXX'),
-(@AKAMA,2,0, "We've come to end your reign, Illidan. My people and all of Outland shall be free!",14,0,100,25,0,11389, 'Akama SAY_XXXXXXXXXXX'),
-(@ILLIDAN,9,0, "Boldly said. But I remain unconvinced.",14,0,100,396,0,11464, 'Illidan SAY_XXXXXXXXXXX'),
-(@AKAMA,3,0, "The time has come! The moment is at hand!",14,0,100,22,0,11380, 'Akama SAY_XXXXXXXXXXX'),
-(@ILLIDAN,10,0, "You are not prepared!",14,0,100,406,0,11466, 'Illidan SAY_XXXXXXXXXXX'),
-(@ILLIDAN,11,0, "Is this it, mortals? Is this all the fury you can muster?",14,0,100,0,0,11476, 'Illidan SAY_XXXXXXXXXXX'),
-(@MAIEV,1,0, "Their fury pales before mine, Illidan. We have some unsettled business between us.",14,0,100,5,0,11491, 'Maiev Shadowsong SAY_XXXXXXXXXXX'),
-(@ILLIDAN,12,0, "Maiev... How is this even possible?",14,0,100,1,0,11477, 'Illidan SAY_XXXXXXXXXXX'),
-(@MAIEV,2,0, "Ah... my long hunt is finally over. Today, Justice will be done!",14,0,100,15,0,11492, 'Maiev Shadowsong SAY_XXXXXXXXXXX'),
-(@ILLIDAN,13,0, "Feel the hatred of ten thousand years!",14,0,100,396,0,11470, 'Illidan SAY_XXXXXXXXXXX'),
-(@MAIEV,3,0, "Ahh... It is finished. You are beaten.",14,0,100,0,0,11496, 'Maiev Shadowsong SAY_XXXXXXXXXXX'),
-(@ILLIDAN,14,0, "You have won... Maiev...but the huntress... is nothing...without the hunt... you... are nothing... without me..",14,0,100,65,0,11478, 'Illidan SAY_XXXXXXXXXXX'),
-(@MAIEV,4,0, "He is right. I feel nothing... I am nothing... Farewell, champions.",14,0,100,0,0,11497, 'Maiev Shadowsong SAY_XXXXXXXXXXX'),
-(@AKAMA,4,0, "The Light will fill these dismal halls once again. I swear it.",14,0,100,0,0,11387, 'Akama SAY_XXXXXXXXXXX');
-
-*/
-
-struct Yells
+enum IllidanPoints
{
- uint32 sound;
- std::string text;
- uint32 creature, timer, emote;
- bool Talk;
+ POINT_ILLIDARI_COUNCIL = 1,
+ POINT_STAIRS,
+ POINT_ILLIDAN_ROOM,
+ POINT_FACE_ILLIDAN,
+ POINT_TELEPORT,
+ POINT_MINIONS,
+ POINT_THROW_GLAIVE,
+ POINT_RANDOM_PILLAR,
+ POINT_DB_TARGET,
+ POINT_ILLIDAN_MIDDLE,
+ POINT_MOVE_BACK,
+ POINT_ILLIDAN
};
-static const Yells Conversation[22] =
+enum IllidanEventGroup
{
- {11463, "Akama... your duplicity is hardly surprising. I should have slaughtered you and your malformed brethren long ago.", ILLIDAN_STORMRAGE, 8000, 0, true},
- {0, "", ILLIDAN_STORMRAGE, 5000, 396, true},
- {11389, "We've come to end your reign, Illidan. My people and all of Outland shall be free!", AKAMA, 7000, 25, true},
- {0, "", AKAMA, 5000, 66, true},
- {11464, "Boldly said. But I remain unconvinced.", ILLIDAN_STORMRAGE, 8000, 396, true},
- {11380, "The time has come! The moment is at hand!", AKAMA, 3000, 22, true},
- {0, "", AKAMA, 2000, 15, true},
- {11466, "You are not prepared!", ILLIDAN_STORMRAGE, 3000, 406, true},
- {0, "", EMPTY, 1000, 0, true},
- {0, "", EMPTY, 0, 0, false}, // 9
- {11476, "Is this it, mortals? Is this all the fury you can muster?", ILLIDAN_STORMRAGE, 8000, 0, true},
- {11491, "Their fury pales before mine, Illidan. We have some unsettled business between us.", MAIEV_SHADOWSONG, 8000, 5, true},
- {11477, "Maiev... How is this even possible?", ILLIDAN_STORMRAGE, 5000, 1, true},
- {11492, "Ah... my long hunt is finally over. Today, Justice will be done!", MAIEV_SHADOWSONG, 8000, 15, true},
- {11470, "Feel the hatred of ten thousand years!", ILLIDAN_STORMRAGE, 1000, 0, false}, // 14
- {11496, "Ahh... It is finished. You are beaten.", MAIEV_SHADOWSONG, 6000, 0, true}, // 15
-
- {11478, "You have won... Maiev...but the huntress... is nothing...without the hunt... you... are nothing... without me..", ILLIDAN_STORMRAGE, 30000, 65, true}, // Emote dead for now. Kill him later
- {11497, "He is right. I feel nothing... I am nothing... Farewell, champions.", MAIEV_SHADOWSONG, 9000, 0, true},
- {11498, "", MAIEV_SHADOWSONG, 5000, 0, true},
- {11498, "", EMPTY, 1000, 0, true}, // 19 Maiev disappear
- {11387, "The Light will fill these dismal halls once again. I swear it.", AKAMA, 8000, 0, true},
- {0, "", EMPTY, 1000, 0, false} // 21
+ GROUP_PHASE_ALL = 0,
+ GROUP_PHASE_1,
+ GROUP_PHASE_2,
+ GROUP_PHASE_3,
+ GROUP_PHASE_DEMON,
+ GROUP_PHASE_4
};
-G3D::Vector3 const HoverPosition[4]=
+enum IllidanEvents
{
- {657.0f, 340.0f, 355.0f},
- {657.0f, 275.0f, 355.0f},
- {705.0f, 275.0f, 355.0f},
- {705.0f, 340.0f, 355.0f}
+ // Akama
+ EVENT_TELEPORT = 1,
+ EVENT_MOVE_TO_ILLIDARI_ROOM,
+ EVENT_AKAMA_SAY_DOOR,
+ EVENT_AKAMA_DOOR_FAIL,
+ EVENT_AKAMA_SAY_ALONE,
+ EVENT_SUMMON_SPIRITS,
+ EVENT_SPIRIT_SAY_1,
+ EVENT_SPIRIT_SAY_2,
+ EVENT_AKAMA_DOOR_SUCCESS,
+ EVENT_AKAMA_THANKS,
+ EVENT_SPIRIT_SALUTE,
+ EVENT_RUN_FROM_ILLIDAN_ROOM,
+ EVENT_START_ILLIDAN,
+ EVENT_FREE,
+ EVENT_TIME_HAS_COME,
+ EVENT_ROAR,
+ EVENT_CHANGE_ORIENTATION,
+ EVENT_HEALING_POTION,
+ EVENT_AKAMA_MINIONS,
+ EVENT_AKAMA_MINIONS_EMOTE,
+ EVENT_AKAMA_MINIONS_MOVE,
+ EVENT_AKAMA_MINIONS_MOVE_2,
+ EVENT_CHAIN_LIGHTNING,
+ EVENT_AKAMA_MOVE_BACK,
+ EVENT_AKAMA_MOVE_TO_ILLIDAN,
+ EVENT_AKAMA_LIGHT_TEXT,
+ EVENT_FINAL_SALUTE,
+ EVENT_AKAMA_DESPAWN,
+
+ // Illidan Stormrage
+ EVENT_START_INTRO,
+ EVENT_UNCONVINCED,
+ EVENT_PREPARED,
+ EVENT_ENCOUNTER_START,
+ EVENT_EVADE_CHECK,
+ EVENT_FLAME_CRASH,
+ EVENT_DRAW_SOUL,
+ EVENT_SHEAR,
+ EVENT_BERSERK,
+ EVENT_PARASITIC_SHADOWFIEND,
+ EVENT_MINIONS_WEAVE,
+ EVENT_MOVE_TO_WARGLAIVE_POINT,
+ EVENT_FACE_MIDDLE,
+ EVENT_FLY,
+ EVENT_THROW_WARGLAIVE,
+ EVENT_THROW_WARGLAIVE_2,
+ EVENT_FLY_TO_RANDOM_PILLAR,
+ EVENT_FIREBALL,
+ EVENT_EYE_BLAST,
+ EVENT_DARK_BARRAGE,
+ EVENT_GLAIVE_EMOTE,
+ EVENT_RESUME_COMBAT,
+ EVENT_AGONIZING_FLAMES,
+ EVENT_DEMON,
+ EVENT_DEMON_TEXT,
+ EVENT_CANCEL_DEMON_FORM,
+ EVENT_RESUME_COMBAT_DEMON,
+ EVENT_FLAME_BURST,
+ EVENT_SHADOW_DEMON,
+ EVENT_SCHEDULE_DEMON_SPELLS,
+ EVENT_SHADOW_BLAST,
+ EVENT_PHASE_4_DELAYED,
+ EVENT_SHADOW_PRISON_TEXT,
+ EVENT_SUMMON_MAIEV,
+ EVENT_CONFRONT_MAIEV_TEXT,
+ EVENT_RESUME_COMBAT_PHASE_4,
+ EVENT_FRENZY,
+ EVENT_TAUNT,
+ EVENT_DEFEATED_TEXT,
+ EVENT_QUIET_SUICIDE,
+
+ // Flame of Azzinoth
+ EVENT_ENGAGE,
+ EVENT_FLAME_CHARGE,
+ EVENT_FLAME_BLAST,
+
+ // Maiev
+ EVENT_MAIEV_APPEAR,
+ EVENT_MAIEV_JUSTICE_TEXT,
+ EVENT_MAIEV_EXCLAMATION,
+ EVENT_MAIEV_YES,
+ EVENT_MAIEV_ROAR,
+ EVENT_MAIEV_COMBAT,
+ EVENT_CAGE_TRAP,
+ EVENT_SHADOW_STRIKE,
+ EVENT_THROW_DAGGER,
+ EVENT_MAIEV_OUTRO_TEXT,
+ EVENT_MAIEV_FAREWELL_TEXT,
+ EVENT_MAIEV_TELEPORT_DESPAWN
};
-G3D::Vector3 const GlaivePosition[4]=
+Position const AkamaTeleportPositions[2] =
{
- {695.105f, 305.303f, 354.256f},
- {659.338f, 305.303f, 354.256f}, // the distance between two glaives is 36
- {700.105f, 305.303f, 354.256f},
- {664.338f, 305.303f, 354.256f}
+ { 609.7720f, 308.4560f, 271.826f }, // Illidari Council Position
+ { 752.2771f, 369.9401f, 353.1584f } // Minions Position
};
-G3D::Vector3 const EyeBlast[2]=
+Position const MinionsSpawnPositions[10] =
{
- {677.0f, 350.0f, 354.0f}, // start point, pass through glaive point
- {677.0f, 260.0f, 354.0f}
+ { 745.2552f, 322.1574f, 310.4596f, 6.038839f },
+ { 747.0576f, 326.4268f, 309.0688f, 0.0f },
+ { 743.9686f, 289.6447f, 311.1807f, 6.056293f },
+ { 748.8422f, 288.0620f, 310.9782f, 1.884956f },
+ { 751.0878f, 327.6505f, 309.4576f, 6.178465f },
+ { 750.0472f, 282.3274f, 309.4353f, 3.071779f },
+ { 754.0332f, 325.8136f, 310.3195f, 2.9147f },
+ { 753.8425f, 286.562f, 310.9353f, 1.029744f },
+ { 745.3237f, 283.986f, 309.2765f, 0.6283185f },
+ { 750.0322f, 323.6064f, 310.2757f, 5.497787f }
};
-G3D::Vector3 const AkamaWP[13]=
+Position const IllidanPhase2Positions[4] =
{
- {770.01f, 304.50f, 312.29f}, // Bottom of the first stairs, at the doors
- {780.66f, 304.50f, 319.74f}, // Top of the first stairs
- {790.13f, 319.68f, 319.76f}, // Bottom of the second stairs (left from the entrance)
- {787.17f, 347.38f, 341.42f}, // Top of the second stairs
- {781.34f, 350.31f, 341.44f}, // Bottom of the third stairs
- {762.60f, 361.06f, 353.60f}, // Top of the third stairs
- {756.35f, 360.52f, 353.27f}, // Before the door-thingy
- {743.82f, 342.21f, 353.00f}, // Somewhere further
- {732.69f, 305.13f, 353.00f}, // In front of Illidan - (8)
- {738.11f, 365.44f, 353.00f}, // in front of the door-thingy (the other one!)
- {792.18f, 366.62f, 341.42f}, // Down the first flight of stairs
- {796.84f, 304.89f, 319.76f}, // Down the second flight of stairs
- {782.01f, 304.55f, 319.76f} // Final location - back at the initial gates. This is where he will fight the minions! (12)
+ { 705.921997f, 337.145996f, 370.083008f, 3.961900f },
+ { 706.226990f, 273.264008f, 370.083008f, 2.251072f },
+ { 658.830017f, 265.098999f, 370.083008f, 0.850345f },
+ { 656.859009f, 344.071991f, 370.083008f, 5.235990f }
};
-// 755.762f, 304.0747f, 312.1769f -- This is where Akama should be spawned
-G3D::Vector3 const SpiritSpawns[2]=
+
+Position const IllidanMiddlePoint = { 676.6479f, 304.7606f, 354.1909f , 6.230825f };
+
+Position const IllidanDBTargetSpawnPositions[4] =
{
- {755.5426f, 309.9156f, 312.2129f},
- {755.5426f, 298.7923f, 312.0834f}
+ { 710.8815f, 306.4028f, 353.5962f, 2.391101f },
+ { 652.105f, 259.5127f, 353.0794f, 0.122173f },
+ { 642.7164f, 305.2436f, 353.5596f, 3.438299f },
+ { 710.8815f, 306.4028f, 353.5962f, 2.391101f }
};
-struct Animation // For the demon transformation
+Position const IllidanDBTargetPoints[4] =
{
- uint32 aura, unaura, timer, size, displayid, phase;
- bool equip;
+ { 660.3492f, 345.5749f, 353.2961f },
+ { 701.6755f, 297.3358f, 354.041f },
+ { 706.7507f, 269.4593f, 353.2778f },
+ { 660.3492f, 345.5749f, 353.2961f }
};
-static const Animation DemonTransformation[10]=
+uint32 const SummonCageTrapSpells[8] =
{
- {SPELL_DEMON_TRANSFORM_1, 0, 1000, 0, 0, 6, true},
- {SPELL_DEMON_TRANSFORM_2, SPELL_DEMON_TRANSFORM_1, 4000, 0, 0, 6, true},
- {0, 0, 3000, 1073741824, 21322, 6, false}, // stunned, cannot cast demon form
- {SPELL_DEMON_TRANSFORM_3, SPELL_DEMON_TRANSFORM_2, 3500, 0, 0, 6, false},
- {SPELL_DEMON_FORM, SPELL_DEMON_TRANSFORM_3, 0, 0, 0, 4, false},
- {SPELL_DEMON_TRANSFORM_1, 0, 1000, 0, 0, 6, false},
- {SPELL_DEMON_TRANSFORM_2, SPELL_DEMON_TRANSFORM_1, 4000, 0, 0, 6, false},
- {0, SPELL_DEMON_FORM, 3000, 1069547520, 21135, 6, false},
- {SPELL_DEMON_TRANSFORM_3, SPELL_DEMON_TRANSFORM_2, 3500, 0, 0, 6, true},
- {0, SPELL_DEMON_TRANSFORM_3, 0, 0, 0, 8, true}
+ SPELL_SUMMON_CAGE_TRAP_1,
+ SPELL_SUMMON_CAGE_TRAP_2,
+ SPELL_SUMMON_CAGE_TRAP_3,
+ SPELL_SUMMON_CAGE_TRAP_4,
+ SPELL_SUMMON_CAGE_TRAP_5,
+ SPELL_SUMMON_CAGE_TRAP_6,
+ SPELL_SUMMON_CAGE_TRAP_7,
+ SPELL_SUMMON_CAGE_TRAP_8
};
-class npc_flame_of_azzinoth : public CreatureScript
+class SummonWarglaiveEvent : public BasicEvent
{
public:
- npc_flame_of_azzinoth() : CreatureScript("npc_flame_of_azzinoth") { }
+ SummonWarglaiveEvent(Unit* owner) : BasicEvent(), _owner(owner) { }
- struct flame_of_azzinothAI : public ScriptedAI
+ bool Execute(uint64 /*eventTime*/, uint32 /*diff*/) override
{
- flame_of_azzinothAI(Creature* creature) : ScriptedAI(creature)
- {
- Initialize();
- }
-
- void Initialize()
- {
- FlameBlastTimer = 15000;
- CheckTimer = 5000;
- GlaiveGUID.Clear();
- }
-
- void Reset() override
- {
- Initialize();
- }
-
- void EnterCombat(Unit* /*who*/) override
- {
- DoZoneInCombat();
- }
-
- void ChargeCheck()
- {
- Unit* target = SelectTarget(SELECT_TARGET_FARTHEST, 0, 200, false);
- if (target && (!me->IsWithinCombatRange(target, FLAME_CHARGE_DISTANCE)))
- {
- me->AddThreat(target, 5000000.0f);
- AttackStart(target);
- DoCast(target, SPELL_CHARGE);
- Talk(EMOTE_AZZINOTH_GAZE);
- }
- }
-
- void EnrageCheck()
- {
- if (Creature* glaive = ObjectAccessor::GetCreature(*me, GlaiveGUID))
- {
- if (!me->IsWithinDistInMap(glaive, FLAME_ENRAGE_DISTANCE))
- {
- glaive->InterruptNonMeleeSpells(true);
- DoCast(me, SPELL_FLAME_ENRAGE, true);
- DoResetThreat();
- if (SelectTarget(SELECT_TARGET_RANDOM, 0))
- {
- me->AddThreat(me->GetVictim(), 5000000.0f);
- AttackStart(me->GetVictim());
- }
- }
- else if (!me->HasAura(SPELL_AZZINOTH_CHANNEL))
- {
- glaive->CastSpell(me, SPELL_AZZINOTH_CHANNEL, false);
- me->RemoveAurasDueToSpell(SPELL_FLAME_ENRAGE);
- }
- }
- }
-
- void SetGlaiveGUID(ObjectGuid guid)
- {
- GlaiveGUID = guid;
- }
-
- void UpdateAI(uint32 diff) override
- {
- if (!UpdateVictim())
- return;
-
- if (FlameBlastTimer <= diff)
- {
- DoCastVictim(SPELL_BLAZE_SUMMON, true); // appear at victim
- DoCastVictim(SPELL_FLAME_BLAST);
- FlameBlastTimer = 15000; // 10000 is official-like?
- DoZoneInCombat(); // in case someone is revived
- } else FlameBlastTimer -= diff;
-
- if (CheckTimer <= diff)
- {
- ChargeCheck();
- EnrageCheck();
- CheckTimer = 1000;
- } else CheckTimer -= diff;
+ _owner->CastSpell(_owner, SPELL_RANGE_MARKER, true);
+ _owner->CastSpell(_owner, SPELL_SUMMON_GLAIVE, true);
+ return true;
+ }
- DoMeleeAttackIfReady();
- }
+private:
+ Unit* _owner;
+};
- private:
- uint32 FlameBlastTimer;
- uint32 CheckTimer;
- ObjectGuid GlaiveGUID;
- };
+class ChargeTargetSelector : public std::unary_function<Unit*, bool>
+{
+public:
+ ChargeTargetSelector(Unit const* unit) : _me(unit) { }
- CreatureAI* GetAI(Creature* creature) const override
+ bool operator()(Unit* unit) const
{
- return new flame_of_azzinothAI(creature);
+ return _me->GetDistance2d(unit) > 25.0f;
}
+
+private:
+ Unit const* _me;
};
-/************************************** Illidan's AI* **************************************/
class boss_illidan_stormrage : public CreatureScript
{
public:
@@ -475,1755 +442,2111 @@ public:
struct boss_illidan_stormrageAI : public BossAI
{
- boss_illidan_stormrageAI(Creature* creature) : BossAI(creature, DATA_ILLIDAN_STORMRAGE)
+ boss_illidan_stormrageAI(Creature* creature) : BossAI(creature, DATA_ILLIDAN_STORMRAGE),
+ _intro(true), _minionsCount(0), _flameCount(0), _orientation(0.0f), _pillarIndex(0), _phase(0), _dead(false), _isDemon(false) { }
+
+ void Reset() override
{
- Initialize();
- DoCast(me, SPELL_DUAL_WIELD, true);
+ _Reset();
+ specialEvents.Reset();
+ me->SummonCreatureGroup(SUMMON_GROUP);
+ me->LoadEquipment(1, true);
+ me->SetSheath(SHEATH_STATE_UNARMED);
+ me->SetControlled(false, UNIT_STATE_ROOT);
+ me->SetDisableGravity(false);
+ _dead = false;
+ _minionsCount = 0;
+ _flameCount = 0;
+ _phase = PHASE_1;
+ _isDemon = false;
+ if (_intro && instance->GetBossState(DATA_ILLIDARI_COUNCIL) == DONE)
+ if (Creature* akama = instance->GetCreature(DATA_AKAMA))
+ akama->AI()->DoAction(ACTION_ACTIVE_AKAMA_INTRO);
}
- void Initialize()
+ void EnterCombat(Unit* /*who*/) override
{
- MaievGUID.Clear();
- for (uint8 i = 0; i < 2; ++i)
- {
- FlameGUID[i].Clear();
- GlaiveGUID[i].Clear();
- }
-
- Phase = PHASE_ILLIDAN_NULL;
- Event = EVENT_NULL;
- Timer[EVENT_BERSERK] = 1500000;
-
- HoverPoint = 0;
- TalkCount = 0;
- FlightCount = 0;
- TransformCount = 0;
+ _EnterCombat();
+ me->SetCanDualWield(true);
+ specialEvents.ScheduleEvent(EVENT_EVADE_CHECK, Seconds(10));
+ specialEvents.ScheduleEvent(EVENT_BERSERK, Minutes(25));
+ ScheduleEvents(GROUP_PHASE_1, GROUP_PHASE_1);
+ events.ScheduleEvent(EVENT_TAUNT, Seconds(30), Seconds(60), GROUP_PHASE_ALL);
}
- void Reset() override;
+ void ChangeOrientation(float orientation)
+ {
+ _orientation = orientation;
+ events.ScheduleEvent(EVENT_CHANGE_ORIENTATION, Milliseconds(1), GROUP_PHASE_ALL);
+ }
- void JustSummoned(Creature* summon) override;
+ void KilledUnit(Unit* victim) override
+ {
+ if (victim->GetTypeId() == TYPEID_PLAYER)
+ Talk(SAY_ILLIDAN_KILL);
+ }
- void SummonedCreatureDespawn(Creature* summon) override
+ void ScheduleEvents(uint8 phase, uint8 group)
{
- if (summon->GetCreatureTemplate()->Entry == FLAME_OF_AZZINOTH)
+ switch (phase)
{
- for (uint8 i = 0; i < 2; ++i)
- if (summon->GetGUID() == FlameGUID[i])
- FlameGUID[i].Clear();
-
- if (!FlameGUID[0] && !FlameGUID[1] && Phase != PHASE_ILLIDAN_NULL)
- {
- me->InterruptNonMeleeSpells(true);
- EnterPhase(PHASE_FLIGHT_SEQUENCE);
- }
+ case GROUP_PHASE_1:
+ events.ScheduleEvent(EVENT_FLAME_CRASH, Seconds(30), group);
+ events.ScheduleEvent(EVENT_DRAW_SOUL, Seconds(34), group);
+ events.ScheduleEvent(EVENT_SHEAR, Seconds(10), group);
+ events.ScheduleEvent(EVENT_PARASITIC_SHADOWFIEND, Seconds(26), group);
+ break;
+ case GROUP_PHASE_2:
+ events.ScheduleEvent(EVENT_FIREBALL, Seconds(1), Seconds(8), group);
+ events.ScheduleEvent(EVENT_EYE_BLAST, Seconds(1), Seconds(30), group);
+ if (roll_chance_i(50))
+ events.ScheduleEvent(EVENT_DARK_BARRAGE, Seconds(1), Seconds(20), group);
+ break;
+ case GROUP_PHASE_3:
+ ScheduleEvents(GROUP_PHASE_1, group);
+ events.ScheduleEvent(EVENT_AGONIZING_FLAMES, Seconds(21), group);
+ events.ScheduleEvent(EVENT_DEMON, Seconds(60), group);
+ break;
+ case GROUP_PHASE_DEMON:
+ events.ScheduleEvent(EVENT_SHADOW_BLAST, Seconds(1), group);
+ events.ScheduleEvent(EVENT_FLAME_BURST, Seconds(6), group);
+ events.ScheduleEvent(EVENT_SHADOW_DEMON, Seconds(18), Seconds(30), group);
+ case GROUP_PHASE_4:
+ ScheduleEvents(GROUP_PHASE_3, group);
+ events.ScheduleEvent(EVENT_FRENZY, Seconds(40), group);
+ break;
+ default:
+ break;
}
- summons.Despawn(summon);
}
- void MovementInform(uint32 /*MovementType*/, uint32 /*Data*/) override
+ void JustSummoned(Creature* summon) override
{
- if (FlightCount == 7) // change hover point
- {
- if (me->GetVictim())
+ BossAI::JustSummoned(summon);
+ if (summon->GetEntry() == NPC_ILLIDARI_ELITE)
+ if (Creature* akama = instance->GetCreature(DATA_AKAMA))
{
- me->SetInFront(me->GetVictim());
- me->StopMoving();
+ summon->CombatStart(akama);
+ summon->AddThreat(akama, 1000.0f);
}
- EnterPhase(PHASE_FLIGHT);
- }
- else // handle flight sequence
- Timer[EVENT_FLIGHT_SEQUENCE] = 1000;
}
- void EnterCombat(Unit* /*who*/) override
+ void SummonedCreatureDies(Creature* summon, Unit* /*killer*/) override
{
- me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC);
- _EnterCombat();
+ if (summon->GetEntry() == NPC_ILLIDARI_ELITE)
+ _minionsCount--;
}
- void AttackStart(Unit* who) override
+ void EnterEvadeMode(EvadeReason /*why*/) override
{
- if (!who || Phase >= PHASE_TALK_SEQUENCE)
- return;
-
- if (Phase == PHASE_FLIGHT || Phase == PHASE_DEMON)
- AttackStartNoMove(who);
- else
- ScriptedAI::AttackStart(who);
+ summons.DespawnAll();
+ specialEvents.Reset();
+ _DespawnAtEvade();
}
- void MoveInLineOfSight(Unit*) override { }
-
+ void DoAction(int32 actionId) override
+ {
+ switch (actionId)
+ {
+ case ACTION_START_ENCOUNTER:
+ events.SetPhase(PHASE_INTRO);
+ me->RemoveAurasDueToSpell(SPELL_KNEEL);
+ events.ScheduleEvent(EVENT_START_INTRO, Seconds(2), GROUP_PHASE_ALL);
+ events.ScheduleEvent(EVENT_UNCONVINCED, Seconds(24), GROUP_PHASE_ALL);
+ if (Creature* akama = instance->GetCreature(DATA_AKAMA))
+ akama->AI()->DoAction(ACTION_FREE);
+ break;
+ case ACTION_INTRO_DONE:
+ _intro = false;
+ break;
+ case ACTION_START_MINIONS:
+ Talk(SAY_ILLIDAN_MINION);
+ if (Creature* akama = instance->GetCreature(DATA_AKAMA))
+ akama->AI()->DoAction(ACTION_START_MINIONS);
+ break;
+ case ACTION_START_MINIONS_WEAVE:
+ events.ScheduleEvent(EVENT_MINIONS_WEAVE, Milliseconds(1), GROUP_PHASE_ALL);
+ break;
+ case ACTION_START_PHASE_2:
+ {
+ me->SetReactState(REACT_PASSIVE);
+ me->AttackStop();
+ me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
+ me->HandleEmoteCommand(EMOTE_ONESHOT_LIFTOFF);
+ me->SetDisableGravity(true);
+ DoPlaySoundToSet(me, ILLIDAN_TAKEOFF_SOUND_ID);
+ events.ScheduleEvent(EVENT_FLY, Seconds(1), GROUP_PHASE_ALL);
+ events.CancelEventGroup(GROUP_PHASE_1);
+ break;
+ }
+ case ACTION_FLAME_DEAD:
+ _flameCount++;
+ if (_flameCount == 2)
+ {
+ _flameCount = 0;
+ DoAction(ACTION_FINALIZE_AIR_PHASE);
+ }
+ break;
+ case ACTION_FINALIZE_AIR_PHASE:
+ me->InterruptNonMeleeSpells(false);
+ me->GetMotionMaster()->Clear();
+ events.CancelEventGroup(GROUP_PHASE_2);
+ _phase = PHASE_3;
+ events.CancelEvent(EVENT_FLY_TO_RANDOM_PILLAR);
+ me->GetMotionMaster()->MovePoint(POINT_ILLIDAN_MIDDLE, IllidanMiddlePoint);
+ break;
+ case ACTION_START_PHASE_4:
+ events.CancelEventGroup(GROUP_PHASE_3);
+ DoCastSelf(SPELL_SHADOW_PRISON, true);
+ me->SetReactState(REACT_PASSIVE);
+ me->AttackStop();
+ me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
+ events.ScheduleEvent(EVENT_SHADOW_PRISON_TEXT, Milliseconds(500), GROUP_PHASE_ALL);
+ break;
+ case ACTION_ILLIDAN_CAGED:
+ for (uint32 summonSpell : SummonCageTrapSpells)
+ DoCastSelf(summonSpell, true);
+ DoCastSelf(SPELL_CAGE_TRAP, true);
+ break;
+ case ACTION_START_OUTRO:
+ me->AttackStop();
+ events.Reset();
+ specialEvents.Reset();
+ DoCastSelf(SPELL_DEATH, true);
+ me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
+ events.ScheduleEvent(EVENT_DEFEATED_TEXT, Seconds(4));
+ break;
+ default:
+ break;
+ }
+ }
void JustDied(Unit* /*killer*/) override
{
me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
-
- _JustDied();
+ instance->SetBossState(DATA_ILLIDAN_STORMRAGE, DONE);
+ events.Reset();
}
- void KilledUnit(Unit* victim) override
+ void MovementInform(uint32 type, uint32 pointId) override
{
- if (victim->GetTypeId() != TYPEID_PLAYER)
+ if (type != POINT_MOTION_TYPE && type != EFFECT_MOTION_TYPE)
return;
- Talk(SAY_ILLIDAN_KILL);
- }
-
- void DamageTaken(Unit* done_by, uint32 &damage) override
- {
- if (damage >= me->GetHealth() && done_by != me)
- damage = 0;
- if (done_by->GetGUID() == MaievGUID)
- done_by->AddThreat(me, -(3*(float)damage)/4); // do not let maiev tank him
- }
-
- void SpellHit(Unit* /*caster*/, const SpellInfo* spell) override
- {
- if (spell->Id == SPELL_GLAIVE_RETURNS) // Re-equip our warglaives!
+ switch (pointId)
{
- if (!me->GetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID))
- SetEquipmentSlots(false, EQUIP_ID_MAIN_HAND, EQUIP_UNEQUIP, EQUIP_NO_CHANGE);
- else
- SetEquipmentSlots(false, EQUIP_UNEQUIP, EQUIP_ID_OFF_HAND, EQUIP_NO_CHANGE);
- me->SetSheath(SHEATH_STATE_MELEE);
- }
- }
-
- void DeleteFromThreatList(ObjectGuid TargetGUID)
- {
- ThreatContainer::StorageType threatlist = me->getThreatManager().getThreatList();
- for (ThreatContainer::StorageType::const_iterator itr = threatlist.begin(); itr != threatlist.end(); ++itr)
- {
- if ((*itr)->getUnitGuid() == TargetGUID)
+ case POINT_THROW_GLAIVE:
+ DoPlaySoundToSet(me, ILLIDAN_WARGLAIVE_SOUND_ID);
+ events.ScheduleEvent(EVENT_THROW_WARGLAIVE, Seconds(2), GROUP_PHASE_ALL);
+ events.ScheduleEvent(EVENT_FACE_MIDDLE, Milliseconds(1), GROUP_PHASE_ALL);
+ break;
+ case POINT_RANDOM_PILLAR:
{
- (*itr)->removeReference();
+ float orientation = IllidanPhase2Positions[_pillarIndex].GetOrientation();
+ ChangeOrientation(orientation);
+ ScheduleEvents(GROUP_PHASE_2, GROUP_PHASE_2);
break;
}
+ case POINT_ILLIDAN_MIDDLE:
+ {
+ float orientation = IllidanMiddlePoint.GetOrientation();
+ ChangeOrientation(orientation);
+
+ std::list<Creature*> triggers;
+ GetCreatureListWithEntryInGrid(triggers, me, NPC_BLADE_OF_AZZINOTH, 150.0f);
+ for (Creature* trigger : triggers)
+ trigger->CastSpell(trigger, SPELL_GLAIVE_RETURNS, true);
+
+ events.ScheduleEvent(EVENT_GLAIVE_EMOTE, Seconds(3), GROUP_PHASE_ALL);
+ break;
+ }
+ default:
+ break;
}
}
- void Talk(uint32 count)
+ void EnterEvadeModeIfNeeded()
{
- Timer[EVENT_TALK_SEQUENCE] = Conversation[count].timer;
+ Map::PlayerList const &players = me->GetMap()->GetPlayers();
+ for (Map::PlayerList::const_iterator i = players.begin(); i != players.end(); ++i)
+ if (Player* player = i->GetSource())
+ if (player->IsAlive() && !player->IsGameMaster() && CheckBoundary(player))
+ return;
- Creature* creature = NULL;
- if (Conversation[count].creature == ILLIDAN_STORMRAGE)
- creature = me;
- else if (Conversation[count].creature == AKAMA)
- creature = (ObjectAccessor::GetCreature((*me), AkamaGUID));
- else if (Conversation[count].creature == MAIEV_SHADOWSONG)
- creature = (ObjectAccessor::GetCreature((*me), MaievGUID));
+ EnterEvadeMode(EVADE_REASON_NO_HOSTILES);
+ }
- if (creature)
+ void SummonMinions()
+ {
+ uint8 needSummon = MAX_MINIONS_NUMBER - _minionsCount;
+ for (uint8 i = 0; i < needSummon; ++i)
{
- if (Conversation[count].emote)
- creature->HandleEmoteCommand(Conversation[count].emote); // Make the Creature do some animation!
- if (Conversation[count].text.size())
- creature->Yell(Conversation[count].text.c_str(), LANG_UNIVERSAL); // Have the Creature yell out some text
- if (Conversation[count].sound)
- DoPlaySoundToSet(creature, Conversation[count].sound); // Play some sound on the creature
+ _minionsCount++;
+ me->SummonCreature(NPC_ILLIDARI_ELITE, MinionsSpawnPositions[i], TEMPSUMMON_CORPSE_TIMED_DESPAWN, 6000);
}
}
- void EnterPhase(PhaseIllidan NextPhase)
+ void DamageTaken(Unit* who, uint32 &damage) override
{
- DoZoneInCombat();
- switch (NextPhase)
+ if (damage >= me->GetHealth() && who->GetGUID() != me->GetGUID())
{
- case PHASE_NORMAL:
- case PHASE_NORMAL_2:
- case PHASE_NORMAL_MAIEV:
- AttackStart(me->GetVictim());
- Timer[EVENT_TAUNT] = 32000;
- Timer[EVENT_SHEAR] = urand(10, 25) * 1000;
- Timer[EVENT_FLAME_CRASH] = 20000;
- Timer[EVENT_PARASITIC_SHADOWFIEND] = 25000;
- Timer[EVENT_PARASITE_CHECK] = 0;
- Timer[EVENT_DRAW_SOUL] = 30000;
- if (NextPhase == PHASE_NORMAL)
- break;
- Timer[EVENT_AGONIZING_FLAMES] = 35000;
- Timer[EVENT_TRANSFORM_NORMAL] = 60000;
- if (NextPhase == PHASE_NORMAL_2)
- break;
- Timer[EVENT_ENRAGE] = urand(30, 40) * 1000;
- break;
- case PHASE_FLIGHT:
- Timer[EVENT_FIREBALL] = 1000;
- if (!(rand32() % 4))
- Timer[EVENT_DARK_BARRAGE] = 10000;
- Timer[EVENT_EYE_BLAST] = urand(10, 25) * 1000;
- Timer[EVENT_MOVE_POINT] = urand(20, 40) * 1000;
- break;
- case PHASE_DEMON:
- Timer[EVENT_SHADOW_BLAST] = 1000;
- Timer[EVENT_FLAME_BURST] = 10000;
- Timer[EVENT_SHADOWDEMON] = 30000;
- Timer[EVENT_TRANSFORM_DEMON] = 60000;
- AttackStart(me->GetVictim());
- break;
- case PHASE_TALK_SEQUENCE:
- Timer[EVENT_TALK_SEQUENCE] = 100;
- me->RemoveAllAuras();
- me->InterruptNonMeleeSpells(false);
- me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE);
- me->GetMotionMaster()->Clear(false);
- me->AttackStop();
- break;
- case PHASE_FLIGHT_SEQUENCE:
- if (Phase == PHASE_NORMAL) // lift off
- {
- FlightCount = 1;
- Timer[EVENT_FLIGHT_SEQUENCE] = 1;
- me->RemoveAllAuras();
- me->InterruptNonMeleeSpells(false);
- me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
- me->GetMotionMaster()->Clear(false);
- me->AttackStop();
- }
- else // land
- Timer[EVENT_FLIGHT_SEQUENCE] = 2000;
- break;
- case PHASE_TRANSFORM_SEQUENCE:
- if (Phase == PHASE_DEMON)
- Timer[EVENT_TRANSFORM_SEQUENCE] = 500;
- else
+ damage = me->GetHealth() - 1;
+ if (!_dead)
{
- TransformCount = 0;
- Timer[EVENT_TRANSFORM_SEQUENCE] = 500;
- Talk(SAY_ILLIDAN_MORPH);
+ if (_isDemon)
+ {
+ events.Reset();
+ specialEvents.Reset();
+ DoCastSelf(SPELL_DEMON_TRANSFORM_1);
+ return;
+ }
+ _dead = true;
+ DoAction(ACTION_START_OUTRO);
+ if (Creature* maiev = instance->GetCreature(DATA_MAIEV))
+ maiev->AI()->DoAction(ACTION_START_OUTRO);
}
- me->GetMotionMaster()->Clear();
- me->AttackStop();
- break;
- default:
- break;
}
- if (MaievGUID)
+ else if (me->HealthBelowPct(90) && _phase < PHASE_MINIONS)
{
- if (Creature* maiev = ObjectAccessor::GetCreature(*me, MaievGUID))
- if (maiev->IsAlive())
- maiev->AI()->DoAction(NextPhase);
+ _phase = PHASE_MINIONS;
+ DoAction(ACTION_START_MINIONS);
}
- Phase = NextPhase;
- Event = EVENT_NULL;
- }
-
- void CastEyeBlast()
- {
- me->InterruptNonMeleeSpells(false);
-
- Talk(SAY_ILLIDAN_EYE_BLAST);
-
- float distx, disty, dist[2];
- for (uint8 i = 0; i < 2; ++i)
+ else if (me->HealthBelowPct(65) && _phase < PHASE_2)
{
- distx = EyeBlast[i].x - HoverPosition[HoverPoint].x;
- disty = EyeBlast[i].y - HoverPosition[HoverPoint].y;
- dist[i] = distx * distx + disty * disty;
+ _phase = PHASE_2;
+ DoAction(ACTION_START_PHASE_2);
}
- G3D::Vector3 initial = EyeBlast[dist[0] < dist[1] ? 0 : 1];
- for (uint8 i = 0; i < 2; ++i)
+ else if (me->HealthBelowPct(30) && _phase < PHASE_4)
{
- distx = GlaivePosition[i].x - HoverPosition[HoverPoint].x;
- disty = GlaivePosition[i].y - HoverPosition[HoverPoint].y;
- dist[i] = distx * distx + disty * disty;
- }
- G3D::Vector3 final = GlaivePosition[dist[0] < dist[1] ? 0 : 1];
-
- final.x = 2 * final.x - initial.x;
- final.y = 2 * final.y - initial.y;
-
- Creature* Trigger = me->SummonCreature(23069, initial.x, initial.y, initial.z, 0, TEMPSUMMON_TIMED_DESPAWN, 13000);
- if (!Trigger)
- return;
-
- Trigger->SetSpeedRate(MOVE_WALK, 3);
- Trigger->SetWalk(true);
- Trigger->GetMotionMaster()->MovePoint(0, final.x, final.y, final.z);
+ _phase = PHASE_4;
- // Trigger->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
- me->SetTarget(Trigger->GetGUID());
- DoCast(Trigger, SPELL_EYE_BLAST);
+ if (_isDemon)
+ {
+ _isDemon = false;
+ me->SetControlled(false, UNIT_STATE_ROOT);
+ events.CancelEventGroup(GROUP_PHASE_DEMON);
+ me->InterruptNonMeleeSpells(false);
+ DoCastSelf(SPELL_DEMON_TRANSFORM_1, true);
+ events.ScheduleEvent(EVENT_PHASE_4_DELAYED, Seconds(12), GROUP_PHASE_ALL);
+ }
+ else
+ DoAction(ACTION_START_PHASE_4);
+ }
}
- void SummonFlamesOfAzzinoth()
+ void ExecuteSpecialEvents()
{
- Talk(SAY_ILLIDAN_SUMMONFLAMES);
-
- for (uint8 i = 0; i < 2; ++i)
+ while (uint32 eventId = specialEvents.ExecuteEvent())
{
- if (Creature* glaive = ObjectAccessor::GetCreature(*me, GlaiveGUID[i]))
+ switch (eventId)
{
- if (Creature* flame = me->SummonCreature(FLAME_OF_AZZINOTH, GlaivePosition[i+2].x, GlaivePosition[i+2].y, GlaivePosition[i+2].z, 0, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 5000))
- {
- flame->setFaction(me->getFaction()); // Just in case the database has it as a different faction
- flame->SetMeleeDamageSchool(SPELL_SCHOOL_FIRE);
- FlameGUID[i] = flame->GetGUID(); // Record GUID in order to check if they're dead later on to move to the next phase
- ENSURE_AI(npc_flame_of_azzinoth::flame_of_azzinothAI, flame->AI())->SetGlaiveGUID(GlaiveGUID[i]);
- glaive->CastSpell(flame, SPELL_AZZINOTH_CHANNEL, false); // Glaives do some random Beam type channel on it.
- }
+ case EVENT_BERSERK:
+ Talk(SAY_ILLIDAN_ENRAGE);
+ DoCastSelf(SPELL_BERSERK, true);
+ break;
+ case EVENT_CANCEL_DEMON_FORM:
+ me->InterruptNonMeleeSpells(false);
+ me->SetControlled(false, UNIT_STATE_ROOT);
+ events.CancelEventGroup(GROUP_PHASE_DEMON);
+ DoCastSelf(SPELL_DEMON_TRANSFORM_1, true);
+ events.ScheduleEvent(EVENT_RESUME_COMBAT_DEMON, Seconds(12), GROUP_PHASE_ALL);
+ _isDemon = false;
+ break;
+ case EVENT_EVADE_CHECK:
+ EnterEvadeModeIfNeeded();
+ specialEvents.Repeat(Seconds(10));
+ break;
+ default:
+ break;
}
}
}
- void SummonMaiev()
+ void UpdateAI(uint32 diff) override
{
- DoCast(me, SPELL_SHADOW_PRISON, true);
- DoCast(me, SPELL_SUMMON_MAIEV, true);
- if (!MaievGUID) // If Maiev cannot be summoned, reset the encounter and post some errors to the console.
- {
- EnterEvadeMode();
- TC_LOG_ERROR("scripts", "SD2 ERROR: Unable to summon Maiev Shadowsong (entry: 23197). Check your database to see if you have the proper SQL for Maiev Shadowsong (entry: 23197)");
- }
- }
+ if (!UpdateVictim() && !events.IsInPhase(PHASE_INTRO))
+ return;
- void HandleTalkSequence();
+ specialEvents.Update(diff);
- void HandleFlightSequence()
- {
- switch (FlightCount)
+ ExecuteSpecialEvents();
+
+ if (me->HasUnitState(UNIT_STATE_CASTING))
+ return;
+
+ events.Update(diff);
+
+ while (uint32 eventId = events.ExecuteEvent())
{
- case 1: // lift off
- me->HandleEmoteCommand(EMOTE_ONESHOT_LIFTOFF);
- me->SetDisableGravity(true);
- me->StopMoving();
- Talk(SAY_ILLIDAN_TAKEOFF);
- Timer[EVENT_FLIGHT_SEQUENCE] = 3000;
- break;
- case 2: // move to center
- me->GetMotionMaster()->MovePoint(0, CENTER_X + 5, CENTER_Y, CENTER_Z); // +5, for SPELL_THROW_GLAIVE bug
- Timer[EVENT_FLIGHT_SEQUENCE] = 0;
- break;
- case 3: // throw one glaive
+ switch (eventId)
+ {
+ case EVENT_START_INTRO:
+ Talk(SAY_ILLIDAN_DUPLICITY);
+ break;
+ case EVENT_UNCONVINCED:
+ Talk(SAY_ILLIDAN_UNCONVINCED);
+ events.ScheduleEvent(EVENT_PREPARED, Seconds(14), GROUP_PHASE_ALL);
+ break;
+ case EVENT_PREPARED:
+ Talk(SAY_ILLIDAN_PREPARED);
+ me->SetSheath(SHEATH_STATE_MELEE);
+ events.ScheduleEvent(EVENT_ENCOUNTER_START, Seconds(3), GROUP_PHASE_ALL);
+ break;
+ case EVENT_ENCOUNTER_START:
+ me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC | UNIT_FLAG_IMMUNE_TO_NPC);
+ DoZoneInCombat();
+ if (Creature* akama = instance->GetCreature(DATA_AKAMA))
+ akama->AI()->DoAction(ACTION_START_ENCOUNTER);
+ break;
+ case EVENT_FLAME_CRASH:
+ DoCastVictim(SPELL_FLAME_CRASH);
+ events.Repeat(Seconds(30));
+ break;
+ case EVENT_DRAW_SOUL:
+ DoCastAOE(SPELL_DRAW_SOUL);
+ events.Repeat(Seconds(34));
+ break;
+ case EVENT_SHEAR:
+ DoCastVictim(SPELL_SHEAR);
+ events.Repeat(Seconds(12));
+ break;
+ case EVENT_PARASITIC_SHADOWFIEND:
+ if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 1))
+ DoCast(target, SPELL_PARASITIC_SHADOWFIEND);
+ events.Repeat(Seconds(30));
+ break;
+ case EVENT_MINIONS_WEAVE:
+ SummonMinions();
+ events.Repeat(Seconds(30));
+ break;
+ case EVENT_MOVE_TO_WARGLAIVE_POINT:
{
- uint8 i=1;
- Creature* Glaive = me->SummonCreature(BLADE_OF_AZZINOTH, GlaivePosition[i].x, GlaivePosition[i].y, GlaivePosition[i].z, 0, TEMPSUMMON_CORPSE_DESPAWN, 0);
- if (Glaive)
+ Position pos;
+ std::list<Creature*> triggers;
+ GetCreatureListWithEntryInGrid(triggers, me, NPC_GLAIVE_WORLD_TRIGGER, 150.0f);
+ triggers.remove_if([](WorldObject* unit)
{
- GlaiveGUID[i] = Glaive->GetGUID();
- Glaive->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
- Glaive->SetDisplayId(MODEL_INVISIBLE);
- Glaive->setFaction(me->getFaction());
- DoCast(Glaive, SPELL_THROW_GLAIVE2);
- }
+ return unit->GetPositionZ() < 355.0f || unit->GetPositionZ() > 365.0f;
+ });
+
+ if (triggers.empty())
+ break;
+
+ triggers.sort(Trinity::ObjectDistanceOrderPred(me));
+ pos.Relocate(triggers.front());
+ pos.SetOrientation(0.0f);
+ me->GetMotionMaster()->MovePoint(POINT_THROW_GLAIVE, pos);
+ break;
}
- Timer[EVENT_FLIGHT_SEQUENCE] = 700;
- break;
- case 4: // throw another
- SetEquipmentSlots(false, EQUIP_UNEQUIP, EQUIP_UNEQUIP, EQUIP_NO_CHANGE);
+ case EVENT_THROW_WARGLAIVE:
+ DoCastAOE(SPELL_THROW_GLAIVE);
+ events.ScheduleEvent(EVENT_THROW_WARGLAIVE_2, Seconds(1), GROUP_PHASE_ALL);
+ break;
+ case EVENT_THROW_WARGLAIVE_2:
+ DoCastAOE(SPELL_THROW_GLAIVE2);
+ me->SetSheath(SHEATH_STATE_UNARMED);
+ events.ScheduleEvent(EVENT_FLY_TO_RANDOM_PILLAR, Seconds(2), GROUP_PHASE_ALL);
+ break;
+ case EVENT_CHANGE_ORIENTATION:
+ me->SetFacingTo(_orientation, true);
+ break;
+ case EVENT_FLY:
+ ChangeOrientation(3.137039f);
+ events.ScheduleEvent(EVENT_MOVE_TO_WARGLAIVE_POINT, Seconds(6), GROUP_PHASE_ALL);
+ break;
+ case EVENT_FLY_TO_RANDOM_PILLAR:
{
- uint8 i=0;
- Creature* Glaive = me->SummonCreature(BLADE_OF_AZZINOTH, GlaivePosition[i].x, GlaivePosition[i].y, GlaivePosition[i].z, 0, TEMPSUMMON_CORPSE_DESPAWN, 0);
- if (Glaive)
- {
- GlaiveGUID[i] = Glaive->GetGUID();
- Glaive->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
- Glaive->SetDisplayId(MODEL_INVISIBLE);
- Glaive->setFaction(me->getFaction());
- DoCast(Glaive, SPELL_THROW_GLAIVE, true);
- }
+ events.CancelEventGroup(GROUP_PHASE_2);
+ _pillarIndex = urand(0, 3);
+ me->GetMotionMaster()->MovePoint(POINT_RANDOM_PILLAR, IllidanPhase2Positions[_pillarIndex]);
+ events.Repeat(Seconds(30));
+ break;
}
- Timer[EVENT_FLIGHT_SEQUENCE] = 5000;
- break;
- case 5: // summon flames
- SummonFlamesOfAzzinoth();
- Timer[EVENT_FLIGHT_SEQUENCE] = 3000;
- break;
- case 6: // fly to hover point
- me->GetMotionMaster()->MovePoint(0, HoverPosition[HoverPoint].x, HoverPosition[HoverPoint].y, HoverPosition[HoverPoint].z);
- Timer[EVENT_FLIGHT_SEQUENCE] = 0;
- break;
- case 7: // return to center
- me->GetMotionMaster()->MovePoint(0, CENTER_X, CENTER_Y, CENTER_Z);
- Timer[EVENT_FLIGHT_SEQUENCE] = 0;
- break;
- case 8: // glaive return
- for (uint8 i = 0; i < 2; ++i)
+ case EVENT_FACE_MIDDLE:
+ {
+ float angle = me->GetAngle(IllidanMiddlePoint);
+ me->SetFacingTo(angle, true);
+ break;
+ }
+ case EVENT_EYE_BLAST:
{
- if (GlaiveGUID[i])
+ events.CancelEvent(EVENT_DARK_BARRAGE);
+ Position pos = IllidanDBTargetSpawnPositions[_pillarIndex];
+ if (TempSummon* dbTarget = me->SummonCreature(NPC_ILLIDAN_DB_TARGET, pos, TEMPSUMMON_MANUAL_DESPAWN))
{
- Unit* Glaive = ObjectAccessor::GetUnit(*me, GlaiveGUID[i]);
- if (Glaive)
- {
- Glaive->CastSpell(me, SPELL_GLAIVE_RETURNS, false); // Make it look like the Glaive flies back up to us
- Glaive->SetDisplayId(MODEL_INVISIBLE); // disappear but not die for now
- }
+ Talk(SAY_ILLIDAN_EYE_BLAST);
+ DoCast(dbTarget, SPELL_EYE_BLAST);
+ dbTarget->GetMotionMaster()->MovePoint(POINT_DB_TARGET, IllidanDBTargetPoints[_pillarIndex]);
}
+ break;
}
- Timer[EVENT_FLIGHT_SEQUENCE] = 2000;
- break;
- case 9: // land
- me->SetDisableGravity(false);
- me->StopMoving();
- me->HandleEmoteCommand(EMOTE_ONESHOT_LAND);
- for (uint8 i = 0; i < 2; ++i)
+ case EVENT_DARK_BARRAGE:
{
- if (GlaiveGUID[i])
+ if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 150.0f, true))
+ DoCast(target, SPELL_DARK_BARRAGE);
+ events.RescheduleEvent(EVENT_EYE_BLAST, Seconds(5), GROUP_PHASE_2);
+ uint32 currentTime = events.GetNextEventTime(EVENT_FLY_TO_RANDOM_PILLAR);
+ events.RescheduleEvent(EVENT_FLY_TO_RANDOM_PILLAR, Seconds(currentTime) + Seconds(30), GROUP_PHASE_2);
+ break;
+ }
+ case EVENT_FIREBALL:
+ if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 150.0f, true))
+ DoCast(target, SPELL_FIREBALL);
+ events.Repeat(Seconds(2), Seconds(4));
+ break;
+ case EVENT_GLAIVE_EMOTE:
+ me->SetDisableGravity(false);
+ me->HandleEmoteCommand(EMOTE_ONESHOT_LAND);
+ me->SetSheath(SHEATH_STATE_MELEE);
+ events.ScheduleEvent(EVENT_RESUME_COMBAT, Seconds(3), GROUP_PHASE_ALL);
+ break;
+ case EVENT_RESUME_COMBAT:
+ me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
+ me->SetReactState(REACT_AGGRESSIVE);
+ ScheduleEvents(GROUP_PHASE_3, GROUP_PHASE_3);
+ break;
+ case EVENT_AGONIZING_FLAMES:
+ DoCastSelf(SPELL_AGONIZING_FLAMES_SELECTOR);
+ events.Repeat(Seconds(53));
+ break;
+ case EVENT_DEMON:
+ me->SetControlled(true, UNIT_STATE_ROOT);
+ _isDemon = true;
+ events.CancelEventGroup(_phase == PHASE_3 ? GROUP_PHASE_3 : GROUP_PHASE_4);
+ me->LoadEquipment(0, true);
+ DoCastSelf(SPELL_DEMON_TRANSFORM_1, true);
+ events.ScheduleEvent(EVENT_DEMON_TEXT, Seconds(2), GROUP_PHASE_ALL);
+ specialEvents.ScheduleEvent(EVENT_CANCEL_DEMON_FORM, Minutes(1) + Seconds(12));
+ events.ScheduleEvent(EVENT_SCHEDULE_DEMON_SPELLS, Seconds(15));
+ break;
+ case EVENT_SCHEDULE_DEMON_SPELLS:
+ DoResetThreat();
+ ScheduleEvents(GROUP_PHASE_DEMON, GROUP_PHASE_DEMON);
+ break;
+ case EVENT_DEMON_TEXT:
+ Talk(SAY_ILLIDAN_MORPH);
+ break;
+ case EVENT_RESUME_COMBAT_DEMON:
+ {
+ uint8 group = _phase == PHASE_3 ? GROUP_PHASE_3 : GROUP_PHASE_4;
+ DoResetThreat();
+ ScheduleEvents(group, group);
+ me->LoadEquipment(1, true);
+ break;
+ }
+ case EVENT_FLAME_BURST:
+ DoCastSelf(SPELL_FLAME_BURST);
+ events.Repeat(Seconds(22));
+ break;
+ case EVENT_SHADOW_DEMON:
+ DoCastSelf(SPELL_SUMMON_SHADOWDEMON);
+ break;
+ case EVENT_SHADOW_BLAST:
+ DoCastVictim(SPELL_SHADOW_BLAST);
+ events.Repeat(Seconds(2));
+ break;
+ case EVENT_PHASE_4_DELAYED:
+ DoAction(ACTION_START_PHASE_4);
+ break;
+ case EVENT_SHADOW_PRISON_TEXT:
+ Talk(SAY_ILLIDAN_SHADOW_PRISON);
+ events.ScheduleEvent(EVENT_SUMMON_MAIEV, Seconds(9), GROUP_PHASE_ALL);
+ break;
+ case EVENT_SUMMON_MAIEV:
+ DoCastSelf(SPELL_SUMMON_MAIEV);
+ if (Creature* maiev = instance->GetCreature(DATA_MAIEV))
+ me->SetFacingToObject(maiev);
+ events.ScheduleEvent(EVENT_CONFRONT_MAIEV_TEXT, Seconds(9), GROUP_PHASE_ALL);
+ break;
+ case EVENT_CONFRONT_MAIEV_TEXT:
+ Talk(SAY_ILLIDAN_CONFRONT_MAIEV);
+ events.ScheduleEvent(EVENT_RESUME_COMBAT_PHASE_4, Seconds(13), GROUP_PHASE_ALL);
+ break;
+ case EVENT_RESUME_COMBAT_PHASE_4:
+ me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
+ me->SetReactState(REACT_AGGRESSIVE);
+ ScheduleEvents(GROUP_PHASE_4, GROUP_PHASE_4);
+ break;
+ case EVENT_FRENZY:
+ DoCastSelf(SPELL_FRENZY);
+ Talk(SAY_ILLIDAN_FRENZY);
+ events.Repeat(Seconds(40));
+ break;
+ case EVENT_TAUNT:
+ Talk(SAY_ILLIDAN_TAUNT);
+ events.Repeat(Seconds(30), Seconds(60));
+ break;
+ case EVENT_DEFEATED_TEXT:
+ Talk(SAY_ILLIDAN_DEFEATED);
+ events.ScheduleEvent(EVENT_QUIET_SUICIDE, Seconds(18));
+ break;
+ case EVENT_QUIET_SUICIDE:
+ {
+ DoCastSelf(SPELL_QUIET_SUICIDE, true);
+ if (Creature* akama = instance->GetCreature(DATA_AKAMA))
+ akama->AI()->DoAction(ACTION_START_OUTRO);
+ ObjectGuid _akamaGUID = instance->GetGuidData(DATA_AKAMA);
+ ObjectGuid _maievGUID = instance->GetGuidData(DATA_MAIEV);
+ summons.DespawnIf([_akamaGUID, _maievGUID](ObjectGuid unitGuid)
{
- if (Creature* glaive = ObjectAccessor::GetCreature(*me, GlaiveGUID[i]))
- glaive->DespawnOrUnsummon();
-
- GlaiveGUID[i].Clear();
- }
+ return unitGuid != _akamaGUID && unitGuid != _maievGUID;
+ });
+ break;
}
- Timer[EVENT_FLIGHT_SEQUENCE] = 2000;
- break;
- case 10: // attack
- DoResetThreat();
- me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE + UNIT_FLAG_NOT_SELECTABLE);
- me->SetSheath(SHEATH_STATE_MELEE);
- EnterPhase(PHASE_NORMAL_2);
- break;
- default:
- break;
+ default:
+ break;
+ }
+
+ if (me->HasUnitState(UNIT_STATE_CASTING))
+ return;
+ }
+
+ DoMeleeAttackIfReady();
+ }
+
+ private:
+ bool _intro;
+ uint8 _minionsCount;
+ uint8 _flameCount;
+ float _orientation;
+ uint8 _pillarIndex;
+ uint8 _phase;
+ bool _dead;
+ bool _isDemon;
+ EventMap specialEvents;
+ };
+
+ CreatureAI* GetAI(Creature* creature) const override
+ {
+ return GetBlackTempleAI<boss_illidan_stormrageAI>(creature);
+ }
+};
+
+class npc_akama : public CreatureScript
+{
+public:
+ npc_akama() : CreatureScript("npc_akama_illidan") { }
+
+ struct npc_akamaAI : public ScriptedAI
+ {
+ npc_akamaAI(Creature* creature) : ScriptedAI(creature), _instance(creature->GetInstanceScript()), _orientation(0.0f), _isTeleportToMinions(false) { }
+
+ void Reset() override
+ {
+ _events.Reset();
+ _spiritOfUdaloGUID.Clear();
+ _spiritOfOlumGUID.Clear();
+ _isTeleportToMinions = false;
+ }
+
+ void sGossipSelect(Player* player, uint32 /*menuId*/, uint32 gossipListId) override
+ {
+ if (gossipListId == GOSSIP_START_INTRO)
+ {
+ _instance->SetData(DATA_AKAMA, AKAMA_FIGHT);
+ me->GetMotionMaster()->MoveAlongSplineChain(POINT_STAIRS, SPLINE_STAIRS, false);
+ me->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP);
+ if (Creature* illidan = _instance->GetCreature(DATA_ILLIDAN_STORMRAGE))
+ illidan->AI()->DoAction(ACTION_INTRO_DONE);
+ CloseGossipMenuFor(player);
+
+ }
+ else if (gossipListId == GOSSIP_START_FIGHT)
+ {
+ _events.SetPhase(PHASE_INTRO);
+ me->GetMotionMaster()->MoveAlongSplineChain(POINT_FACE_ILLIDAN, SPLINE_FACE_ILLIDAN, false);
+ me->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP);
+ CloseGossipMenuFor(player);
}
- ++FlightCount;
}
- void HandleTransformSequence()
+ bool CanAIAttack(Unit const* who) const override
{
- if (DemonTransformation[TransformCount].unaura)
- me->RemoveAurasDueToSpell(DemonTransformation[TransformCount].unaura);
+ if (_events.IsInPhase(PHASE_MINIONS) && who->GetEntry() == NPC_ILLIDAN_STORMRAGE)
+ return false;
+ return ScriptedAI::CanAIAttack(who);
+ }
- if (DemonTransformation[TransformCount].aura)
- DoCast(me, DemonTransformation[TransformCount].aura, true);
+ uint32 GetData(uint32 /*data*/) const override
+ {
+ return _isTeleportToMinions ? 1 : 0;
+ }
- if (DemonTransformation[TransformCount].displayid)
- me->SetDisplayId(DemonTransformation[TransformCount].displayid); // It's morphin time!
+ void EnterEvadeMode(EvadeReason /*why*/) override { }
- if (DemonTransformation[TransformCount].equip)
+ void JustSummoned(Creature* summon) override
+ {
+ if (summon->GetEntry() == NPC_SPIRIT_OF_UDALO)
{
- // Requip warglaives if needed
- SetEquipmentSlots(false, EQUIP_ID_MAIN_HAND, EQUIP_ID_OFF_HAND, EQUIP_NO_CHANGE);
- me->SetSheath(SHEATH_STATE_MELEE);
+ _spiritOfUdaloGUID = summon->GetGUID();
+ summon->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP);
}
- else
+ else if (summon->GetEntry() == NPC_SPIRIT_OF_OLUM)
{
- // Unequip warglaives if needed
- SetEquipmentSlots(false, EQUIP_UNEQUIP, EQUIP_UNEQUIP, EQUIP_NO_CHANGE);
+ _spiritOfOlumGUID = summon->GetGUID();
+ summon->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP);
}
+ }
- switch (TransformCount)
+ void DoAction(int32 actionId) override
+ {
+ switch (actionId)
{
- case 2:
- DoResetThreat();
+ case ACTION_ACTIVE_AKAMA_INTRO:
+ _events.SetPhase(PHASE_INTRO);
+ me->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP);
+ _events.SetPhase(PHASE_INTRO);
+ _events.ScheduleEvent(EVENT_TELEPORT, Seconds(1));
+ _events.ScheduleEvent(EVENT_MOVE_TO_ILLIDARI_ROOM, Seconds(1) + Milliseconds(500));
break;
- case 4:
- EnterPhase(PHASE_DEMON);
+ case ACTION_OPEN_DOOR:
+ _instance->SetData(ACTION_OPEN_DOOR, 0);
+ _events.ScheduleEvent(EVENT_AKAMA_THANKS, Seconds(2));
break;
- case 7:
- DoResetThreat();
+ case ACTION_FREE:
+ _events.ScheduleEvent(EVENT_FREE, Seconds(14));
break;
- case 9:
- if (MaievGUID)
- EnterPhase(PHASE_NORMAL_MAIEV); // Depending on whether we summoned Maiev, we switch to either phase 5 or 3
- else
- EnterPhase(PHASE_NORMAL_2);
+ case ACTION_START_ENCOUNTER:
+ DoZoneInCombat();
+ _events.ScheduleEvent(EVENT_HEALING_POTION, Seconds(1));
+ break;
+ case ACTION_START_MINIONS:
+ _events.ScheduleEvent(EVENT_AKAMA_MINIONS, Seconds(8));
+ break;
+ case ACTION_START_OUTRO:
+ me->SetReactState(REACT_PASSIVE);
+ me->AttackStop();
+ _events.Reset();
+ _events.ScheduleEvent(EVENT_AKAMA_MOVE_BACK, Seconds(2));
break;
default:
break;
}
- if (Phase == PHASE_TRANSFORM_SEQUENCE)
- Timer[EVENT_TRANSFORM_SEQUENCE] = DemonTransformation[TransformCount].timer;
- ++TransformCount;
}
- void UpdateAI(uint32 diff) override
+ void ChangeOrientation(float orientation)
{
- if ((!UpdateVictim()) && Phase < PHASE_TALK_SEQUENCE)
- return;
+ _orientation = orientation;
+ _events.ScheduleEvent(EVENT_CHANGE_ORIENTATION, Milliseconds(1));
+ }
- Event = EVENT_NULL;
- for (int32 i = 1; i <= MaxTimer[Phase]; ++i)
- {
- if (Timer[i]) // Event is enabled
- {
- if (Timer[i] <= diff)
- {
- if (!Event) // No event with higher priority
- Event = (EventIllidan)i;
- }
- else Timer[i] -= diff;
- }
- }
+ void MovementInform(uint32 type, uint32 pointId) override
+ {
+ if (type != POINT_MOTION_TYPE && type != SPLINE_CHAIN_MOTION_TYPE)
+ return;
- switch (Phase)
+ switch (pointId)
{
- case PHASE_NORMAL:
- if (HealthBelowPct(65))
- EnterPhase(PHASE_FLIGHT_SEQUENCE);
+ case POINT_ILLIDARI_COUNCIL:
+ Talk(SAY_AKAMA_FINISH);
+ me->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP);
break;
-
- case PHASE_NORMAL_2:
- if (HealthBelowPct(30))
- EnterPhase(PHASE_TALK_SEQUENCE);
+ case POINT_STAIRS:
+ ChangeOrientation(6.265732f);
+ _events.ScheduleEvent(EVENT_AKAMA_SAY_DOOR, Seconds(5));
break;
-
- case PHASE_NORMAL_MAIEV:
- if (HealthBelowPct(1))
- EnterPhase(PHASE_TALK_SEQUENCE);
+ case POINT_ILLIDAN_ROOM:
+ ChangeOrientation(2.129302f);
+ Talk(SAY_AKAMA_BETRAYER);
+ me->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP);
break;
-
- case PHASE_TALK_SEQUENCE:
- if (Event == EVENT_TALK_SEQUENCE)
- HandleTalkSequence();
+ case POINT_FACE_ILLIDAN:
+ ChangeOrientation(3.140537f);
+ _events.ScheduleEvent(EVENT_START_ILLIDAN, Seconds(2));
break;
-
- case PHASE_FLIGHT_SEQUENCE:
- if (Event == EVENT_FLIGHT_SEQUENCE)
- HandleFlightSequence();
+ case POINT_TELEPORT:
+ DoCastSelf(SPELL_AKAMA_TELEPORT);
+ _events.ScheduleEvent(EVENT_AKAMA_MINIONS_MOVE_2, Milliseconds(500));
break;
-
- case PHASE_TRANSFORM_SEQUENCE:
- if (Event == EVENT_TRANSFORM_SEQUENCE)
- HandleTransformSequence();
+ case POINT_MINIONS:
+ _events.SetPhase(PHASE_MINIONS);
+ me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_NPC);
+ me->SetReactState(REACT_AGGRESSIVE);
+ if (Creature* illidan = _instance->GetCreature(DATA_ILLIDAN_STORMRAGE))
+ illidan->AI()->DoAction(ACTION_START_MINIONS_WEAVE);
+ _events.ScheduleEvent(EVENT_CHAIN_LIGHTNING, Seconds(2));
+ break;
+ case POINT_MOVE_BACK:
+ _events.ScheduleEvent(EVENT_AKAMA_MOVE_TO_ILLIDAN, Milliseconds(1));
+ break;
+ case POINT_ILLIDAN:
+ _events.ScheduleEvent(EVENT_AKAMA_LIGHT_TEXT, Seconds(1));
break;
default:
break;
}
+ }
+
+ void DamageTaken(Unit* /*who*/, uint32 &damage) override
+ {
+ if (damage >= me->GetHealth())
+ damage = me->GetHealth() - 1;
+ }
- if (me->IsNonMeleeSpellCast(false))
+ void UpdateAI(uint32 diff) override
+ {
+ if (!UpdateVictim() && !_events.IsInPhase(PHASE_INTRO))
return;
- if (Phase == PHASE_NORMAL || Phase == PHASE_NORMAL_2 || (Phase == PHASE_NORMAL_MAIEV && !me->HasAura(SPELL_CAGED)))
+ _events.Update(diff);
+
+ if (me->HasUnitState(UNIT_STATE_CASTING))
+ return;
+
+ while (uint32 eventId = _events.ExecuteEvent())
{
- switch (Event)
+ switch (eventId)
{
- // PHASE_NORMAL
- case EVENT_BERSERK:
- Talk(SAY_ILLIDAN_ENRAGE);
- DoCast(me, SPELL_BERSERK, true);
- Timer[EVENT_BERSERK] = 5000; // The buff actually lasts forever.
+ case EVENT_TELEPORT:
+ DoCastSelf(SPELL_AKAMA_TELEPORT, true);
break;
-
- case EVENT_TAUNT:
- Talk(SAY_ILLIDAN_TAUNT);
- Timer[EVENT_TAUNT] = urand(25000, 35000);
+ case EVENT_MOVE_TO_ILLIDARI_ROOM:
+ me->GetMotionMaster()->MoveAlongSplineChain(POINT_ILLIDARI_COUNCIL, SPLINE_ILLIDARI_COUNCIL, false);
break;
-
- case EVENT_SHEAR:
- // no longer exists in 3.0f.2
- // DoCastVictim(SPELL_SHEAR);
- Timer[EVENT_SHEAR] = 25000 + (rand32() % 16 * 1000);
+ case EVENT_AKAMA_SAY_DOOR:
+ Talk(SAY_AKAMA_DOOR);
+ _events.ScheduleEvent(EVENT_AKAMA_DOOR_FAIL, Seconds(4));
break;
-
- case EVENT_FLAME_CRASH:
- DoCastVictim(SPELL_FLAME_CRASH);
- Timer[EVENT_FLAME_CRASH] = urand(30000, 40000);
+ case EVENT_AKAMA_DOOR_FAIL:
+ DoCastSelf(SPELL_AKAMA_DOOR_FAIL);
+ _events.ScheduleEvent(EVENT_AKAMA_SAY_ALONE, Seconds(10));
break;
-
- case EVENT_PARASITIC_SHADOWFIEND:
+ case EVENT_AKAMA_SAY_ALONE:
+ Talk(SAY_AKAMA_ALONE);
+ _events.ScheduleEvent(EVENT_SUMMON_SPIRITS, Seconds(7));
+ break;
+ case EVENT_SUMMON_SPIRITS:
+ me->SummonCreatureGroup(SUMMON_GROUP);
+ _events.ScheduleEvent(EVENT_SPIRIT_SAY_1, Seconds(1));
+ break;
+ case EVENT_SPIRIT_SAY_1:
+ if (Creature* undalo = ObjectAccessor::GetCreature(*me, _spiritOfUdaloGUID))
+ undalo->AI()->Talk(SAY_SPIRIT_ALONE);
+ _events.ScheduleEvent(EVENT_SPIRIT_SAY_2, Seconds(6));
+ break;
+ case EVENT_SPIRIT_SAY_2:
+ if (Creature* olum = ObjectAccessor::GetCreature(*me, _spiritOfOlumGUID))
+ olum->AI()->Talk(SAY_SPIRIT_ALONE);
+ _events.ScheduleEvent(EVENT_AKAMA_DOOR_SUCCESS, Seconds(6));
+ break;
+ case EVENT_AKAMA_DOOR_SUCCESS:
+ DoCastSelf(SPELL_AKAMA_DOOR_CHANNEL);
+ if (Creature* undalo = ObjectAccessor::GetCreature(*me, _spiritOfUdaloGUID))
+ undalo->CastSpell((Unit*) nullptr, SPELL_DEATHSWORN_DOOR_CHANNEL);
+ if (Creature* olum = ObjectAccessor::GetCreature(*me, _spiritOfOlumGUID))
+ olum->CastSpell((Unit*) nullptr, SPELL_DEATHSWORN_DOOR_CHANNEL);
+ break;
+ case EVENT_AKAMA_THANKS:
+ Talk(SAY_AKAMA_SALUTE);
+ _events.ScheduleEvent(EVENT_SPIRIT_SALUTE, Seconds(3));
+ _events.ScheduleEvent(EVENT_RUN_FROM_ILLIDAN_ROOM, Seconds(7));
+ break;
+ case EVENT_SPIRIT_SALUTE:
+ if (Creature* undalo = ObjectAccessor::GetCreature(*me, _spiritOfUdaloGUID))
{
- if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 1, 200, true))
- DoCast(target, SPELL_PARASITIC_SHADOWFIEND, true);
- Timer[EVENT_PARASITIC_SHADOWFIEND] = urand(35000, 45000);
+ undalo->HandleEmoteCommand(EMOTE_ONESHOT_SALUTE);
+ undalo->DespawnOrUnsummon(Seconds(7));
+ }
+ if (Creature* olum = ObjectAccessor::GetCreature(*me, _spiritOfOlumGUID))
+ {
+ olum->HandleEmoteCommand(EMOTE_ONESHOT_SALUTE);
+ olum->DespawnOrUnsummon(Seconds(7));
}
break;
-
- case EVENT_PARASITE_CHECK:
- Timer[EVENT_PARASITE_CHECK] = 0;
+ case EVENT_RUN_FROM_ILLIDAN_ROOM:
+ me->GetMotionMaster()->MoveAlongSplineChain(POINT_ILLIDAN_ROOM, SPLINE_ILLIDAN_ROOM, false);
break;
-
- case EVENT_DRAW_SOUL:
- DoCastVictim(SPELL_DRAW_SOUL);
- Timer[EVENT_DRAW_SOUL] = urand(50000, 60000);
+ case EVENT_START_ILLIDAN:
+ if (Creature* illidan = _instance->GetCreature(DATA_ILLIDAN_STORMRAGE))
+ illidan->AI()->DoAction(ACTION_START_ENCOUNTER);
break;
-
- // PHASE_NORMAL_2
- case EVENT_AGONIZING_FLAMES:
- DoCast(SelectTarget(SELECT_TARGET_RANDOM, 0), SPELL_AGONIZING_FLAMES);
- Timer[EVENT_AGONIZING_FLAMES] = 0;
+ case EVENT_FREE:
+ Talk(SAY_AKAMA_FREE);
+ _events.ScheduleEvent(EVENT_TIME_HAS_COME, Seconds(18));
break;
-
- case EVENT_TRANSFORM_NORMAL:
- EnterPhase(PHASE_TRANSFORM_SEQUENCE);
+ case EVENT_TIME_HAS_COME:
+ Talk(SAY_AKAMA_TIME_HAS_COME);
+ _events.ScheduleEvent(EVENT_ROAR, Seconds(2));
break;
-
- // PHASE_NORMAL_MAIEV
- case EVENT_ENRAGE:
- DoCast(me, SPELL_ENRAGE);
- Timer[EVENT_ENRAGE] = 0;
+ case EVENT_ROAR:
+ me->HandleEmoteCommand(EMOTE_ONESHOT_ROAR);
+ me->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_STATE_READY1H);
break;
-
- default:
+ case EVENT_CHANGE_ORIENTATION:
+ me->SetFacingTo(_orientation, true);
break;
- }
- DoMeleeAttackIfReady();
- }
-
- if (Phase == PHASE_FLIGHT)
- {
- switch (Event)
- {
- case EVENT_FIREBALL:
- DoCast(SelectTarget(SELECT_TARGET_RANDOM, 0), SPELL_FIREBALL);
- Timer[EVENT_FIREBALL] = 3000;
+ case EVENT_HEALING_POTION:
+ if (me->HealthBelowPct(20))
+ DoCastSelf(SPELL_HEALING_POTION);
+ _events.Repeat(Seconds(1));
break;
-
- case EVENT_DARK_BARRAGE:
- DoCast(SelectTarget(SELECT_TARGET_RANDOM, 0), SPELL_DARK_BARRAGE);
- Timer[EVENT_DARK_BARRAGE] = 0;
+ case EVENT_AKAMA_MINIONS:
+ Talk(SAY_AKAMA_MINIONS);
+ _events.ScheduleEvent(EVENT_AKAMA_MINIONS_EMOTE, Seconds(2));
break;
-
- case EVENT_EYE_BLAST:
- CastEyeBlast();
- Timer[EVENT_EYE_BLAST] = 0;
+ case EVENT_AKAMA_MINIONS_EMOTE:
+ me->SetReactState(REACT_PASSIVE);
+ me->AttackStop();
+ me->HandleEmoteCommand(EMOTE_ONESHOT_EXCLAMATION);
+ me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_NPC);
+ _events.ScheduleEvent(EVENT_AKAMA_MINIONS_MOVE, Seconds(4));
break;
-
- case EVENT_MOVE_POINT:
- Phase = PHASE_FLIGHT_SEQUENCE;
- Timer[EVENT_FLIGHT_SEQUENCE] = 0; // do not start Event when changing hover point
- HoverPoint += (rand32() % 3 + 1);
- if (HoverPoint > 3)
- HoverPoint -= 4;
- me->GetMotionMaster()->MovePoint(0, HoverPosition[HoverPoint].x, HoverPosition[HoverPoint].y, HoverPosition[HoverPoint].z);
+ case EVENT_AKAMA_MINIONS_MOVE:
+ _isTeleportToMinions = true;
+ me->GetMotionMaster()->MoveAlongSplineChain(POINT_TELEPORT, SPLINE_TELEPORT, false);
break;
-
- default:
+ case EVENT_AKAMA_MINIONS_MOVE_2:
+ me->GetMotionMaster()->MoveAlongSplineChain(POINT_MINIONS, SPLINE_MINIONS, false);
break;
- }
- }
-
- if (Phase == PHASE_DEMON)
- {
- switch (Event)
- {
- case EVENT_SHADOW_BLAST:
- me->GetMotionMaster()->Clear(false);
- if (me->GetVictim() && (!me->IsWithinDistInMap(me->GetVictim(), 50) || !me->IsWithinLOSInMap(me->GetVictim())))
- me->GetMotionMaster()->MoveChase(me->GetVictim(), 30);
- else
- me->GetMotionMaster()->MoveIdle();
- DoCastVictim(SPELL_SHADOW_BLAST);
- Timer[EVENT_SHADOW_BLAST] = 4000;
+ case EVENT_CHAIN_LIGHTNING:
+ DoCastVictim(SPELL_CHAIN_LIGHTNING);
+ _events.Repeat(Seconds(8) + Milliseconds(500));
break;
- case EVENT_SHADOWDEMON:
- DoCast(me, SPELL_SUMMON_SHADOWDEMON);
- Timer[EVENT_SHADOWDEMON] = 0;
- Timer[EVENT_FLAME_BURST] += 10000;
+ case EVENT_AKAMA_MOVE_BACK:
+ me->GetMotionMaster()->MoveAlongSplineChain(POINT_MOVE_BACK, SPLINE_MOVE_BACK, false);
break;
- case EVENT_FLAME_BURST:
- DoCast(me, SPELL_FLAME_BURST);
- Timer[EVENT_FLAME_BURST] = 15000;
+ case EVENT_AKAMA_MOVE_TO_ILLIDAN:
+ if (Creature* illidan = _instance->GetCreature(DATA_ILLIDAN_STORMRAGE))
+ me->GetMotionMaster()->MoveCloserAndStop(POINT_ILLIDAN, illidan, 5.0f);
break;
- case EVENT_TRANSFORM_DEMON:
- EnterPhase(PHASE_TRANSFORM_SEQUENCE);
+ case EVENT_AKAMA_LIGHT_TEXT:
+ Talk(SAY_AKAMA_LIGHT);
+ _events.ScheduleEvent(EVENT_FINAL_SALUTE, Seconds(4));
+ break;
+ case EVENT_FINAL_SALUTE:
+ me->HandleEmoteCommand(EMOTE_ONESHOT_SALUTE);
+ _events.ScheduleEvent(EVENT_AKAMA_DESPAWN, Seconds(5));
+ break;
+ case EVENT_AKAMA_DESPAWN:
+ DoCastSelf(SPELL_AKAMA_DESPAWN, true);
break;
default:
break;
}
+
+ if (me->HasUnitState(UNIT_STATE_CASTING))
+ return;
}
+
+ DoMeleeAttackIfReady();
}
- public:
- ObjectGuid AkamaGUID;
- uint32 Timer[EVENT_ENRAGE + 1];
- PhaseIllidan Phase;
private:
- EventIllidan Event;
- uint32 TalkCount;
- uint32 TransformCount;
- uint32 FlightCount;
- uint32 HoverPoint;
- ObjectGuid MaievGUID;
- ObjectGuid FlameGUID[2];
- ObjectGuid GlaiveGUID[2];
+ InstanceScript* _instance;
+ EventMap _events;
+ ObjectGuid _spiritOfUdaloGUID;
+ ObjectGuid _spiritOfOlumGUID;
+ float _orientation;
+ bool _isTeleportToMinions;
};
CreatureAI* GetAI(Creature* creature) const override
{
- return GetInstanceAI<boss_illidan_stormrageAI>(creature);
+ return GetBlackTempleAI<npc_akamaAI>(creature);
}
};
-/********************************** End of Illidan AI* *****************************************/
-
-/******* Functions and vars for Maiev's AI* *****/
-class boss_maiev_shadowsong : public CreatureScript
+class npc_parasitic_shadowfiend : public CreatureScript
{
public:
- boss_maiev_shadowsong() : CreatureScript("boss_maiev_shadowsong") { }
+ npc_parasitic_shadowfiend() : CreatureScript("npc_parasitic_shadowfiend") { }
- struct boss_maievAI : public ScriptedAI
+ struct npc_parasitic_shadowfiendAI : public ScriptedAI
{
- boss_maievAI(Creature* creature) : ScriptedAI(creature)
- {
- Initialize();
- }
-
- void Initialize()
- {
- MaxTimer = 0;
- Phase = PHASE_NORMAL_MAIEV;
- IllidanGUID.Clear();
- Timer[EVENT_MAIEV_STEALTH] = 0;
- Timer[EVENT_MAIEV_TAUNT] = urand(22, 43) * 1000;
- Timer[EVENT_MAIEV_SHADOW_STRIKE] = 30000;
- }
+ npc_parasitic_shadowfiendAI(Creature* creature) : ScriptedAI(creature), _instance(creature->GetInstanceScript()) { }
void Reset() override
{
- Initialize();
- SetEquipmentSlots(false, EQUIP_ID_MAIN_HAND_MAIEV, EQUIP_UNEQUIP, EQUIP_NO_CHANGE);
- me->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID + 2, 45738);
+ if (_instance->GetBossState(DATA_ILLIDAN_STORMRAGE) != IN_PROGRESS)
+ {
+ me->DespawnOrUnsummon();
+ return;
+ }
+
+ if (Creature* illidan = _instance->GetCreature(DATA_ILLIDAN_STORMRAGE))
+ illidan->AI()->JustSummoned(me);
+ me->SetReactState(REACT_DEFENSIVE);
+ _scheduler.Schedule(Seconds(2), [this](TaskContext /*context*/)
+ {
+ me->SetReactState(REACT_AGGRESSIVE);
+ me->SetInCombatWithZone();
+ });
}
- void EnterCombat(Unit* /*who*/) override { }
- void MoveInLineOfSight(Unit* /*who*/) override { }
+ void UpdateAI(uint32 diff) override
+ {
+ if (!UpdateVictim())
+ return;
- void EnterEvadeMode(EvadeReason /*why*/) override { }
+ if (me->HasUnitState(UNIT_STATE_CASTING))
+ return;
- void GetIllidanGUID(ObjectGuid guid)
- {
- IllidanGUID = guid;
+ _scheduler.Update(diff, [this]
+ {
+ DoMeleeAttackIfReady();
+ });
}
- void DamageTaken(Unit* done_by, uint32 &damage) override
- {
- if (done_by->GetGUID() != IllidanGUID)
- damage = 0;
- else
- {
- if (Creature* illidan = ObjectAccessor::GetCreature(*me, IllidanGUID))
- if (illidan->GetVictim() == me)
- damage = me->CountPctFromMaxHealth(10);
+ private:
+ InstanceScript* _instance;
+ TaskScheduler _scheduler;
+ };
- if (damage >= me->GetHealth())
- damage = 0;
- }
- }
+ CreatureAI* GetAI(Creature* creature) const override
+ {
+ return GetBlackTempleAI<npc_parasitic_shadowfiendAI>(creature);
+ }
+};
- void AttackStart(Unit* who) override
+class npc_blade_of_azzinoth : public CreatureScript
+{
+public:
+ npc_blade_of_azzinoth() : CreatureScript("npc_blade_of_azzinoth") { }
+
+ struct npc_blade_of_azzinothAI : public NullCreatureAI
+ {
+ npc_blade_of_azzinothAI(Creature* creature) : NullCreatureAI(creature), _instance(creature->GetInstanceScript()) { }
+
+ void Reset() override
{
- if (!who || Timer[EVENT_MAIEV_STEALTH])
+ if (_instance->GetBossState(DATA_ILLIDAN_STORMRAGE) != IN_PROGRESS)
+ {
+ me->DespawnOrUnsummon();
return;
+ }
- if (Phase == PHASE_TALK_SEQUENCE)
- AttackStartNoMove(who);
- else if (Phase == PHASE_DEMON || Phase == PHASE_TRANSFORM_SEQUENCE)
+ if (Creature* illidan = _instance->GetCreature(DATA_ILLIDAN_STORMRAGE))
+ illidan->AI()->JustSummoned(me);
+ _flameGuid.Clear();
+ me->PlayDirectSound(WARGLAIVE_SPAWN_SOUND_ID);
+ DoCastSelf(SPELL_BIRTH, true);
+ _scheduler.Schedule(Seconds(3), [this](TaskContext /*context*/)
{
- if (Creature* illidan = ObjectAccessor::GetCreature(*me, IllidanGUID))
- if (me->IsWithinDistInMap(illidan, 25))
- BlinkToPlayer(); // Do not let dread aura hurt her.
- AttackStartNoMove(who);
- }
- else
- ScriptedAI::AttackStart(who);
+ DoCastSelf(SPELL_SUMMON_TEAR_OF_AZZINOTH);
+ _scheduler.Schedule(Milliseconds(500), [this](TaskContext /*context*/)
+ {
+ if (Creature* flame = ObjectAccessor::GetCreature(*me, _flameGuid))
+ DoCast(flame, SPELL_AZZINOTH_CHANNEL);
+ });
+ });
}
- void DoAction(int32 param) override
+ void JustSummoned(Creature* summon) override
{
- if (param > PHASE_ILLIDAN_NULL && param < PHASE_ILLIDAN_MAX)
- EnterPhase(PhaseIllidan(param));
+ if (summon->GetEntry() == NPC_FLAME_OF_AZZINOTH)
+ _flameGuid = summon->GetGUID();
}
- void EnterPhase(PhaseIllidan NextPhase) // This is in fact Illidan's phase.
+ void UpdateAI(uint32 diff) override
{
- switch (NextPhase)
- {
- case PHASE_TALK_SEQUENCE:
- if (Timer[EVENT_MAIEV_STEALTH])
- {
- me->SetFullHealth();
- me->SetVisible(true);
- Timer[EVENT_MAIEV_STEALTH] = 0;
- }
- me->InterruptNonMeleeSpells(false);
- me->GetMotionMaster()->Clear(false);
- me->AttackStop();
- me->SetTarget(IllidanGUID);
- MaxTimer = 0;
- break;
- case PHASE_TRANSFORM_SEQUENCE:
- MaxTimer = 4;
- Timer[EVENT_MAIEV_TAUNT] += 10000;
- Timer[EVENT_MAIEV_THROW_DAGGER] = 2000;
- break;
- case PHASE_DEMON:
- break;
- case PHASE_NORMAL_MAIEV:
- MaxTimer = 4;
- Timer[EVENT_MAIEV_TAUNT] += 10000;
- Timer[EVENT_MAIEV_TRAP] = 22000;
- break;
- default:
- break;
- }
- if (Timer[EVENT_MAIEV_STEALTH])
- MaxTimer = 1;
- Phase = NextPhase;
+ _scheduler.Update(diff);
}
- void BlinkTo(float x, float y, float z)
+ private:
+ InstanceScript* _instance;
+ TaskScheduler _scheduler;
+ ObjectGuid _flameGuid;
+ };
+
+ CreatureAI* GetAI(Creature* creature) const override
+ {
+ return GetBlackTempleAI<npc_blade_of_azzinothAI>(creature);
+ }
+};
+
+class npc_flame_of_azzinoth : public CreatureScript
+{
+public:
+ npc_flame_of_azzinoth() : CreatureScript("npc_flame_of_azzinoth") { }
+
+ struct npc_flame_of_azzinothAI : public ScriptedAI
+ {
+ npc_flame_of_azzinothAI(Creature* creature) : ScriptedAI(creature), _instance(creature->GetInstanceScript())
{
- me->AttackStop();
- me->InterruptNonMeleeSpells(false);
- me->GetMotionMaster()->Clear(false);
- DoTeleportTo(x, y, z);
- DoCast(me, SPELL_TELEPORT_VISUAL, true);
+ SetBoundary(_instance->GetBossBoundary(DATA_ILLIDAN_STORMRAGE));
}
- void BlinkToPlayer()
+ void Reset() override
{
- if (Creature* illidan = ObjectAccessor::GetCreature(*me, IllidanGUID))
+ if (_instance->GetBossState(DATA_ILLIDAN_STORMRAGE) != IN_PROGRESS)
{
- Unit* target = illidan->AI()->SelectTarget(SELECT_TARGET_RANDOM, 0);
-
- if (!target || !me->IsWithinDistInMap(target, 80) || illidan->IsWithinDistInMap(target, 20))
- {
- uint8 pos = rand32() % 4;
- BlinkTo(HoverPosition[pos].x, HoverPosition[pos].y, HoverPosition[pos].z);
- }
- else
- {
- float x, y, z;
- target->GetPosition(x, y, z);
- BlinkTo(x, y, z);
- }
+ me->DespawnOrUnsummon();
+ return;
}
+
+ if (Creature* illidan = _instance->GetCreature(DATA_ILLIDAN_STORMRAGE))
+ illidan->AI()->JustSummoned(me);
+ DoCastSelf(SPELL_FLAME_TEAR_OF_AZZINOTH, true); // Idk what this spell should do
+ me->SetReactState(REACT_PASSIVE);
+ _events.ScheduleEvent(EVENT_ENGAGE, Seconds(3));
+ _events.ScheduleEvent(EVENT_FLAME_BLAST, Seconds(11));
}
void UpdateAI(uint32 diff) override
{
- if ((!UpdateVictim())
- && !Timer[EVENT_MAIEV_STEALTH])
+ if (!UpdateVictim())
+ return;
+
+ if (me->HasUnitState(UNIT_STATE_CASTING))
return;
- EventMaiev Event = EVENT_MAIEV_NULL;
- for (uint8 i = 1; i <= MaxTimer; ++i)
+ _events.Update(diff);
+
+ while (uint32 eventId = _events.ExecuteEvent())
{
- if (Timer[i])
+ switch (eventId)
{
- if (Timer[i] <= diff)
- Event = (EventMaiev)i;
- else Timer[i] -= diff;
+ case EVENT_ENGAGE:
+ me->SetReactState(REACT_AGGRESSIVE);
+ me->SetInCombatWithZone();
+ _events.ScheduleEvent(EVENT_FLAME_CHARGE, Seconds(5));
+ break;
+ case EVENT_FLAME_CHARGE:
+ if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, ChargeTargetSelector(me)))
+ {
+ DoCast(target, SPELL_CHARGE);
+ _events.Repeat(Seconds(5));
+ }
+ else
+ _events.Repeat(Seconds(1));
+ break;
+ case EVENT_FLAME_BLAST:
+ DoCastAOE(SPELL_FLAME_BLAST);
+ _events.Repeat(Seconds(12));
+ break;
+ default:
+ break;
}
- }
- switch (Event)
- {
- case EVENT_MAIEV_STEALTH:
- {
- me->SetFullHealth();
- me->SetVisible(true);
- me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE);
- Timer[EVENT_MAIEV_STEALTH] = 0;
- BlinkToPlayer();
- EnterPhase(Phase);
- }
- break;
- case EVENT_MAIEV_TAUNT:
- Talk(SAY_MAIEV_SHADOWSONG_TAUNT);
- Timer[EVENT_MAIEV_TAUNT] = urand(22, 43) * 1000;
- break;
- case EVENT_MAIEV_SHADOW_STRIKE:
- DoCastVictim(SPELL_SHADOW_STRIKE);
- Timer[EVENT_MAIEV_SHADOW_STRIKE] = 60000;
- break;
- case EVENT_MAIEV_TRAP:
- if (Phase == PHASE_NORMAL_MAIEV)
- {
- BlinkToPlayer();
- DoCast(me, SPELL_CAGE_TRAP_SUMMON);
- Timer[EVENT_MAIEV_TRAP] = 22000;
- }
- else
- {
- if (!me->IsWithinDistInMap(me->GetVictim(), 40))
- me->GetMotionMaster()->MoveChase(me->GetVictim(), 30);
- DoCastVictim(SPELL_THROW_DAGGER);
- Timer[EVENT_MAIEV_THROW_DAGGER] = 2000;
- }
- break;
- default:
- break;
+ if (me->HasUnitState(UNIT_STATE_CASTING))
+ return;
}
- if (HealthBelowPct(50))
- {
- me->SetVisible(false);
- me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE);
- if (Creature* illidan = ObjectAccessor::GetCreature(*me, IllidanGUID))
- ENSURE_AI(boss_illidan_stormrage::boss_illidan_stormrageAI, illidan->AI())->DeleteFromThreatList(me->GetGUID());
- me->AttackStop();
- Timer[EVENT_MAIEV_STEALTH] = 60000; // reappear after 1 minute
- MaxTimer = 1;
- }
+ DoMeleeAttackIfReady();
+ }
- if (Phase == PHASE_NORMAL_MAIEV)
- DoMeleeAttackIfReady();
+ void JustDied(Unit* /*killer*/) override
+ {
+ if (Creature* illidan = _instance->GetCreature(DATA_ILLIDAN_STORMRAGE))
+ illidan->AI()->DoAction(ACTION_FLAME_DEAD);
}
private:
- ObjectGuid IllidanGUID;
- PhaseIllidan Phase;
- uint32 Timer[5];
- uint32 MaxTimer;
+ InstanceScript* _instance;
+ EventMap _events;
};
CreatureAI* GetAI(Creature* creature) const override
{
- return new boss_maievAI(creature);
+ return GetBlackTempleAI<npc_flame_of_azzinothAI>(creature);
}
};
-/******* Functions and vars for Akama's AI* *****/
-class npc_akama_illidan : public CreatureScript
+class npc_illidan_db_target : public CreatureScript
{
public:
- npc_akama_illidan() : CreatureScript("npc_akama_illidan") { }
+ npc_illidan_db_target() : CreatureScript("npc_illidan_db_target") { }
- struct npc_akama_illidanAI : public ScriptedAI
+ struct npc_illidan_db_targetAI : public NullCreatureAI
{
- npc_akama_illidanAI(Creature* creature) : ScriptedAI(creature)
+ npc_illidan_db_targetAI(Creature* creature) : NullCreatureAI(creature) { }
+
+ void Reset() override
{
- Initialize();
- instance = creature->GetInstanceScript();
- JustCreated = true;
+ DoCastSelf(SPELL_EYE_BLAST_TRIGGER);
}
- void Initialize()
+ void JustSummoned(Creature* summon) override
{
- ChannelGUID.Clear();
- SpiritGUID[0].Clear();
- SpiritGUID[1].Clear();
-
- Phase = PHASE_AKAMA_NULL;
- Timer = 0;
-
- ChannelCount = 0;
- TalkCount = 0;
- Check_Timer = 5000;
- WalkCount = 0;
+ if (summon->GetEntry() == NPC_DEMON_FIRE)
+ summon->SetReactState(REACT_PASSIVE);
}
- void Reset() override
+ void MovementInform(uint32 type, uint32 pointId) override
{
- Initialize();
- instance->SetBossState(DATA_ILLIDAN_STORMRAGE, NOT_STARTED);
+ if (type == POINT_MOTION_TYPE && pointId == POINT_DB_TARGET)
+ {
+ me->RemoveAurasDueToSpell(SPELL_EYE_BLAST_TRIGGER);
+ me->RemoveAurasDueToSpell(SPELL_EYE_BLAST);
+ }
+ }
+ };
- IllidanGUID = instance->GetGuidData(DATA_ILLIDAN_STORMRAGE);
- GateGUID = instance->GetGuidData(DATA_GO_ILLIDAN_GATE);
+ CreatureAI* GetAI(Creature* creature) const override
+ {
+ return GetBlackTempleAI<npc_illidan_db_targetAI>(creature);
+ }
+};
- if (JustCreated) // close all doors at create
- instance->HandleGameObject(GateGUID, false);
- else // open all doors, raid wiped
+class npc_illidan_shadow_demon : public CreatureScript
+{
+public:
+ npc_illidan_shadow_demon() : CreatureScript("npc_shadow_demon") { }
+
+ struct npc_illidan_shadow_demonAI : public PassiveAI
+ {
+ npc_illidan_shadow_demonAI(Creature* creature) : PassiveAI(creature), _instance(creature->GetInstanceScript()) { }
+
+ void Reset() override
+ {
+ if (_instance->GetBossState(DATA_ILLIDAN_STORMRAGE) != IN_PROGRESS)
{
- instance->HandleGameObject(GateGUID, true);
- WalkCount = 1; // skip first wp
+ me->DespawnOrUnsummon();
+ return;
}
- KillAllElites();
+ DoCastSelf(SPELL_SHADOW_DEMON_PASSIVE);
+ DoCastSelf(SPELL_FIND_TARGET);
+ _scheduler.Schedule(Seconds(1), [this](TaskContext checkTarget)
+ {
+ if (Unit* target = ObjectAccessor::GetUnit(*me, _targetGUID))
+ {
+ if (!target->IsAlive())
+ DoCastSelf(SPELL_FIND_TARGET);
+ else if (me->IsWithinMeleeRange(target))
+ {
+ me->InterruptNonMeleeSpells(false);
+ DoCast(target, SPELL_CONSUME_SOUL, true);
+ }
+ }
+ checkTarget.Repeat();
+ });
+ }
- me->SetUInt32Value(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_NONE); // Database sometimes has strange values..
- me->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP);
- me->setActive(false);
- me->SetVisible(false);
+ void SetGUID(ObjectGuid guid, int32 /*id*/) override
+ {
+ _targetGUID = guid;
+ if (Unit* target = ObjectAccessor::GetUnit(*me, _targetGUID))
+ me->GetMotionMaster()->MoveChase(target);
}
- // Do not call reset in Akama's evade mode, as this will stop him from summoning minions after he kills the first bit
- void EnterEvadeMode(EvadeReason /*why*/) override
+ void UpdateAI(uint32 diff) override
{
- me->RemoveAllAuras();
- me->DeleteThreatList();
- me->CombatStop(true);
+ _scheduler.Update(diff);
}
- void EnterCombat(Unit* /*who*/) override { }
- void MoveInLineOfSight(Unit* /*who*/) override { }
+ private:
+ InstanceScript* _instance;
+ TaskScheduler _scheduler;
+ ObjectGuid _targetGUID;
+ };
+ CreatureAI* GetAI(Creature* creature) const override
+ {
+ return GetBlackTempleAI<npc_illidan_shadow_demonAI>(creature);
+ }
+};
- void MovementInform(uint32 MovementType, uint32 /*Data*/) override
+class npc_maiev : public CreatureScript
+{
+public:
+ npc_maiev() : CreatureScript("npc_maiev") { }
+
+ struct npc_maievAI : public ScriptedAI
+ {
+ npc_maievAI(Creature* creature) : ScriptedAI(creature), _instance(creature->GetInstanceScript()), _canDown(true) { }
+
+ void Reset() override
{
- if (MovementType == POINT_MOTION_TYPE)
- Timer = 1;
+ if (Creature* illidan = _instance->GetCreature(DATA_ILLIDAN_STORMRAGE))
+ me->SetFacingToObject(illidan);
+ me->SetReactState(REACT_PASSIVE);
+ _events.SetPhase(PHASE_INTRO);
+ _events.ScheduleEvent(EVENT_MAIEV_APPEAR, Seconds(1));
+ _events.ScheduleEvent(EVENT_MAIEV_EXCLAMATION, Seconds(2));
+ _events.ScheduleEvent(EVENT_MAIEV_JUSTICE_TEXT, Seconds(14));
+ _events.ScheduleEvent(EVENT_TAUNT, Seconds(20), Seconds(60));
+ _canDown = true;
}
- void DamageTaken(Unit* done_by, uint32 &damage) override
+ void EnterCombat(Unit* /*who*/) override
{
- if (damage > me->GetHealth() || done_by->GetGUID() != IllidanGUID)
- damage = 0;
+ _events.SetPhase(PHASE_1);
+ _events.ScheduleEvent(EVENT_CAGE_TRAP, Seconds(30));
+ _events.ScheduleEvent(EVENT_SHADOW_STRIKE, Seconds(50));
+ _events.ScheduleEvent(EVENT_THROW_DAGGER, Seconds(1));
}
- void KillAllElites()
+ void DoAction(int32 actionId) override
{
- ThreatContainer::StorageType const &threatList = me->getThreatManager().getThreatList();
- std::vector<Unit*> eliteList;
- for (ThreatContainer::StorageType::const_iterator itr = threatList.begin(); itr != threatList.end(); ++itr)
+ if (actionId == ACTION_START_OUTRO)
{
- Unit* unit = ObjectAccessor::GetUnit(*me, (*itr)->getUnitGuid());
- if (unit && unit->GetEntry() == ILLIDARI_ELITE)
- eliteList.push_back(unit);
+ _events.Reset();
+ me->SetReactState(REACT_PASSIVE);
+ me->AttackStop();
+ if (Creature* illidan = _instance->GetCreature(DATA_ILLIDAN_STORMRAGE))
+ me->SetFacingToObject(illidan);
+ Talk(SAY_MAIEV_SHADOWSONG_FINISHED);
+ _events.ScheduleEvent(EVENT_MAIEV_OUTRO_TEXT, Seconds(28));
}
- for (std::vector<Unit*>::const_iterator itr = eliteList.begin(); itr != eliteList.end(); ++itr)
- (*itr)->setDeathState(JUST_DIED);
- EnterEvadeMode(EVADE_REASON_OTHER);
+ else if (actionId == ACTION_MAIEV_DOWN_FADE)
+ _canDown = true;
}
- void BeginTalk()
+ void DamageTaken(Unit* /*who*/, uint32 &damage) override
{
- if (Creature* illidan = ObjectAccessor::GetCreature(*me, IllidanGUID))
+ if (damage >= me->GetHealth() && _canDown)
{
- illidan->RemoveAurasDueToSpell(SPELL_KNEEL);
- me->SetInFront(illidan);
- illidan->SetInFront(me);
- me->GetMotionMaster()->MoveIdle();
- illidan->GetMotionMaster()->MoveIdle();
- ENSURE_AI(boss_illidan_stormrage::boss_illidan_stormrageAI, illidan->AI())->AkamaGUID = me->GetGUID();
- ENSURE_AI(boss_illidan_stormrage::boss_illidan_stormrageAI, illidan->AI())->EnterPhase(PHASE_TALK_SEQUENCE);
+ damage = me->GetHealth() - 1;
+ _canDown = false;
+ DoCastSelf(SPELL_MAIEV_DOWN, true);
+ Talk(SAY_MAIEV_SHADOWSONG_DOWN, me);
}
}
- void BeginChannel()
+ void UpdateAI(uint32 diff) override
{
- me->setActive(true);
- me->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP);
- if (!JustCreated)
+ if (!UpdateVictim() && !_events.IsInPhase(PHASE_INTRO))
return;
- float x, y, z;
- if (GameObject* gate = ObjectAccessor::GetGameObject(*me, GateGUID))
- gate->GetPosition(x, y, z);
- else
- return; // if door not spawned, don't crash server
- if (Creature* Channel = me->SummonCreature(ILLIDAN_DOOR_TRIGGER, x, y, z+5, 0, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 360000))
- {
- ChannelGUID = Channel->GetGUID();
- Channel->SetDisplayId(MODEL_INVISIBLE); // Invisible but spell visuals can still be seen.
- DoCast(Channel, SPELL_AKAMA_DOOR_FAIL);
- }
+ if (me->HasUnitState(UNIT_STATE_CASTING))
+ return;
- for (uint8 i = 0; i < 2; ++i)
- if (Creature* Spirit = me->SummonCreature(i ? SPIRIT_OF_OLUM : SPIRIT_OF_UDALO, SpiritSpawns[i].x, SpiritSpawns[i].y, SpiritSpawns[i].z, 0, TEMPSUMMON_TIMED_DESPAWN, 20000))
+ _events.Update(diff);
+
+ while (uint32 eventId = _events.ExecuteEvent())
+ {
+ switch (eventId)
{
- Spirit->SetVisible(false);
- SpiritGUID[i] = Spirit->GetGUID();
+ case EVENT_MAIEV_APPEAR:
+ Talk(SAY_MAIEV_SHADOWSONG_APPEAR);
+ break;
+ case EVENT_MAIEV_EXCLAMATION:
+ me->HandleEmoteCommand(EMOTE_ONESHOT_EXCLAMATION);
+ break;
+ case EVENT_MAIEV_JUSTICE_TEXT:
+ Talk(SAY_MAIEV_SHADOWSONG_JUSTICE);
+ _events.ScheduleEvent(EVENT_MAIEV_YES, Seconds(2));
+ break;
+ case EVENT_MAIEV_YES:
+ me->HandleEmoteCommand(EMOTE_ONESHOT_YES);
+ _events.ScheduleEvent(EVENT_MAIEV_ROAR, Seconds(3));
+ break;
+ case EVENT_MAIEV_ROAR:
+ me->HandleEmoteCommand(EMOTE_ONESHOT_ROAR);
+ _events.ScheduleEvent(EVENT_MAIEV_COMBAT, Seconds(3));
+ break;
+ case EVENT_MAIEV_COMBAT:
+ me->SetReactState(REACT_AGGRESSIVE);
+ if (Creature* illidan = _instance->GetCreature(DATA_ILLIDAN_STORMRAGE))
+ AttackStart(illidan);
+ break;
+ case EVENT_CAGE_TRAP:
+ if (Creature* illidan = _instance->GetCreature(DATA_ILLIDAN_STORMRAGE))
+ illidan->CastSpell(illidan, SPELL_CAGED_TRAP_TELEPORT, true);
+ DoCastSelf(SPELL_CAGE_TRAP_SUMMON);
+ Talk(SAY_MAIEV_SHADOWSONG_TRAP);
+ _events.Repeat(Seconds(30));
+ break;
+ case EVENT_SHADOW_STRIKE:
+ DoCastVictim(SPELL_SHADOW_STRIKE);
+ _events.Repeat(Seconds(50));
+ break;
+ case EVENT_THROW_DAGGER:
+ if (Unit* target = me->GetVictim())
+ if (!me->IsWithinMeleeRange(target))
+ {
+ DoCastVictim(SPELL_THROW_DAGGER);
+ _events.Repeat(Seconds(5));
+ break;
+ }
+ _events.Repeat(Seconds(1));
+ break;
+ case EVENT_TAUNT:
+ Talk(SAY_MAIEV_SHADOWSONG_TAUNT);
+ _events.Repeat(Seconds(30), Seconds(60));
+ break;
+ case EVENT_MAIEV_OUTRO_TEXT:
+ Talk(SAY_MAIEV_SHADOWSONG_OUTRO);
+ _events.ScheduleEvent(EVENT_MAIEV_FAREWELL_TEXT, Seconds(11));
+ break;
+ case EVENT_MAIEV_FAREWELL_TEXT:
+ Talk(SAY_MAIEV_SHADOWSONG_FAREWELL);
+ _events.ScheduleEvent(EVENT_MAIEV_TELEPORT_DESPAWN, Seconds(3));
+ break;
+ case EVENT_MAIEV_TELEPORT_DESPAWN:
+ DoCastSelf(SPELL_TELEPORT_VISUAL);
+ me->DespawnOrUnsummon(Seconds(1));
+ break;
+ default:
+ break;
}
+
+ if (me->HasUnitState(UNIT_STATE_CASTING))
+ return;
+ }
+
+ DoMeleeAttackIfReady();
+ }
+
+ private:
+ EventMap _events;
+ InstanceScript* _instance;
+ bool _canDown;
+ };
+
+ CreatureAI* GetAI(Creature* creature) const override
+ {
+ return GetBlackTempleAI<npc_maievAI>(creature);
+ }
+};
+
+class npc_cage_trap_trigger : public CreatureScript
+{
+public:
+ npc_cage_trap_trigger() : CreatureScript("npc_cage_trap_trigger") { }
+
+ struct npc_cage_trap_triggerAI : public PassiveAI
+ {
+ npc_cage_trap_triggerAI(Creature* creature) : PassiveAI(creature) { }
+
+ void Reset() override
+ {
+ _scheduler.Schedule(Seconds(1), [this](TaskContext checkTarget)
+ {
+ DoCastSelf(SPELL_CAGE_TRAP_PERIODIC);
+ checkTarget.Repeat();
+ });
}
- void BeginWalk()
+ void UpdateAI(uint32 diff) override
{
- me->SetWalk(false);
- me->SetSpeedRate(MOVE_RUN, 1.0f);
- me->GetMotionMaster()->MovePoint(0, AkamaWP[WalkCount].x, AkamaWP[WalkCount].y, AkamaWP[WalkCount].z);
+ _scheduler.Update(diff);
}
- void EnterPhase(PhaseAkama NextPhase)
+ private:
+ TaskScheduler _scheduler;
+ };
+
+ CreatureAI* GetAI(Creature* creature) const override
+ {
+ return GetBlackTempleAI<npc_cage_trap_triggerAI>(creature);
+ }
+};
+
+// 41077 - Akama Teleport
+class spell_illidan_akama_teleport : public SpellScriptLoader
+{
+ public:
+ spell_illidan_akama_teleport() : SpellScriptLoader("spell_illidan_akama_teleport") { }
+
+ class spell_illidan_akama_teleport_SpellScript : public SpellScript
{
- switch (NextPhase)
+ PrepareSpellScript(spell_illidan_akama_teleport_SpellScript);
+
+ void SetDest(SpellDestination& dest)
{
- case PHASE_CHANNEL:
- BeginChannel();
- Timer = 5000;
- ChannelCount = 0;
- break;
- case PHASE_WALK:
- if (Phase == PHASE_CHANNEL)
- WalkCount = 0;
- else if (Phase == PHASE_TALK)
- {
- if (Creature* illidan = ObjectAccessor::GetCreature(*me, IllidanGUID))
- ENSURE_AI(boss_illidan_stormrage::boss_illidan_stormrageAI, illidan->AI())->DeleteFromThreatList(me->GetGUID());
- EnterEvadeMode(EVADE_REASON_OTHER);
- me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE);
- ++WalkCount;
- }
- JustCreated = false;
- BeginWalk();
- Timer = 0;
- break;
- case PHASE_TALK:
- if (Phase == PHASE_WALK)
- {
- BeginTalk();
- Timer = 0;
- }
- else if (Phase == PHASE_FIGHT_ILLIDAN)
- {
- Timer = 1;
- TalkCount = 0;
- }
- break;
- case PHASE_FIGHT_ILLIDAN:
- if (Creature* illidan = ObjectAccessor::GetCreature(*me, IllidanGUID))
+ if (Creature* caster = GetCaster()->ToCreature())
{
- me->AddThreat(illidan, 10000000.0f);
- me->GetMotionMaster()->MoveChase(illidan);
+ uint32 destination = caster->AI()->GetData(DATA_AKAMA_TELEPORT_POSITION);
+ dest.Relocate(AkamaTeleportPositions[destination]);
}
- Timer = 30000; // chain lightning
- break;
- case PHASE_FIGHT_MINIONS:
- me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE);
- Timer = urand(10000, 16000); // summon minion
- break;
- case PHASE_RETURN:
- me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE);
- KillAllElites();
- WalkCount = 0;
- BeginWalk();
- Timer = 1;
- break;
- default:
- break;
- }
- Phase = NextPhase;
- }
-
- void HandleTalkSequence()
- {
- switch (TalkCount)
- {
- case 0:
- if (Creature* illidan = ObjectAccessor::GetCreature(*me, IllidanGUID))
- {
- ENSURE_AI(boss_illidan_stormrage::boss_illidan_stormrageAI, illidan->AI())->Timer[EVENT_TAUNT] += 30000;
- illidan->AI()->Talk(SAY_ILLIDAN_MINION);
- }
- Timer = 8000;
- break;
- case 1:
- Talk(SAY_AKAMA_LEAVE);
- Timer = 3000;
- break;
- case 2:
- EnterPhase(PHASE_WALK);
- break;
}
- ++TalkCount;
+
+ void Register() override
+ {
+ OnDestinationTargetSelect += SpellDestinationTargetSelectFn(spell_illidan_akama_teleport_SpellScript::SetDest, EFFECT_0, TARGET_DEST_NEARBY_ENTRY);
+ }
+ };
+
+ SpellScript* GetSpellScript() const override
+ {
+ return new spell_illidan_akama_teleport_SpellScript();
}
+};
- void HandleChannelSequence()
+// 41268 - Quest - Black Temple - Akama - Door Open
+class spell_illidan_akama_door_channel : public SpellScriptLoader
+{
+ public:
+ spell_illidan_akama_door_channel() : SpellScriptLoader("spell_illidan_akama_door_channel") { }
+
+ class spell_illidan_akama_door_channel_AuraScript : public AuraScript
{
- Unit* Channel = NULL;
- Unit* Spirit[2] = { NULL, NULL };
- if (ChannelCount <= 5)
+ PrepareAuraScript(spell_illidan_akama_door_channel_AuraScript);
+
+ bool Validate(SpellInfo const* /*spell*/) override
{
- Channel = ObjectAccessor::GetUnit(*me, ChannelGUID);
- Spirit[0] = ObjectAccessor::GetUnit(*me, SpiritGUID[0]);
- Spirit[1] = ObjectAccessor::GetUnit(*me, SpiritGUID[1]);
- if (!Channel || !Spirit[0] || !Spirit[1])
- return;
+ if (!sSpellMgr->GetSpellInfo(SPELL_ARCANE_EXPLOSION))
+ return false;
+ return true;
}
- switch (ChannelCount)
- {
- case 0: // channel failed
- me->InterruptNonMeleeSpells(true);
- Timer = 2000;
- break;
- case 1: // spirit appear
- Spirit[0]->SetVisible(true);
- Spirit[1]->SetVisible(true);
- Timer = 2000;
- break;
- case 2: // spirit help
- DoCast(Channel, SPELL_AKAMA_DOOR_CHANNEL);
- Spirit[0]->CastSpell(Channel, SPELL_DEATHSWORN_DOOR_CHANNEL, false);
- Spirit[1]->CastSpell(Channel, SPELL_DEATHSWORN_DOOR_CHANNEL, false);
- Timer = 5000;
- break;
- case 3: // open the gate
- me->InterruptNonMeleeSpells(true);
- Spirit[0]->InterruptNonMeleeSpells(true);
- Spirit[1]->InterruptNonMeleeSpells(true);
- instance->HandleGameObject(GateGUID, true);
- Timer = 2000;
- break;
- case 4:
- me->HandleEmoteCommand(EMOTE_ONESHOT_SALUTE);
- Timer = 2000;
- break;
- case 5:
- Talk(SAY_AKAMA_BEWARE);
- Channel->setDeathState(JUST_DIED);
- Spirit[0]->SetVisible(false);
- Spirit[1]->SetVisible(false);
- Timer = 3000;
- break;
- case 6:
- EnterPhase(PHASE_WALK);
- break;
- default:
- break;
- }
- ++ChannelCount;
- }
-
- void HandleWalkSequence()
- {
- switch (WalkCount)
- {
- case 8:
- if (Phase == PHASE_WALK)
- EnterPhase(PHASE_TALK);
- else
- EnterPhase(PHASE_FIGHT_ILLIDAN);
- break;
- case 12:
- EnterPhase(PHASE_FIGHT_MINIONS);
- break;
+ void OnRemoveDummy(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
+ {
+ Unit* target = GetTarget();
+ target->CastSpell(target, SPELL_ARCANE_EXPLOSION, true);
+
+ if (InstanceScript* instance = target->GetInstanceScript())
+ if (Creature* akama = instance->GetCreature(DATA_AKAMA))
+ akama->AI()->DoAction(ACTION_OPEN_DOOR);
}
- if (Phase == PHASE_WALK)
+ void Register() override
{
- Timer = 0;
- ++WalkCount;
- me->GetMotionMaster()->MovePoint(WalkCount, AkamaWP[WalkCount].x, AkamaWP[WalkCount].y, AkamaWP[WalkCount].z);
+ AfterEffectRemove += AuraEffectRemoveFn(spell_illidan_akama_door_channel_AuraScript::OnRemoveDummy, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL);
}
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_illidan_akama_door_channel_AuraScript();
}
+};
- void UpdateAI(uint32 diff) override
+// 40904 - Draw Soul
+class spell_illidan_draw_soul : public SpellScriptLoader
+{
+ public:
+ spell_illidan_draw_soul() : SpellScriptLoader("spell_illidan_draw_soul") { }
+
+ class spell_illidan_draw_soul_SpellScript : public SpellScript
{
- if (!me->IsVisible())
+ PrepareSpellScript(spell_illidan_draw_soul_SpellScript);
+
+ bool Validate(SpellInfo const* /*spellInfo*/) override
{
- if (Check_Timer <= diff)
- {
- if (instance->GetBossState(DATA_ILLIDARI_COUNCIL) == DONE)
- me->SetVisible(true);
+ if (!sSpellMgr->GetSpellInfo(SPELL_DRAW_SOUL_HEAL))
+ return false;
+ return true;
+ }
- Check_Timer = 5000;
- } else Check_Timer -= diff;
+ void HandleScriptEffect(SpellEffIndex effIndex)
+ {
+ PreventHitDefaultEffect(effIndex);
+ GetHitUnit()->CastSpell(GetCaster(), SPELL_DRAW_SOUL_HEAL, true);
}
- bool Event = false;
- if (Timer)
+
+ void Register() override
{
- if (Timer <= diff)
- Event = true;
- else Timer -= diff;
+ OnEffectHitTarget += SpellEffectFn(spell_illidan_draw_soul_SpellScript::HandleScriptEffect, EFFECT_1, SPELL_EFFECT_SCRIPT_EFFECT);
}
+ };
+
+ SpellScript* GetSpellScript() const override
+ {
+ return new spell_illidan_draw_soul_SpellScript();
+ }
+};
+
+/* 41917 - Parasitic Shadowfiend
+ 41914 - Parasitic Shadowfiend */
+class spell_illidan_parasitic_shadowfiend : public SpellScriptLoader
+{
+ public:
+ spell_illidan_parasitic_shadowfiend() : SpellScriptLoader("spell_illidan_parasitic_shadowfiend") { }
+
+ class spell_illidan_parasitic_shadowfiend_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_illidan_parasitic_shadowfiend_AuraScript);
- if (Event)
+ bool Validate(SpellInfo const* /*spellInfo*/) override
{
- switch (Phase)
- {
- case PHASE_CHANNEL:
- if (JustCreated)
- HandleChannelSequence();
- else{
- EnterPhase(PHASE_WALK);
- }
- break;
- case PHASE_TALK:
- HandleTalkSequence();
- break;
- case PHASE_WALK:
- case PHASE_RETURN:
- HandleWalkSequence();
- break;
- case PHASE_FIGHT_ILLIDAN:
- {
- Creature* illidan = ObjectAccessor::GetCreature(*me, IllidanGUID);
- if (illidan && illidan->HealthBelowPct(90))
- EnterPhase(PHASE_TALK);
- else
- {
- DoCastVictim(SPELL_CHAIN_LIGHTNING);
- Timer = 30000;
- }
- }
- break;
- case PHASE_FIGHT_MINIONS:
- {
- float x, y, z;
- me->GetPosition(x, y, z);
- Creature* Elite = me->SummonCreature(ILLIDARI_ELITE, x + rand32() % 10, y + rand32() % 10, z, 0, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, 30000);
- // Creature* Elite = me->SummonCreature(ILLIDARI_ELITE, x, y, z, 0, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, 30000);
- if (Elite)
- {
- Elite->AI()->AttackStart(me);
- Elite->AddThreat(me, 1000000.0f);
- AttackStart(Elite);
- me->AddThreat(Elite, 1000000.0f);
- }
- Timer = urand(10000, 16000);
- if (Creature* illidan = ObjectAccessor::GetCreature(*me, IllidanGUID))
- if (illidan->HealthBelowPct(10))
- EnterPhase(PHASE_RETURN);
- }
- break;
- default:
- break;
- }
+ if (!sSpellMgr->GetSpellInfo(SPELL_SUMMON_PARASITIC_SHADOWFIENDS))
+ return false;
+ return true;
}
- if (!UpdateVictim())
- return;
+ void HandleEffectRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
+ {
+ Unit* target = GetTarget();
+ target->CastSpell(target, SPELL_SUMMON_PARASITIC_SHADOWFIENDS, true);
+ }
- if (HealthBelowPct(20))
- DoCast(me, SPELL_HEALING_POTION);
+ void Register() override
+ {
+ AfterEffectRemove += AuraEffectRemoveFn(spell_illidan_parasitic_shadowfiend_AuraScript::HandleEffectRemove, EFFECT_0, SPELL_AURA_PERIODIC_DAMAGE, AURA_EFFECT_HANDLE_REAL);
+ }
+ };
- DoMeleeAttackIfReady();
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_illidan_parasitic_shadowfiend_AuraScript();
}
+};
- void sGossipSelect(Player* player, uint32 /*menuId*/, uint32 /*gossipListId*/) override
+/* 39635 - Throw Glaive
+ 39849 - Throw Glaive */
+class spell_illidan_throw_warglaive : public SpellScriptLoader
+{
+ public:
+ spell_illidan_throw_warglaive() : SpellScriptLoader("spell_illidan_throw_warglaive") { }
+
+ class spell_illidan_throw_warglaive_SpellScript : public SpellScript
{
- CloseGossipMenuFor(player);
- EnterPhase(PHASE_CHANNEL);
- }
+ PrepareSpellScript(spell_illidan_throw_warglaive_SpellScript);
- private:
- bool JustCreated;
- InstanceScript* instance;
- PhaseAkama Phase;
- uint32 Timer;
- ObjectGuid IllidanGUID;
- ObjectGuid ChannelGUID;
- ObjectGuid SpiritGUID[2];
- ObjectGuid GateGUID;
- uint32 ChannelCount;
- uint32 WalkCount;
- uint32 TalkCount;
- uint32 Check_Timer;
- };
+ void HandleDummy(SpellEffIndex /*effIndex*/)
+ {
+ Unit* target = GetHitUnit();
+ target->m_Events.AddEvent(new SummonWarglaiveEvent(target), target->m_Events.CalculateTime(1000));
+ }
- CreatureAI* GetAI(Creature* creature) const override
- {
- return GetInstanceAI<npc_akama_illidanAI>(creature);
- }
+ void Register() override
+ {
+ OnEffectHitTarget += SpellEffectFn(spell_illidan_throw_warglaive_SpellScript::HandleDummy, EFFECT_0, SPELL_EFFECT_DUMMY);
+ }
+ };
+
+ SpellScript* GetSpellScript() const override
+ {
+ return new spell_illidan_throw_warglaive_SpellScript();
+ }
};
-void boss_illidan_stormrage::boss_illidan_stormrageAI::Reset()
+// 39857 - Tear of Azzinoth Summon Channel
+class spell_illidan_tear_of_azzinoth_channel : public SpellScriptLoader
{
- _Reset();
+ public:
+ spell_illidan_tear_of_azzinoth_channel() : SpellScriptLoader("spell_illidan_tear_of_azzinoth_channel") { }
- if (Creature* akama = ObjectAccessor::GetCreature(*me, AkamaGUID))
- {
- if (!akama->IsAlive())
- akama->Respawn();
- else
- akama->AI()->EnterEvadeMode();
- }
+ class spell_illidan_tear_of_azzinoth_channel_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_illidan_tear_of_azzinoth_channel_AuraScript);
- Initialize();
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_UNCAGED_WRATH))
+ return false;
+ return true;
+ }
- me->SetDisplayId(MODEL_ILLIDAN);
- me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC);
- me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE);
- me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
- SetEquipmentSlots(false, EQUIP_UNEQUIP, EQUIP_UNEQUIP, EQUIP_NO_CHANGE);
- me->SetDisableGravity(false);
- me->setActive(false);
-}
+ void OnPeriodic(AuraEffect const* /*aurEff*/)
+ {
+ PreventDefaultAction();
+ if (Unit* caster = GetCaster())
+ {
+ Unit* target = GetTarget();
+ if (caster->GetDistance2d(target) > 25.0f)
+ {
+ target->CastSpell(target, SPELL_UNCAGED_WRATH, true);
+ Remove();
+ }
+ }
+ }
-void boss_illidan_stormrage::boss_illidan_stormrageAI::JustSummoned(Creature* summon)
-{
- summons.Summon(summon);
- switch (summon->GetEntry())
- {
- case PARASITIC_SHADOWFIEND:
- {
- if (Phase == PHASE_TALK_SEQUENCE)
+ void Register() override
{
- summon->SetVisible(false);
- summon->setDeathState(JUST_DIED);
- return;
+ OnEffectPeriodic += AuraEffectPeriodicFn(spell_illidan_tear_of_azzinoth_channel_AuraScript::OnPeriodic, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL);
}
- Unit* target = SelectTarget(SELECT_TARGET_TOPAGGRO, 0, 999, true);
- if (!target || target->HasAura(SPELL_PARASITIC_SHADOWFIEND)
- || target->HasAura(SPELL_PARASITIC_SHADOWFIEND2))
- target = SelectTarget(SELECT_TARGET_RANDOM, 0, 999, true);
- if (target)
- summon->AI()->AttackStart(target);
- }
- break;
- case SHADOW_DEMON:
- if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 999, true)) // only on players.
+ };
+
+ AuraScript* GetAuraScript() const override
{
- summon->AddThreat(target, 5000000.0f);
- summon->AI()->AttackStart(target);
+ return new spell_illidan_tear_of_azzinoth_channel_AuraScript();
}
- break;
- case MAIEV_SHADOWSONG:
+};
+
+// 40631 - Flame Blast
+class spell_illidan_flame_blast : public SpellScriptLoader
+{
+ public:
+ spell_illidan_flame_blast() : SpellScriptLoader("spell_illidan_flame_blast") { }
+
+ class spell_illidan_flame_blast_SpellScript : public SpellScript
{
- summon->SetVisible(false); // Leave her invisible until she has to talk
- summon->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE);
- MaievGUID = summon->GetGUID();
- ENSURE_AI(boss_maiev_shadowsong::boss_maievAI, summon->AI())->GetIllidanGUID(me->GetGUID());
- summon->AI()->DoAction(PHASE_TALK_SEQUENCE);
- }
- break;
- case FLAME_OF_AZZINOTH:
+ PrepareSpellScript(spell_illidan_flame_blast_SpellScript);
+
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_BLAZE_SUMMON))
+ return false;
+ return true;
+ }
+
+ void HandleBlaze(SpellEffIndex /*effIndex*/)
+ {
+ Unit* target = GetHitUnit();
+ target->CastSpell(target, SPELL_BLAZE_SUMMON, true);
+ }
+
+ void Register() override
+ {
+ OnEffectHitTarget += SpellEffectFn(spell_illidan_flame_blast_SpellScript::HandleBlaze, EFFECT_0, SPELL_EFFECT_SCHOOL_DAMAGE);
+ }
+ };
+
+ SpellScript* GetSpellScript() const override
{
- summon->AI()->AttackStart(summon->SelectNearestTarget(999));
+ return new spell_illidan_flame_blast_SpellScript();
}
- break;
- default:
- break;
- }
-}
+};
-void boss_illidan_stormrage::boss_illidan_stormrageAI::HandleTalkSequence()
+// 39873 - Glaive Returns
+class spell_illidan_return_glaives : public SpellScriptLoader
{
- switch (TalkCount)
- {
- case 0:
- me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
- break;
- case 8:
- // Equip our warglaives!
- SetEquipmentSlots(false, EQUIP_ID_MAIN_HAND, EQUIP_ID_OFF_HAND, EQUIP_NO_CHANGE);
- me->SetSheath(SHEATH_STATE_MELEE);
- me->SetWalk(false);
- break;
- case 9:
- if (Creature* akama = ObjectAccessor::GetCreature(*me, AkamaGUID))
- {
- me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE + UNIT_FLAG_NOT_SELECTABLE);
- me->AddThreat(akama, 100.0f);
- ENSURE_AI(npc_akama_illidan::npc_akama_illidanAI, akama->AI())->EnterPhase(PHASE_FIGHT_ILLIDAN);
- EnterPhase(PHASE_NORMAL);
- }
- break;
- case 10:
- SummonMaiev();
- break;
- case 11:
- if (Creature* maiev = ObjectAccessor::GetCreature(*me, MaievGUID))
- {
- maiev->SetVisible(true); // Maiev is now visible
- maiev->CastSpell(maiev, SPELL_TELEPORT_VISUAL, true); // onoz she looks like she teleported!
- maiev->SetInFront(me); // Have her face us
- me->SetInFront(maiev); // Face her, so it's not rude =P
- maiev->GetMotionMaster()->MoveIdle();
- me->GetMotionMaster()->MoveIdle();
- }
- break;
- case 14:
- if (Creature* maiev = ObjectAccessor::GetCreature(*me, MaievGUID))
- {
- me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE + UNIT_FLAG_NOT_SELECTABLE);
- maiev->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE + UNIT_FLAG_NOT_SELECTABLE);
- maiev->AddThreat(me, 10000000.0f); // Have Maiev add a lot of threat on us so that players don't pull her off if they damage her via AOE
- maiev->AI()->AttackStart(me); // Force Maiev to attack us.
- EnterPhase(PHASE_NORMAL_MAIEV);
- }
- break;
- case 15:
- DoCast(me, SPELL_DEATH); // Animate his kneeling + stun him
- summons.DespawnAll();
- break;
- case 17:
- if (Creature* akama = ObjectAccessor::GetCreature(*me, AkamaGUID))
- {
- if (!me->IsWithinDistInMap(akama, 15))
- {
- float x, y, z;
- me->GetPosition(x, y, z);
- x += 10; y += 10;
- akama->GetMotionMaster()->Clear(false);
- // Akama->GetMotionMaster()->MoveIdle();
- akama->SetPosition(x, y, z, 0.0f);
- akama->MonsterMoveWithSpeed(x, y, z, 0); // Illidan must not die until Akama arrives.
- akama->GetMotionMaster()->MoveChase(me);
- }
- }
- break;
- case 19: // Make Maiev leave
- if (Creature* maiev = ObjectAccessor::GetCreature(*me, MaievGUID))
- {
- maiev->CastSpell(maiev, SPELL_TELEPORT_VISUAL, true);
- maiev->setDeathState(JUST_DIED);
- me->SetUInt32Value(UNIT_FIELD_BYTES_1, UNIT_STAND_STATE_DEAD);
- }
- break;
- case 21: // Kill ourself.
- me->DealDamage(me, me->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false);
- break;
- default:
- break;
- }
- if (Phase == PHASE_TALK_SEQUENCE)
- Talk(TalkCount); // This function does most of the talking
- ++TalkCount;
-}
+ public: spell_illidan_return_glaives() : SpellScriptLoader("spell_illidan_return_glaives") { }
-class npc_cage_trap_trigger : public CreatureScript
-{
-public:
- npc_cage_trap_trigger() : CreatureScript("npc_cage_trap_trigger") { }
+ class spell_illidan_return_glaives_SpellScript : public SpellScript
+ {
+ PrepareSpellScript(spell_illidan_return_glaives_SpellScript);
- struct cage_trap_triggerAI : public ScriptedAI
- {
- cage_trap_triggerAI(Creature* creature) : ScriptedAI(creature)
+ void HandleScriptEffect(SpellEffIndex /*effIndex*/)
+ {
+ GetHitUnit()->SendPlaySpellVisual(SPELL_GLAIVE_VISUAL_KIT);
+ if (Creature* caster = GetCaster()->ToCreature())
+ caster->DespawnOrUnsummon();
+ }
+
+ void Register() override
+ {
+ OnEffectHitTarget += SpellEffectFn(spell_illidan_return_glaives_SpellScript::HandleScriptEffect, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT);
+ }
+ };
+
+ SpellScript* GetSpellScript() const override
{
- Initialize();
+ return new spell_illidan_return_glaives_SpellScript();
}
+};
+
+// 40834 - Agonizing Flames
+class spell_illidan_agonizing_flames : public SpellScriptLoader
+{
+ public:
+ spell_illidan_agonizing_flames() : SpellScriptLoader("spell_illidan_agonizing_flames") { }
- void Initialize()
+ class spell_illidan_agonizing_flames_SpellScript : public SpellScript
{
- IllidanGUID.Clear();
+ PrepareSpellScript(spell_illidan_agonizing_flames_SpellScript);
+
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_AGONIZING_FLAMES))
+ return false;
+ return true;
+ }
- Active = false;
- SummonedBeams = false;
+ void FilterTargets(std::list<WorldObject*>& targets)
+ {
+ if (targets.empty())
+ return;
+
+ WorldObject* target = Trinity::Containers::SelectRandomContainerElement(targets);
+ targets.clear();
+ targets.push_back(target);
+ }
- DespawnTimer = 0;
+ void HandleScript(SpellEffIndex /*effIndex*/)
+ {
+ GetCaster()->CastSpell(GetHitUnit(), SPELL_AGONIZING_FLAMES, true);
+ }
+
+ void Register() override
+ {
+ OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_illidan_agonizing_flames_SpellScript::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY);
+ OnEffectHitTarget += SpellEffectFn(spell_illidan_agonizing_flames_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_DUMMY);
+ }
+ };
+
+ SpellScript* GetSpellScript() const override
+ {
+ return new spell_illidan_agonizing_flames_SpellScript();
}
+};
- void Reset() override
+// 40511 - Demon Transform 1
+class spell_illidan_demon_transform1 : public SpellScriptLoader
+{
+ public:
+ spell_illidan_demon_transform1() : SpellScriptLoader("spell_illidan_demon_transform1") { }
+
+ class spell_illidan_demon_transform1_AuraScript : public AuraScript
{
- Initialize();
+ PrepareAuraScript(spell_illidan_demon_transform1_AuraScript);
- me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
- }
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_DEMON_TRANSFORM_2))
+ return false;
+ return true;
+ }
- void EnterCombat(Unit* /*who*/) override { }
+ void OnPeriodic(AuraEffect const* /*aurEff*/)
+ {
+ PreventDefaultAction();
+ GetTarget()->CastSpell(GetTarget(), SPELL_DEMON_TRANSFORM_2, true);
+ Remove();
+ }
- void MoveInLineOfSight(Unit* who) override
+ void Register() override
+ {
+ OnEffectPeriodic += AuraEffectPeriodicFn(spell_illidan_demon_transform1_AuraScript::OnPeriodic, EFFECT_1, SPELL_AURA_PERIODIC_TRIGGER_SPELL);
+ }
+ };
+ AuraScript* GetAuraScript() const override
{
- if (!Active)
- return;
+ return new spell_illidan_demon_transform1_AuraScript();
+ }
+};
- if (who && (who->GetTypeId() != TYPEID_PLAYER))
+// 40398 - Demon Transform 2
+class spell_illidan_demon_transform2 : public SpellScriptLoader
+{
+ public:
+ spell_illidan_demon_transform2() : SpellScriptLoader("spell_illidan_demon_transform2") { }
+
+ class spell_illidan_demon_transform2_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_illidan_demon_transform2_AuraScript);
+
+ bool Validate(SpellInfo const* /*spellInfo*/) override
{
- if (who->GetEntry() == ILLIDAN_STORMRAGE) // Check if who is Illidan
+ if (!sSpellMgr->GetSpellInfo(SPELL_DEMON_FORM)
+ || !sSpellMgr->GetSpellInfo(SPELL_DEMON_TRANSFORM_3))
+ return false;
+ return true;
+ }
+
+ void OnPeriodic(AuraEffect const* aurEff)
+ {
+ PreventDefaultAction();
+ Unit* target = GetTarget();
+
+ if (aurEff->GetTickNumber() == 1)
{
- if (!IllidanGUID && me->IsWithinDistInMap(who, 3) && (!who->HasAura(SPELL_CAGED)))
- {
- IllidanGUID = who->GetGUID();
- who->CastSpell(who, SPELL_CAGED, true);
- DespawnTimer = 5000;
- if (who->HasAura(SPELL_ENRAGE))
- who->RemoveAurasDueToSpell(SPELL_ENRAGE); // Dispel his enrage
- // if (GameObject* CageTrap = instance->instance->GetGameObject(instance->GetGuidData(CageTrapGUID)))
-
- // CageTrap->SetLootState(GO_JUST_DEACTIVATED);
- }
+ if (target->GetDisplayId() == target->GetNativeDisplayId())
+ target->CastSpell(target, SPELL_DEMON_FORM, true);
+ else
+ target->RemoveAurasDueToSpell(SPELL_DEMON_FORM);
+ }
+ else if (aurEff->GetTickNumber() == 2)
+ {
+ target->CastSpell(target, SPELL_DEMON_TRANSFORM_3, true);
+ if (Aura* aura = GetUnitOwner()->GetAura(SPELL_DEMON_TRANSFORM_3))
+ aura->SetDuration(4300);
+ Remove();
}
}
- }
- void UpdateAI(uint32 diff) override
- {
- if (DespawnTimer)
+ void Register() override
{
- if (DespawnTimer <= diff)
- me->DealDamage(me, me->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false);
- else DespawnTimer -= diff;
+ OnEffectPeriodic += AuraEffectPeriodicFn(spell_illidan_demon_transform2_AuraScript::OnPeriodic, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL);
}
+ };
- // if (IllidanGUID && !SummonedBeams)
- // {
- // if (Unit* Illidan = ObjectAccessor::GetUnit(*me, IllidanGUID)
- // {
- // /// @todo Find proper spells and properly apply 'caged' Illidan effect
- // }
- // }
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_illidan_demon_transform2_AuraScript();
}
+};
+// 41126 - Flame Burst
+class spell_illidan_flame_burst : public SpellScriptLoader
+{
public:
- bool Active;
- private:
- ObjectGuid IllidanGUID;
- uint32 DespawnTimer;
- bool SummonedBeams;
- };
+ spell_illidan_flame_burst() : SpellScriptLoader("spell_illidan_flame_burst") { }
- CreatureAI* GetAI(Creature* creature) const override
- {
- return new cage_trap_triggerAI(creature);
- }
-};
+ class spell_illidan_flame_burst_SpellScript : public SpellScript
+ {
+ PrepareSpellScript(spell_illidan_flame_burst_SpellScript);
-class gameobject_cage_trap : public GameObjectScript
-{
-public:
- gameobject_cage_trap() : GameObjectScript("gameobject_cage_trap") { }
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_FLAME_BURST_EFFECT))
+ return false;
+ return true;
+ }
- bool OnGossipHello(Player* player, GameObject* go) override
- {
- float x, y, z;
- player->GetPosition(x, y, z);
+ void HandleScriptEffect(SpellEffIndex /*effIndex*/)
+ {
+ GetHitUnit()->CastSpell(GetHitUnit(), SPELL_FLAME_BURST_EFFECT, true);
+ }
- // Grid search for nearest live Creature of entry 23304 within 10 yards
- if (Creature* pTrigger = go->FindNearestCreature(23304, 10.0f))
- ENSURE_AI(npc_cage_trap_trigger::cage_trap_triggerAI, pTrigger->AI())->Active = true;
- go->SetGoState(GO_STATE_ACTIVE);
- return true;
- }
+ void Register() override
+ {
+ OnEffectHitTarget += SpellEffectFn(spell_illidan_flame_burst_SpellScript::HandleScriptEffect, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT);
+ }
+ };
+
+ SpellScript* GetSpellScript() const override
+ {
+ return new spell_illidan_flame_burst_SpellScript();
+ }
};
-class npc_shadow_demon : public CreatureScript
+// 41081 - Find Target
+class spell_illidan_find_target : public SpellScriptLoader
{
-public:
- npc_shadow_demon() : CreatureScript("npc_shadow_demon") { }
+ public:
+ spell_illidan_find_target() : SpellScriptLoader("spell_illidan_find_target") { }
- struct shadow_demonAI : public ScriptedAI
- {
- shadow_demonAI(Creature* creature) : ScriptedAI(creature) { }
+ class spell_illidan_find_target_SpellScript : public SpellScript
+ {
+ PrepareSpellScript(spell_illidan_find_target_SpellScript);
- void EnterCombat(Unit* /*who*/) override
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_PARALYZE))
+ return false;
+ return true;
+ }
+
+ void FilterTargets(std::list<WorldObject*>& targets)
+ {
+ targets.remove_if(Trinity::UnitAuraCheck(true, SPELL_PARALYZE));
+
+ if (targets.empty())
+ return;
+
+ WorldObject* target = Trinity::Containers::SelectRandomContainerElement(targets);
+ targets.clear();
+ targets.push_back(target);
+ }
+
+ void HandleScript(SpellEffIndex /*effIndex*/)
+ {
+ Unit* target = GetHitUnit();
+ if (Creature* caster = GetCaster()->ToCreature())
+ {
+ caster->CastSpell(target, SPELL_PARALYZE, true);
+ caster->ClearUnitState(UNIT_STATE_CASTING);
+ caster->AI()->SetGUID(target->GetGUID(), 0);
+ }
+ }
+
+ void Register() override
+ {
+ OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_illidan_find_target_SpellScript::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY);
+ OnEffectHitTarget += SpellEffectFn(spell_illidan_find_target_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_DUMMY);
+ }
+ };
+
+ SpellScript* GetSpellScript() const override
{
- DoZoneInCombat();
+ return new spell_illidan_find_target_SpellScript();
}
+};
- void Reset() override
+// 39908 - Eye Blast
+class spell_illidan_eye_blast : public SpellScriptLoader
+{
+ public:
+ spell_illidan_eye_blast() : SpellScriptLoader("spell_illidan_eye_blast") { }
+
+ class spell_illidan_eye_blast_AuraScript : public AuraScript
{
- TargetGUID.Clear();
- DoCast(me, SPELL_SHADOW_DEMON_PASSIVE, true);
- }
+ PrepareAuraScript(spell_illidan_eye_blast_AuraScript);
- void JustDied(Unit* /*killer*/) override
+ void HandleEffectRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
+ {
+ if (Creature* target = GetTarget()->ToCreature())
+ target->DespawnOrUnsummon();
+ }
+
+ void Register() override
+ {
+ AfterEffectRemove += AuraEffectRemoveFn(spell_illidan_eye_blast_AuraScript::HandleEffectRemove, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
{
- if (Unit* target = ObjectAccessor::GetUnit(*me, TargetGUID))
- target->RemoveAurasDueToSpell(SPELL_PARALYZE);
+ return new spell_illidan_eye_blast_AuraScript();
}
+};
- void UpdateAI(uint32 /*diff*/) override
- {
- if (!UpdateVictim() || !me->GetVictim())
- return;
+// 40761 - Cage Trap
+class spell_illidan_cage_trap : public SpellScriptLoader
+{
+ public:
+ spell_illidan_cage_trap() : SpellScriptLoader("spell_illidan_cage_trap") { }
- if (me->EnsureVictim()->GetTypeId() != TYPEID_PLAYER)
- return; // Only cast the below on players.
+ class spell_illidan_cage_trap_SpellScript : public SpellScript
+ {
+ PrepareSpellScript(spell_illidan_cage_trap_SpellScript);
- if (!me->EnsureVictim()->HasAura(SPELL_PARALYZE))
+ void HandleScriptEffect(SpellEffIndex /*effIndex*/)
{
- TargetGUID = me->EnsureVictim()->GetGUID();
- me->AddThreat(me->GetVictim(), 10000000.0f);
- DoCastVictim(SPELL_PURPLE_BEAM, true);
- DoCastVictim(SPELL_PARALYZE, true);
+ Creature* target = GetHitCreature();
+ Creature* caster = GetCaster()->ToCreature();
+
+ if (!target || !caster)
+ return;
+
+ if (caster->GetDistance2d(target) < 4.0f)
+ {
+ target->AI()->DoAction(ACTION_ILLIDAN_CAGED);
+ caster->DespawnOrUnsummon();
+ if (GameObject* trap = target->FindNearestGameObject(GO_ILLIDAN_CAGE_TRAP, 10.0f))
+ trap->UseDoorOrButton();
+ }
}
- // Kill our target if we're very close.
- if (me->IsWithinDistInMap(me->GetVictim(), 3))
- DoCastVictim(SPELL_CONSUME_SOUL);
- }
- private:
- ObjectGuid TargetGUID;
- };
+ void Register() override
+ {
+ OnEffectHitTarget += SpellEffectFn(spell_illidan_cage_trap_SpellScript::HandleScriptEffect, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT);
+ }
+ };
- CreatureAI* GetAI(Creature* creature) const override
- {
- return new shadow_demonAI(creature);
- }
+ SpellScript* GetSpellScript() const override
+ {
+ return new spell_illidan_cage_trap_SpellScript();
+ }
};
-class npc_blade_of_azzinoth : public CreatureScript
+// 40760 - Cage Trap
+class spell_illidan_caged : public SpellScriptLoader
{
-public:
- npc_blade_of_azzinoth() : CreatureScript("npc_blade_of_azzinoth") { }
+ public:
+ spell_illidan_caged() : SpellScriptLoader("spell_illidan_caged") { }
- struct blade_of_azzinothAI : public NullCreatureAI
- {
- blade_of_azzinothAI(Creature* creature) : NullCreatureAI(creature) { }
+ class spell_illidan_caged_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_illidan_caged_AuraScript);
- void SpellHit(Unit* /*caster*/, const SpellInfo* spell) override
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_CAGED_DEBUFF))
+ return false;
+ return true;
+ }
+
+ void OnPeriodic(AuraEffect const* /*aurEff*/)
+ {
+ PreventDefaultAction();
+ Unit* target = GetTarget();
+ target->CastSpell(target, SPELL_CAGED_DEBUFF, true);
+ Remove();
+ }
+
+ void Register() override
+ {
+ OnEffectPeriodic += AuraEffectPeriodicFn(spell_illidan_caged_AuraScript::OnPeriodic, EFFECT_1, SPELL_AURA_PERIODIC_TRIGGER_SPELL);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
{
- if (spell->Id == SPELL_THROW_GLAIVE2 || spell->Id == SPELL_THROW_GLAIVE)
- me->SetDisplayId(MODEL_BLADE);// appear when hit by Illidan's glaive
+ return new spell_illidan_caged_AuraScript();
}
- };
-
- CreatureAI* GetAI(Creature* creature) const override
- {
- return new blade_of_azzinothAI(creature);
- }
};
-class npc_parasitic_shadowfiend : public CreatureScript
+// 40409 - Maiev Down
+class spell_maiev_down : public SpellScriptLoader
{
public:
- npc_parasitic_shadowfiend() : CreatureScript("npc_parasitic_shadowfiend") { }
+ spell_maiev_down() : SpellScriptLoader("spell_maiev_down") { }
- // Shadowfiends interact with Illidan, setting more targets in Illidan's hashmap
- struct npc_parasitic_shadowfiendAI : public ScriptedAI
+ class spell_maiev_down_AuraScript : public AuraScript
{
- npc_parasitic_shadowfiendAI(Creature* creature) : ScriptedAI(creature)
+ PrepareAuraScript(spell_maiev_down_AuraScript);
+
+ bool Load() override
{
- Initialize();
- instance = creature->GetInstanceScript();
+ return GetUnitOwner()->GetTypeId() == TYPEID_UNIT;
}
- void Initialize()
+ void HandleEffectApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
{
- CheckTimer = 5000;
+ GetTarget()->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
}
- void Reset() override
+ void HandleEffectRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
{
- IllidanGUID = instance->GetGuidData(DATA_ILLIDAN_STORMRAGE);
-
- Initialize();
- DoCast(me, SPELL_SHADOWFIEND_PASSIVE, true);
+ GetTarget()->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
+ GetTarget()->GetAI()->DoAction(ACTION_MAIEV_DOWN_FADE);
}
- void EnterCombat(Unit* /*who*/) override
+ void Register() override
{
- DoZoneInCombat();
+ OnEffectApply += AuraEffectApplyFn(spell_maiev_down_AuraScript::HandleEffectApply, EFFECT_1, SPELL_AURA_MOD_STUN, AURA_EFFECT_HANDLE_REAL);
+ AfterEffectRemove += AuraEffectRemoveFn(spell_maiev_down_AuraScript::HandleEffectRemove, EFFECT_1, SPELL_AURA_MOD_STUN, AURA_EFFECT_HANDLE_REAL);
}
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_maiev_down_AuraScript();
+ }
+};
- void DoMeleeAttackIfReady()
+// 40693 - Cage Trap
+class spell_illidan_cage_teleport : public SpellScriptLoader
+{
+ public:
+ spell_illidan_cage_teleport() : SpellScriptLoader("spell_illidan_cage_teleport") { }
+
+ class spell_illidan_cage_teleport_SpellScript : public SpellScript
{
- if (me->isAttackReady() && me->IsWithinMeleeRange(me->GetVictim()))
+ PrepareSpellScript(spell_illidan_cage_teleport_SpellScript);
+
+ void SetDest(SpellDestination& dest)
{
- if (!me->EnsureVictim()->HasAura(SPELL_PARASITIC_SHADOWFIEND)
- && !me->EnsureVictim()->HasAura(SPELL_PARASITIC_SHADOWFIEND2))
- {
- if (Creature* illidan = ObjectAccessor::GetCreature((*me), IllidanGUID))// summon only in 1. phase
- if (ENSURE_AI(boss_illidan_stormrage::boss_illidan_stormrageAI, illidan->AI())->Phase == PHASE_NORMAL)
- me->CastSpell(me->GetVictim(), SPELL_PARASITIC_SHADOWFIEND2, true, 0, 0, IllidanGUID); // do not stack
- }
- me->AttackerStateUpdate(me->GetVictim());
- me->resetAttackTimer();
+ Position offset = { 0.0f, 0.0f, GetCaster()->GetPositionZ(), 0.0f };
+ dest.RelocateOffset(offset);
+ }
+
+ void Register() override
+ {
+ OnDestinationTargetSelect += SpellDestinationTargetSelectFn(spell_illidan_cage_teleport_SpellScript::SetDest, EFFECT_0, TARGET_DEST_CASTER_RADIUS);
}
+ };
+
+ SpellScript* GetSpellScript() const override
+ {
+ return new spell_illidan_cage_teleport_SpellScript();
}
+};
- void UpdateAI(uint32 diff) override
+// 41242 - Akama Despawn
+class spell_illidan_despawn_akama : public SpellScriptLoader
+{
+ public:
+ spell_illidan_despawn_akama() : SpellScriptLoader("spell_illidan_despawn_akama") { }
+
+ class spell_illidan_despawn_akama_SpellScript : public SpellScript
{
- if (!me->GetVictim())
+ PrepareSpellScript(spell_illidan_despawn_akama_SpellScript);
+
+ void HandleDummy(SpellEffIndex /*effIndex*/)
{
- if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 999, true))
- AttackStart(target);
- else
- {
- me->DespawnOrUnsummon();
- return;
- }
+ if (Creature* target = GetHitCreature())
+ target->DespawnOrUnsummon(Seconds(1));
}
- if (CheckTimer <= diff)
+ void Register() override
{
- Creature* illidan = ObjectAccessor::GetCreature(*me, IllidanGUID);
- if (!illidan || illidan->IsInEvadeMode())
- {
- me->DespawnOrUnsummon();
- return;
- }
- else
- CheckTimer = 5000;
+ OnEffectHitTarget += SpellEffectFn(spell_illidan_despawn_akama_SpellScript::HandleDummy, EFFECT_0, SPELL_EFFECT_DUMMY);
}
- else
- CheckTimer -= diff;
+ };
- DoMeleeAttackIfReady();
+ SpellScript* GetSpellScript() const override
+ {
+ return new spell_illidan_despawn_akama_SpellScript();
}
-
- private:
- InstanceScript* instance;
- ObjectGuid IllidanGUID;
- uint32 CheckTimer;
- };
-
- CreatureAI* GetAI(Creature* creature) const override
- {
- return GetInstanceAI<npc_parasitic_shadowfiendAI>(creature);
- }
};
void AddSC_boss_illidan()
{
new boss_illidan_stormrage();
- new npc_akama_illidan();
- new boss_maiev_shadowsong();
- new npc_flame_of_azzinoth();
+ new npc_akama();
+ new npc_parasitic_shadowfiend();
new npc_blade_of_azzinoth();
- new gameobject_cage_trap();
+ new npc_flame_of_azzinoth();
+ new npc_illidan_db_target();
+ new npc_maiev();
+ new npc_illidan_shadow_demon();
new npc_cage_trap_trigger();
- new npc_shadow_demon();
- new npc_parasitic_shadowfiend();
+ new spell_illidan_akama_teleport();
+ new spell_illidan_akama_door_channel();
+ new spell_illidan_draw_soul();
+ new spell_illidan_parasitic_shadowfiend();
+ new spell_illidan_throw_warglaive();
+ new spell_illidan_tear_of_azzinoth_channel();
+ new spell_illidan_flame_blast();
+ new spell_illidan_return_glaives();
+ new spell_illidan_agonizing_flames();
+ new spell_illidan_demon_transform1();
+ new spell_illidan_demon_transform2();
+ new spell_illidan_flame_burst();
+ new spell_illidan_find_target();
+ new spell_illidan_eye_blast();
+ new spell_illidan_cage_trap();
+ new spell_illidan_caged();
+ new spell_maiev_down();
+ new spell_illidan_cage_teleport();
+ new spell_illidan_despawn_akama();
}
diff --git a/src/server/scripts/Outland/BlackTemple/instance_black_temple.cpp b/src/server/scripts/Outland/BlackTemple/instance_black_temple.cpp
index b8c11a06092..35b80e4a47a 100644
--- a/src/server/scripts/Outland/BlackTemple/instance_black_temple.cpp
+++ b/src/server/scripts/Outland/BlackTemple/instance_black_temple.cpp
@@ -48,7 +48,7 @@ BossBoundaryData const boundaries =
{ DATA_RELIQUARY_OF_SOULS, new ZRangeBoundary(81.8f, 148.0f) },
{ DATA_MOTHER_SHAHRAZ, new RectangleBoundary(903.4f, 982.1f, 92.4f, 313.2f) },
{ DATA_ILLIDARI_COUNCIL, new EllipseBoundary(Position(696.6f, 305.0f), 70.0 , 85.0) },
- { DATA_ILLIDAN_STORMRAGE, new EllipseBoundary(Position(694.8f, 309.0f), 70.0 , 85.0) }
+ { DATA_ILLIDAN_STORMRAGE, new EllipseBoundary(Position(694.8f, 309.0f), 80.0 , 95.0) }
};
ObjectData const creatureData[] =
@@ -70,6 +70,7 @@ ObjectData const creatureData[] =
{ NPC_VERAS_DARKSHADOW, DATA_VERAS_DARKSHADOW },
{ NPC_BLOOD_ELF_COUNCIL_VOICE, DATA_BLOOD_ELF_COUNCIL_VOICE },
{ NPC_BLACK_TEMPLE_TRIGGER, DATA_BLACK_TEMPLE_TRIGGER },
+ { NPC_MAIEV_SHADOWSONG, DATA_MAIEV },
{ 0, 0 } // END
};
@@ -94,6 +95,7 @@ class instance_black_temple : public InstanceMapScript
LoadDoorData(doorData);
LoadObjectData(creatureData, gameObjectData);
LoadBossBoundaries(boundaries);
+ akamaState = AKAMA_INTRO;
}
void OnGameObjectCreate(GameObject* go) override
@@ -127,6 +129,30 @@ class instance_black_temple : public InstanceMapScript
}
}
+ uint32 GetData(uint32 data) const override
+ {
+ if (data == DATA_AKAMA)
+ return akamaState;
+
+ return 0;
+ }
+
+ void SetData(uint32 data, uint32 value) override
+ {
+ switch (data)
+ {
+ case DATA_AKAMA:
+ akamaState = value;
+ break;
+ case ACTION_OPEN_DOOR:
+ if (GameObject* illidanGate = GetGameObject(DATA_GO_ILLIDAN_GATE))
+ HandleGameObject(ObjectGuid::Empty, true, illidanGate);
+ break;
+ default:
+ break;
+ }
+ }
+
bool SetBossState(uint32 type, EncounterState state) override
{
if (!InstanceScript::SetBossState(type, state))
@@ -157,6 +183,11 @@ class instance_black_temple : public InstanceMapScript
HandleGameObject(ObjectGuid::Empty, true, door);
}
break;
+ case DATA_ILLIDARI_COUNCIL:
+ if (state == DONE)
+ if (Creature* akama = GetCreature(DATA_AKAMA))
+ akama->AI()->DoAction(ACTION_ACTIVE_AKAMA_INTRO);
+ break;
default:
break;
}
@@ -171,8 +202,10 @@ class instance_black_temple : public InstanceMapScript
return false;
return true;
}
+
protected:
GuidVector AshtongueGUIDs;
+ uint8 akamaState;
};
InstanceScript* GetInstanceScript(InstanceMap* map) const override