diff options
Diffstat (limited to 'src')
10 files changed, 2275 insertions, 2639 deletions
diff --git a/src/bindings/scripts/scripts/zone/black_temple/boss_illidan.cpp b/src/bindings/scripts/scripts/zone/black_temple/boss_illidan.cpp index 8005387b04e..48e0bc86ab2 100644 --- a/src/bindings/scripts/scripts/zone/black_temple/boss_illidan.cpp +++ b/src/bindings/scripts/scripts/zone/black_temple/boss_illidan.cpp @@ -17,17 +17,21 @@ /* ScriptData
SDName: boss_illidan_stormrage
SD%Complete: 90
-SDComment:
+SDComment: Somewhat of a workaround for Parasitic Shadowfiend, unable to summon GOs for Cage Trap.
SDCategory: Black Temple
EndScriptData */
#include "precompiled.h"
#include "def_black_temple.h"
-#include "WorldPacket.h"
+
+#define GETGO(obj, guid) GameObject* obj = GameObject::GetGameObject(*m_creature, guid)
+#define GETUNIT(unit, guid) Unit* unit = Unit::GetUnit(*m_creature, guid)
+#define GETCRE(cre, guid) Creature* cre = (Creature*)Unit::GetUnit(*m_creature, guid)
+#define HPPCT(unit) unit->GetHealth()*100 / unit->GetMaxHealth()
/************* Quotes and Sounds ***********************/
// Gossip for when a player clicks Akama
-#define GOSSIP_ITEM "We are ready to face Illidan"
+#define GOSSIP_ITEM "We are ready to face Illidan"
// Yells for/by Akama
#define SAY_AKAMA_BEWARE "Be wary friends, The Betrayer meditates in the court just beyond."
@@ -63,63 +67,74 @@ EndScriptData */ /************** Spells *************/
// Normal Form
-#define SPELL_SHEAR 41032 // Reduces Max. Health by 60% for 7 seconds. Can stack 19 times. 1.5 second cast
-#define SPELL_FLAME_CRASH 40832 // Summons an invis/unselect passive mob that has an aura of flame in a circle around him.
-#define SPELL_DRAW_SOUL 40904 // 5k Shadow Damage in front of him. Heals Illidan for 100k health (script effect)
-#define SPELL_PARASITIC_SHADOWFIEND 41917 // DoT of 3k Shadow every 2 seconds. Lasts 10 seconds. (Script effect: Summon 2 parasites once the debuff has ticked off)
-#define SPELL_SUMMON_PARASITICS 41915 // Summons 2 Parasitic Shadowfiends on the target. It's supposed to be cast as soon as the Parasitic Shadowfiend debuff is gone, but the spells aren't linked :(
-#define SPELL_AGONIZING_FLAMES 40932 // 4k fire damage initial to target and anyone w/i 5 yards. PHASE 3 ONLY
-#define SPELL_ENRAGE 40683 // Increases damage by 50% and attack speed by 30%. 20 seconds, PHASE 5 ONLY
+#define SPELL_SHEAR 37335 // 41032 is bugged, cannot be block/dodge/parry// Reduces Max. Health by 60% for 7 seconds. Can stack 19 times. 1.5 second cast
+#define SPELL_FLAME_CRASH 40832 // Summons an invis/unselect passive mob that has an aura of flame in a circle around him.
+#define SPELL_DRAW_SOUL 40904 // 5k Shadow Damage in front of him. Heals Illidan for 100k health (script effect)
+#define SPELL_PARASITIC_SHADOWFIEND 41917 // DoT of 3k Shadow every 2 seconds. Lasts 10 seconds. (Script effect: Summon 2 parasites once the debuff has ticked off)
+#define SPELL_SUMMON_PARASITICS 41915 // Summons 2 Parasitic Shadowfiends on the target. It's supposed to be cast as soon as the Parasitic Shadowfiend debuff is gone, but the spells aren't linked :(
+#define SPELL_AGONIZING_FLAMES 40932 // 4k fire damage initial to target and anyone w/i 5 yards. PHASE 3 ONLY
+#define SPELL_ENRAGE 40683 // Increases damage by 50% and attack speed by 30%. 20 seconds, PHASE 5 ONLY
// Flying (Phase 2)
-#define SPELL_THROW_GLAIVE 39635 // Throws a glaive on the ground
-#define SPELL_THROW_GLAIVE2 39849 // Animation for the above spell
-#define SPELL_GLAIVE_RETURNS 39873 // Glaive flies back to Illidan
-#define SPELL_FIREBALL 40598 // 2.5k-3.5k damage in 10 yard radius. 2 second cast time.
-#define SPELL_DARK_BARRAGE 40585 // 10 second channeled spell, 3k shadow damage per second.
+#define SPELL_THROW_GLAIVE 39635 // Throws a glaive on the ground
+#define SPELL_THROW_GLAIVE2 39849 // Animation for the above spell
+#define SPELL_GLAIVE_RETURNS 39873 // Glaive flies back to Illidan
+#define SPELL_FIREBALL 40598 // 2.5k-3.5k damage in 10 yard radius. 2 second cast time.
+#define SPELL_DARK_BARRAGE 40585 // 10 second channeled spell, 3k shadow damage per second.
// Demon Form
-#define SPELL_DEMON_TRANSFORM_1 40511 // First phase of animations for transforming into Dark Illidan (fall to ground)
-#define SPELL_DEMON_TRANSFORM_2 40398 // Second phase of animations (kneel)
-#define SPELL_DEMON_TRANSFORM_3 40510 // Final phase of animations (stand up and roar)
-#define SPELL_DEMON_FORM 40506 // Transforms into Demon Illidan. Has an Aura of Dread on him.
-#define SPELL_SHADOW_BLAST 41078 // 8k - 11k Shadow Damage. Targets highest threat. Has a splash effect, damaging anyone in 20 yards of the target.
-#define SPELL_FLAME_BURST 41126 // Hurls fire at entire raid for ~3.5k damage every 10 seconds. Resistable. (Does not work: Script effect)
-#define SPELL_FLAME_BURST_EFFECT 41131 // The actual damage. Handled by core (41126 triggers 41131)
+#define SPELL_DEMON_TRANSFORM_1 40511 // First phase of animations for transforming into Dark Illidan (fall to ground)
+#define SPELL_DEMON_TRANSFORM_2 40398 // Second phase of animations (kneel)
+#define SPELL_DEMON_TRANSFORM_3 40510 // Final phase of animations (stand up and roar)
+#define SPELL_DEMON_FORM 40506 // Transforms into Demon Illidan. Has an Aura of Dread on him.
+#define SPELL_SHADOW_BLAST 41078 // 8k - 11k Shadow Damage. Targets highest threat. Has a splash effect, damaging anyone in 20 yards of the target.
+#define SPELL_FLAME_BURST 41126 // Hurls fire at entire raid for ~3.5k damage every 10 seconds. Resistable. (Does not work: Script effect)
+#define SPELL_FLAME_BURST_EFFECT 41131 // The actual damage. Have each player cast it on itself (workaround)
// Other Illidan spells
-#define SPELL_KNEEL 39656 // Before beginning encounter, this is how he appears (talking to Wilson).
-#define SPELL_SHADOW_PRISON 40647 // Illidan casts this spell to immobilize entire raid when he summons Maiev.
-#define SPELL_DEATH 41220 // This spell doesn't do anything except stun Illidan and set him on his knees.
-#define SPELL_BERSERK 45078 // Damage increased by 500%, attack speed by 150%
-
-// Non-Illidan spells
-#define SPELL_AKAMA_DOOR_CHANNEL 41268 // Akama's channel spell on the door before the Temple Summit
-#define SPELL_DEATHSWORN_DOOR_CHANNEL 41269 // Olum and Udalo's channel spell on the door before the Temple Summit
-#define SPELL_AKAMA_DOOR_FAIL 41271 // Not sure where this is really used...
-#define SPELL_HEALING_POTION 40535 // Akama uses this to heal himself to full.
-#define SPELL_AZZINOTH_CHANNEL 39857 // Glaives cast it on Flames. Not sure if this is the right spell.
-#define SPELL_SHADOW_DEMON_PASSIVE 41079 // Adds the "shadowform" aura to Shadow Demons.
-#define SPELL_CONSUME_SOUL 41080 // Once the Shadow Demons reach their target, they use this to kill them
-#define SPELL_PARALYZE 41083 // Shadow Demons cast this on their target
-#define SPELL_PURPLE_BEAM 39123 // Purple Beam connecting Shadow Demon to their target
-#define SPELL_CAGE_TRAP_DUMMY 40761 // Put this in DB for cage trap GO.
-#define SPELL_EYE_BLAST_TRIGGER 40017 // This summons Demon Form every few seconds and deals ~20k damage in its radius
-#define SPELL_EYE_BLAST 39908 // This does the blue flamey animation.
-#define SPELL_FLAME_CRASH_EFFECT 40836 // Firey blue ring of circle that the other flame crash summons
-#define SPELL_BLAZE_EFFECT 40610 // Green flame on the ground, triggers damage (5k) every few seconds
-#define SPELL_BLAZE_SUMMON 40637 // Summons the Blaze creature
-#define SPELL_DEMON_FIRE 40029 // Blue fire trail left by Eye Blast. Deals 2k per second if players stand on it.
-#define SPELL_CAGED 40695 // Caged Trap triggers will cast this on Illidan if he is within 3 yards
-#define SPELL_CAGE_TRAP_SUMMON 40694 // Summons a Cage Trap GO (bugged) on the ground along with a Cage Trap Disturb Trigger mob (working)
-#define SPELL_CAGE_TRAP_BEAM 40713 // 8 Triggers on the ground in an octagon cast spells like this on Illidan 'caging him'
-#define SPELL_FLAME_BLAST 40631 // Flames of Azzinoth use this. Frontal cone AoE 7k-9k damage.
-#define SPELL_CHARGE 40602 // Flames of Azzinoth charges whoever is too far from them. They enrage after this. For simplicity, we'll use the same enrage as Illidan.
-#define SPELL_TELEPORT_VISUAL 41232 // Teleport visual for Maiev
-#define SPELL_SHADOWFIEND_PASSIVE 41913 // Passive aura for shadowfiends
+#define SPELL_KNEEL 39656 // Before beginning encounter, this is how he appears (talking to skully).
+#define SPELL_SHADOW_PRISON 40647 // Illidan casts this spell to immobilize entire raid when he summons Maiev.
+#define SPELL_DEATH 41220 // This spell doesn't do anything except stun Illidan and set him on his knees.
+#define SPELL_BERSERK 45078 // Damage increased by 500%, attack speed by 150%
+#define SPELL_DUAL_WIELD 42459
+//Phase Normal spells
+#define SPELL_FLAME_CRASH_EFFECT 40836 // Firey blue ring of circle that the other flame crash summons
+#define SPELL_SHADOWFIEND_PASSIVE 41913 // Passive aura for shadowfiends
+#define SPELL_SHADOW_DEMON_PASSIVE 41079 // Adds the "shadowform" aura to Shadow Demons.
+#define SPELL_CONSUME_SOUL 41080 // Once the Shadow Demons reach their target, they use this to kill them
+#define SPELL_PARALYZE 41083 // Shadow Demons cast this on their target
+#define SPELL_PURPLE_BEAM 39123 // Purple Beam connecting Shadow Demon to their target
+//Phase Flight spells
+#define SPELL_AZZINOTH_CHANNEL 39857 // Glaives cast it on Flames. Not sure if this is the right spell.
+#define SPELL_EYE_BLAST_TRIGGER 40017 // This summons Demon Form every few seconds and deals ~20k damage in its radius
+#define SPELL_EYE_BLAST 39908 // This does the blue flamey animation.
+#define SPELL_BLAZE_EFFECT 40610 // Green flame on the ground, triggers damage (5k) every few seconds
+#define SPELL_BLAZE_SUMMON 40637 // Summons the Blaze creature
+#define SPELL_DEMON_FIRE 40029 // Blue fire trail left by Eye Blast. Deals 2k per second if players stand on it.
+#define SPELL_FLAME_BLAST 40631 // Flames of Azzinoth use this. Frontal cone AoE 7k-9k damage.
+#define SPELL_CHARGE 41581 //40602 // Flames of Azzinoth charges whoever is too far from them. They enrage after this. For simplicity, we'll use the same enrage as Illidan.
+#define SPELL_FLAME_ENRAGE 45078
+//Akama spells
+#define SPELL_AKAMA_DOOR_CHANNEL 41268 // Akama's channel spell on the door before the Temple Summit
+#define SPELL_DEATHSWORN_DOOR_CHANNEL 41269 // Olum and Udalo's channel spell on the door before the Temple Summit
+#define SPELL_AKAMA_DOOR_FAIL 41271 // Not sure where this is really used...
+#define SPELL_HEALING_POTION 40535 // Akama uses this to heal himself to full.
+#define SPELL_CHAIN_LIGHTNING 40536 // 6938 to 8062 for 5 targets
+//Maiev spells
+#define SPELL_CAGE_TRAP_DUMMY 40761 // Put this in DB for cage trap GO.
+#define SPELL_CAGED 40695 // Caged Trap triggers will cast this on Illidan if he is within 3 yards
+#define SPELL_CAGE_TRAP_SUMMON 40694 // Summons a Cage Trap GO (bugged) on the ground along with a Cage Trap Disturb Trigger mob (working)
+#define SPELL_CAGE_TRAP_BEAM 40713 // 8 Triggers on the ground in an octagon cast spells like this on Illidan 'caging him'
+#define SPELL_TELEPORT_VISUAL 41232 // Teleport visual for Maiev
+#define SPELL_SHADOW_STRIKE 40685 // 4375 to 5625 every 3 seconds for 12 seconds
+#define SPELL_THROW_DAGGER 41152 // 5400 to 6600 damage, need dagger
+#define SPELL_FAN_BLADES 39954 // bugged visual
// Other defines
-#define CENTER_X 676.740
+#define CENTER_X 676.740
#define CENTER_Y 305.297
#define CENTER_Z 353.192
+#define FLAME_ENRAGE_DISTANCE 30
+#define FLAME_CHARGE_DISTANCE 50
+
/**** Creature Summon and Recognition IDs ****/
enum CreatureEntry
{
@@ -141,14 +156,81 @@ enum CreatureEntry };
/*** Phase Names ***/
-enum Phase
+enum PhaseIllidan
+{
+ PHASE_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,
+};//Maiev uses the same phase
+
+enum PhaseAkama
+{
+ PHASE_AKAMA_NULL = 0,
+ PHASE_CHANNEL = 1,
+ PHASE_WALK = 2,
+ PHASE_TALK = 3,
+ PHASE_FIGHT_ILLIDAN = 4,
+ PHASE_FIGHT_MINIONS = 5,
+ PHASE_RETURN = 6,
+};
+
+enum EventIllidan
+{
+ 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,
+};
+
+enum EventMaiev
{
- PHASE_NORMAL = 1,
- PHASE_FLIGHT = 2,
- PHASE_NORMAL_2 = 3,
- PHASE_DEMON = 4,
- PHASE_NORMAL_MAIEV = 5,
- PHASE_DEMON_SEQUENCE = 6,
+ 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 = 5,
+};
+
+static EventIllidan MaxTimer[]=
+{
+ 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
};
struct Yells
@@ -162,7 +244,7 @@ struct Yells static Yells Conversation[]=
{
{11463, "Akama... your duplicity is hardly surprising. I should have slaughtered you and your malformed brethren long ago.", ILLIDAN_STORMRAGE, 8000, 0, true},
- {0, NULL, ILLIDAN_STORMRAGE, 5000, 396, true},
+ {0, NULL, 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, NULL, AKAMA, 5000, 66, true},
{11464, "Boldly said. But I remain unconvinced.", ILLIDAN_STORMRAGE, 8000, 396, true},
@@ -170,20 +252,19 @@ static Yells Conversation[]= {0, NULL, AKAMA, 2000, 15, true},
{11466, "You are not prepared!", ILLIDAN_STORMRAGE, 3000, 406, true},
{0, NULL, EMPTY, 1000, 0, true},
- {0, NULL, EMPTY, 0, 0, false},
+ {0, NULL, 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, 7000, 1, 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},
- {11496, "Ahh... It is finished. You are beaten.", MAIEV_SHADOWSONG, 6000, 0, true},
- { // Emote dead for now. Kill him later
- 11478, "You have won... Maiev...but the huntress... is nothing...without the hunt... you... are nothing... without me..", ILLIDAN_STORMRAGE, 22000, 65, 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, NULL, MAIEV_SHADOWSONG, 0, true},
+ {11498, NULL, MAIEV_SHADOWSONG, 5000, 0, true},
+ {11498, NULL, 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, NULL, EMPTY, 1000, 0, false}
+ {0, NULL, EMPTY, 1000, 0, false}//21
};
static Yells RandomTaunts[]=
@@ -205,62 +286,54 @@ static Yells MaievTaunts[]= struct Locations
{
float x, y, z;
- uint32 id;
+};
+
+static Locations HoverPosition[]=
+{
+ {657, 340, 355},
+ {657, 275, 355},
+ {705, 275, 355},
+ {705, 340, 355}
};
static Locations GlaivePosition[]=
{
{695.105, 305.303, 354.256},
- {659.338, 305.303, 354.256},
+ {659.338, 305.303, 354.256},//the distance between two glaives is 36
{700.105, 305.303, 354.256},
{664.338, 305.303, 354.256}
};
static Locations EyeBlast[]=
{
- {650.697, 320.128, 353.730},
- {652.799, 275.091, 353.367},
- {701.527, 273.815, 353.230},
- {709.865, 325.654, 353.322}
+ {677, 350, 354},//start point, pass through glaive point
+ {677, 260, 354}
};
static Locations AkamaWP[]=
{
- { 770.01, 304.50, 312.29 }, // Bottom of the first stairs, at the doors
- { 780.66, 304.50, 319.74 }, // Top of the first stairs
- { 790.13, 319.68, 319.76 }, // Bottom of the second stairs (left from the entrance)
- { 787.17, 347.38, 341.42 }, // Top of the second stairs
- { 781.34, 350.31, 341.44 }, // Bottom of the third stairs
- { 762.60, 361.06, 353.60 }, // Top of the third stairs
- { 756.35, 360.52, 353.27 }, // Before the door-thingy
- { 743.82, 342.21, 353.00 }, // Somewhere further
- { 732.69, 305.13, 353.00 }, // In front of Illidan
- { 738.11, 365.44, 353.00 }, // in front of the door-thingy (the other one!)
- { 792.18, 366.62, 341.42 }, // Down the first flight of stairs
- { 796.84, 304.89, 319.76 }, // Down the second flight of stairs
- { 782.01, 304.55, 319.76 } // Final location - back at the initial gates. This is where he will fight the minions!
+ {770.01, 304.50, 312.29}, // Bottom of the first stairs, at the doors
+ {780.66, 304.50, 319.74}, // Top of the first stairs
+ {790.13, 319.68, 319.76}, // Bottom of the second stairs (left from the entrance)
+ {787.17, 347.38, 341.42}, // Top of the second stairs
+ {781.34, 350.31, 341.44}, // Bottom of the third stairs
+ {762.60, 361.06, 353.60}, // Top of the third stairs
+ {756.35, 360.52, 353.27}, // Before the door-thingy
+ {743.82, 342.21, 353.00}, // Somewhere further
+ {732.69, 305.13, 353.00}, // In front of Illidan - (8)
+ {738.11, 365.44, 353.00}, // in front of the door-thingy (the other one!)
+ {792.18, 366.62, 341.42}, // Down the first flight of stairs
+ {796.84, 304.89, 319.76}, // Down the second flight of stairs
+ {782.01, 304.55, 319.76} // Final location - back at the initial gates. This is where he will fight the minions! (12)
};
// 755.762, 304.0747, 312.1769 -- This is where Akama should be spawned
static Locations SpiritSpawns[]=
{
- {755.5426, 309.9156, 312.2129, SPIRIT_OF_UDALO},
- {755.5426, 298.7923, 312.0834, SPIRIT_OF_OLUM}
+ {755.5426, 309.9156, 312.2129},
+ {755.5426, 298.7923, 312.0834}
};
-struct WayPoints
-{
- WayPoints(uint32 _id, float _x, float _y, float _z)
- {
- id = _id;
- x = _x;
- y = _y;
- z = _z;
- }
- uint32 id;
- float x, y, z;
-};
-
-struct Animation // For the demon transformation
+struct Animation // For the demon transformation
{
uint32 aura, unaura, timer, size, displayid, phase;
bool equip;
@@ -268,22 +341,24 @@ struct Animation // For the demon tra static Animation DemonTransformation[]=
{
- {SPELL_DEMON_TRANSFORM_1, 0, 1300, 0, 0, 6, true},
+ {SPELL_DEMON_TRANSFORM_1, 0, 1000, 0, 0, 6, true},
{SPELL_DEMON_TRANSFORM_2, SPELL_DEMON_TRANSFORM_1, 4000, 0, 0, 6, true},
- {SPELL_DEMON_FORM, 0, 3000, 1073741824, 21322, 6, false},
+ {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},
- {0, 0, 0, 0, 0, 4, false},
- {SPELL_DEMON_TRANSFORM_1, 0, 1500, 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, 0, 0, 0, 0, 8, true}
+ {0, SPELL_DEMON_TRANSFORM_3, 0, 0, 0, 8, true}
};
-/**** Demon Fire will be used for Eye Blast. Illidan needs to have access to it's vars and functions, so we'll set it here ****/
-struct TRINITY_DLL_DECL demonfireAI : public ScriptedAI
+
+
+/************************************** Illidan's AI ***************************************/
+struct TRINITY_DLL_DECL boss_illidan_stormrageAI : public ScriptedAI
{
- demonfireAI(Creature *c) : ScriptedAI(c)
+ boss_illidan_stormrageAI(Creature* c) : ScriptedAI(c)
{
pInstance = ((ScriptedInstance*)c->GetInstanceData());
Reset();
@@ -291,1644 +366,1334 @@ struct TRINITY_DLL_DECL demonfireAI : public ScriptedAI ScriptedInstance* pInstance;
- uint64 IllidanGUID;
-
- bool IsTrigger;
+ PhaseIllidan Phase;
+ EventIllidan Event;
+ uint32 Timer[EVENT_ENRAGE + 1];
- uint32 CheckTimer;
- uint32 DemonFireTimer;
- uint32 DespawnTimer;
+ uint32 TalkCount;
+ uint32 TransformCount;
+ uint32 FlightCount;
- void Reset()
- {
- IllidanGUID = 0;
+ uint32 HoverPoint;
- IsTrigger = false;
+ uint64 AkamaGUID;
+ uint64 MaievGUID;
+ uint64 FlameGUID[2];
+ uint64 GlaiveGUID[2];
- CheckTimer = 2000;
- DemonFireTimer = 0;
- DespawnTimer = 45000;
- }
+ std::list<uint64> ParasiteTargets; // for safety, do not use Unit*
- void Aggro(Unit *who) {}
- void AttackStart(Unit* who) { }
- void MoveInLineOfSight(Unit *who){ }
+ void Reset();
- void UpdateAI(const uint32 diff)
+ void JustSummoned(Creature* summon)//, TempSummonType type)
{
- if(IsTrigger)
- return;
-
- m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
+ if(summon->GetCreatureInfo()->Entry == FLAME_CRASH)
+ {
+ // type = TEMPSUMMON_TIMED_DESPAWN;
+ }
+ //error_log("justsummoned %d %d", summon->GetCreatureInfo()->Entry, summon->GetGUID());
+ }
- if(CheckTimer < diff)
+ void SummonedCreatureDespawn(Creature* summon)
+ {
+ if(summon->GetCreatureInfo()->Entry == FLAME_OF_AZZINOTH)
{
- if(!IllidanGUID && pInstance)
+ for(uint8 i = 0; i < 2; i++)
+ if(summon->GetGUID() == FlameGUID[i])
+ FlameGUID[i] = 0;
+
+ if(!FlameGUID[0] && !FlameGUID[1])
{
- IllidanGUID = pInstance->GetData64(DATA_ILLIDANSTORMRAGE);
- if(IllidanGUID)
- {
- Unit* Illidan = Unit::GetUnit((*m_creature), IllidanGUID);
- if(Illidan && !Illidan->HasUnitMovementFlag(MOVEMENTFLAG_LEVITATING))
- m_creature->setDeathState(JUST_DIED);
- }
+ m_creature->InterruptNonMeleeSpells(true);
+ EnterPhase(PHASE_FLIGHT_SEQUENCE);
}
- CheckTimer = 2000;
- }else CheckTimer -= diff;
+ }
+ }
- if(DemonFireTimer < diff)
+ void MovementInform(uint32 MovementType, uint32 Data)
+ {
+ if(FlightCount == 7) //change hover point
{
- DoCast(m_creature, SPELL_DEMON_FIRE);
- DemonFireTimer = 30000;
- }else DemonFireTimer -= diff;
-
- if(DespawnTimer < diff)
- m_creature->setDeathState(JUST_DIED);
- else DespawnTimer -= diff;
-
- DoMeleeAttackIfReady();
+ if(m_creature->getVictim())
+ {
+ m_creature->SetInFront(m_creature->getVictim());
+ m_creature->StopMoving();
+ }
+ EnterPhase(PHASE_FLIGHT);
+ }
+ else
+ Timer[EVENT_FLIGHT_SEQUENCE] = 1000;
}
-};
-/******* Functions and vars for Akama's AI ******/
-struct TRINITY_DLL_SPEC npc_akama_illidanAI : public ScriptedAI
-{
- npc_akama_illidanAI(Creature* c) : ScriptedAI(c)
+ void Aggro(Unit *who)
{
- pInstance = ((ScriptedInstance*)c->GetInstanceData());
- WayPointList.clear();
- Reset();
+ DoZoneInCombat();
}
- /* Instance Data */
- ScriptedInstance* pInstance;
-
- /* Timers */
- uint32 ChannelTimer;
- uint32 TalkTimer;
- uint32 WalkTimer;
- uint32 SummonMinionTimer;
-
- /* GUIDs */
- uint64 IllidanGUID;
- uint64 PlayerGUID;
- uint64 SpiritGUID[2];
- uint64 ChannelGUID;
-
- bool IsTalking;
- bool StartChanneling;
- bool DoorOpen;
- bool FightMinions;
- bool IsReturningToIllidan;
- bool IsWalking;
- uint32 TalkCount;
- uint32 ChannelCount;
-
- std::list<WayPoints> WayPointList;
- std::list<WayPoints>::iterator WayPoint;
-
- void BeginEvent(uint64 PlayerGUID);
- void Aggro(Unit *who) {}
-
- void Reset()
+ void AttackStart(Unit *who)
{
- if(pInstance)
+ if(!who || Phase >= PHASE_TALK_SEQUENCE)
+ return;
+
+ if (who->isTargetableForAttack())
{
- pInstance->SetData(DATA_ILLIDANSTORMRAGEEVENT, NOT_STARTED);
- GameObject* Gate = GameObject::GetGameObject((*m_creature), pInstance->GetData64(DATA_GAMEOBJECT_ILLIDAN_GATE));
- if( Gate && !Gate->GetGoState() )
- Gate->SetGoState(1); // close door if already open (when raid wipes or something)
+ if(Phase == PHASE_FLIGHT || Phase == PHASE_DEMON)
+ m_creature->Attack(who, false);
+ else
+ DoStartAttackAndMovement(who);
- for(uint8 i = DATA_GAMEOBJECT_ILLIDAN_DOOR_R; i < DATA_GAMEOBJECT_ILLIDAN_DOOR_L + 1; ++i)
+ if (!InCombat)
{
- GameObject* Door = GameObject::GetGameObject((*m_creature), pInstance->GetData64(i));
- if(Door)
- Door->SetGoState(0);
+ Aggro(who);
+ InCombat = true;
}
}
+ }
- IllidanGUID = 0;
- PlayerGUID = 0;
- ChannelGUID = 0;
- for(uint8 i = 0; i < 2; ++i) SpiritGUID[i] = 0;
+ void MoveInLineOfSight(Unit *who) {}
- ChannelTimer = 0;
- ChannelCount = 0;
- SummonMinionTimer = 2000;
+ void JustDied(Unit *killer)
+ {
+ m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
- WalkTimer = 0;
+ if(!pInstance)
+ return;
- TalkTimer = 0;
- TalkCount = 0;
+ pInstance->SetData(DATA_ILLIDANSTORMRAGEEVENT, DONE); // Completed
- KillAllElites();
+ for(uint8 i = DATA_GAMEOBJECT_ILLIDAN_DOOR_R; i < DATA_GAMEOBJECT_ILLIDAN_DOOR_L + 1; ++i)
+ {
+ GameObject* Door = GameObject::GetGameObject((*m_creature), pInstance->GetData64(i));
+ if(Door)
+ Door->SetUInt32Value(GAMEOBJECT_STATE, 0); // Open Doors
+ }
+ }
- IsReturningToIllidan = false;
- FightMinions = false;
- IsTalking = false;
- StartChanneling = false;
- DoorOpen = false;
+ void KilledUnit(Unit *victim)
+ {
+ if(victim == m_creature) return;
- m_creature->SetUInt32Value(UNIT_NPC_FLAGS, 0); // Database sometimes has strange values..
- m_creature->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP);
- m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE);
- m_creature->SetVisibility(VISIBILITY_ON);
+ switch(rand()%2)
+ {
+ case 0:
+ DoYell(SAY_KILL1, LANG_UNIVERSAL, victim);
+ DoPlaySoundToSet(m_creature, SOUND_KILL1);
+ break;
+ case 1:
+ DoYell(SAY_KILL2, LANG_UNIVERSAL, victim);
+ DoPlaySoundToSet(m_creature, SOUND_KILL2);
+ break;
+ }
}
- // 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()
+ void DamageTaken(Unit *done_by, uint32 &damage)
{
- InCombat = false;
-
- m_creature->RemoveAllAuras();
- m_creature->DeleteThreatList();
- m_creature->CombatStop();
+ if(damage >= m_creature->GetHealth() && done_by != m_creature)
+ damage = 0;
+ if(done_by->GetGUID() == MaievGUID)
+ done_by->AddThreat(m_creature, -(3*(float)damage)/4); // do not let maiev tank him
}
- void KillAllElites()
+ void SpellHit(Unit *caster, const SpellEntry *spell)
{
- std::list<HostilReference*>::iterator itr;
- for(itr = m_creature->getThreatManager().getThreatList().begin(); itr != m_creature->getThreatManager().getThreatList().end(); ++itr)
+ if(spell->Id == SPELL_GLAIVE_RETURNS) // Re-equip our warblades!
{
- Unit* pUnit = Unit::GetUnit((*m_creature), (*itr)->getUnitGuid());
- if(pUnit && (pUnit->GetTypeId() == TYPEID_UNIT) && (pUnit->GetEntry() == ILLIDARI_ELITE))
- pUnit->setDeathState(JUST_DIED);
+ if(!m_creature->GetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_DISPLAY))
+ m_creature->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_DISPLAY, 45479);
+ else
+ m_creature->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_DISPLAY+1, 45481);
+ m_creature->SetByteValue(UNIT_FIELD_BYTES_2, 0, SHEATH_STATE_MELEE );
}
}
- void ReturnToIllidan()
+ void AddParasiteTarget(uint64 targetGUID)
{
- KillAllElites();
- InCombat = false;
- FightMinions = false;
- IsReturningToIllidan = true;
- WayPoint = WayPointList.begin();
- m_creature->SetSpeed(MOVE_RUN, 2.0f);
- m_creature->RemoveUnitMovementFlag(MOVEMENTFLAG_WALK_MODE);
- IsWalking = true;
- }
+ for(std::list<uint64>::iterator tIter = ParasiteTargets.begin(); tIter != ParasiteTargets.end(); tIter++)
+ {
+ if(*tIter == targetGUID)
+ return;
+ }
+ ParasiteTargets.push_back(targetGUID);
- void AddWaypoint(uint32 id, float x, float y, float z)
- {
- WayPoints AkamaWP(id, x, y, z);
- WayPointList.push_back(AkamaWP);
+ if(Phase == PHASE_NORMAL || Phase == PHASE_NORMAL_2 || Phase == PHASE_NORMAL_MAIEV)
+ Timer[EVENT_PARASITE_CHECK] += 1000;
}
- void DamageTaken(Unit *done_by, uint32 &damage)
+ void DeleteFromThreatList(uint64 TargetGUID)
{
- if(damage > m_creature->GetHealth() && (done_by->GetGUID() != m_creature->GetGUID()))
+ for(std::list<HostilReference*>::iterator itr = m_creature->getThreatManager().getThreatList().begin(); itr != m_creature->getThreatManager().getThreatList().end(); ++itr)
{
- damage = 0;
- DoCast(m_creature, SPELL_HEALING_POTION);
+ if((*itr)->getUnitGuid() == TargetGUID)
+ {
+ (*itr)->removeReference();
+ break;
+ }
}
}
- void BeginDoorEvent(Player* player)
+ void Talk(uint32 count)
{
- if(!pInstance)
- return;
+ Timer[EVENT_TALK_SEQUENCE] = Conversation[count].timer;
- outstring_log("SD2: Akama - Door event initiated by player %s", player->GetName());
- PlayerGUID = player->GetGUID();
+ Creature* creature = NULL;
+ if(Conversation[count].creature == ILLIDAN_STORMRAGE)
+ creature = m_creature;
+ else if(Conversation[count].creature == AKAMA)
+ creature = ((Creature*)Unit::GetUnit((*m_creature), AkamaGUID));
+ else if(Conversation[count].creature == MAIEV_SHADOWSONG)
+ creature = ((Creature*)Unit::GetUnit((*m_creature), MaievGUID));
- GameObject* Gate = GameObject::GetGameObject((*m_creature), pInstance->GetData64(DATA_GAMEOBJECT_ILLIDAN_GATE));
- if(Gate)
+ if(creature)
{
- float x,y,z;
- Gate->GetPosition(x, y, z);
- Creature* Channel = m_creature->SummonCreature(ILLIDAN_DOOR_TRIGGER, x, y, z+5, 0, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 360000);
- if(Channel)
+ if(Conversation[count].emote)
+ creature->HandleEmoteCommand(Conversation[count].emote); // Make the creature do some animation!
+ if(Conversation[count].text)
+ creature->Yell(Conversation[count].text, LANG_UNIVERSAL, 0); // Have the creature yell out some text
+ if(Conversation[count].sound)
+ DoPlaySoundToSet(creature, Conversation[count].sound); // Play some sound on the creature
+ }
+ }
+
+ void EnterPhase(PhaseIllidan NextPhase);
+ void CastEyeBlast();
+ void SummonFlamesOfAzzinoth();
+ void SummonMaiev();
+ void SummonShadowDemon()
+ {
+ Creature* ShadowDemon = NULL;
+ Unit* target = NULL;
+ for(uint8 i = 0; i < 4; i++)
+ {
+ ShadowDemon = DoSpawnCreature(SHADOW_DEMON, 0,0,0,0,TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN,25000);
+ if(ShadowDemon)
{
- ChannelGUID = Channel->GetGUID();
- // Invisible but spell visuals can still be seen.
- Channel->SetUInt32Value(UNIT_FIELD_DISPLAYID, 11686);
- Channel->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
- float PosX, PosY, PosZ;
- m_creature->GetPosition(PosX, PosY, PosZ);
- for(uint8 i = 0; i < 2; ++i)
+ target = SelectUnit(SELECT_TARGET_RANDOM, 0);
+ if(target && target->GetTypeId() == TYPEID_PLAYER) // only on players.
{
- Creature* Spirit = m_creature->SummonCreature(SpiritSpawns[i].id, SpiritSpawns[i].x, SpiritSpawns[i].y, SpiritSpawns[i].z, 0, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 360000);
- if(Spirit)
- {
- Spirit->SetVisibility(VISIBILITY_OFF);
- SpiritGUID[i] = Spirit->GetGUID();
- }
+ ShadowDemon->AddThreat(target, 5000000.0f);
+ ShadowDemon->AI()->AttackStart(target);
}
- StartChanneling = true;
- m_creature->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP);
- m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE);
- DoCast(Channel, SPELL_AKAMA_DOOR_FAIL);
+ DoZoneInCombat(ShadowDemon);
}
}
}
-
- void MovementInform(uint32 type, uint32 id)
+ void HandleTalkSequence();
+ void HandleFlightSequence()
{
- if(type != POINT_MOTION_TYPE || !IsWalking)
- return;
-
- if(WayPoint->id != id)
- return;
-
- switch(id)
- {
- case 6:
- if(!IsReturningToIllidan)
- { // open the doors that close the summit
- for(uint32 i = DATA_GAMEOBJECT_ILLIDAN_DOOR_R; i < DATA_GAMEOBJECT_ILLIDAN_DOOR_L+1; ++i)
- {
- GameObject* Door = GameObject::GetGameObject((*m_creature), pInstance->GetData64(i));
- if(Door)
- Door->SetGoState(0);
- }
+ switch(FlightCount)
+ {
+ case 1://lift off
+ m_creature->HandleEmoteCommand(EMOTE_ONESHOT_LIFTOFF);
+ //m_creature->GetMotionMaster()->Clear(false);
+ m_creature->SetUnitMovementFlags(MOVEMENTFLAG_LEVITATING);
+ //m_creature->GetMotionMaster()->MovePoint(0, m_creature->GetPositionX(),m_creature->GetPositionY(),m_creature->GetPositionZ());
+ m_creature->StopMoving();
+ DoYell(SAY_TAKEOFF, LANG_UNIVERSAL, NULL);
+ DoPlaySoundToSet(m_creature, SOUND_TAKEOFF);
+ Timer[EVENT_FLIGHT_SEQUENCE] = 3000;
+ break;
+ case 2://move to center
+ //m_creature->GetMotionMaster()->Clear(false);
+ m_creature->AddUnitMovementFlag(MOVEMENTFLAG_ONTRANSPORT);
+ m_creature->GetMotionMaster()->MovePoint(0, CENTER_X + 5, CENTER_Y, CENTER_Z); //+5, for SPELL_THROW_GLAIVE bug
+ m_creature->RemoveUnitMovementFlag(MOVEMENTFLAG_ONTRANSPORT);
+ Timer[EVENT_FLIGHT_SEQUENCE] = 0;
+ break;
+ case 3://throw one glaive
+ {
+ uint8 i=1;
+ Creature* Glaive = m_creature->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_NON_ATTACKABLE);
+ Glaive->SetUInt32Value(UNIT_FIELD_DISPLAYID, 11686);
+ Glaive->setFaction(m_creature->getFaction());
+ DoCast(Glaive, SPELL_THROW_GLAIVE2);
}
- case 7:
- if(IsReturningToIllidan)
+ }
+ Timer[EVENT_FLIGHT_SEQUENCE] = 700;
+ break;
+ case 4://throw another
+ m_creature->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_DISPLAY, 0);
+ m_creature->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_DISPLAY+1, 0);
+ {
+ uint8 i=0;
+ Creature* Glaive = m_creature->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_NON_ATTACKABLE);
+ Glaive->SetUInt32Value(UNIT_FIELD_DISPLAYID, 11686);
+ Glaive->setFaction(m_creature->getFaction());
+ DoCast(Glaive, SPELL_THROW_GLAIVE, true);
+ }
+ }
+ Timer[EVENT_FLIGHT_SEQUENCE] = 5000;
+ break;
+ case 5://summon flames
+ SummonFlamesOfAzzinoth();
+ Timer[EVENT_FLIGHT_SEQUENCE] = 3000;
+ break;
+ case 6://fly to hover point
+ m_creature->AddUnitMovementFlag(MOVEMENTFLAG_ONTRANSPORT);
+ m_creature->GetMotionMaster()->MovePoint(0, HoverPosition[HoverPoint].x, HoverPosition[HoverPoint].y, HoverPosition[HoverPoint].z);
+ m_creature->RemoveUnitMovementFlag(MOVEMENTFLAG_ONTRANSPORT);
+ Timer[EVENT_FLIGHT_SEQUENCE] = 0;
+ break;
+ case 7://return to center
+ m_creature->AddUnitMovementFlag(MOVEMENTFLAG_ONTRANSPORT);
+ m_creature->GetMotionMaster()->MovePoint(0, CENTER_X, CENTER_Y, CENTER_Z);
+ m_creature->RemoveUnitMovementFlag(MOVEMENTFLAG_ONTRANSPORT);
+ Timer[EVENT_FLIGHT_SEQUENCE] = 0;
+ break;
+ case 8://glaive return
+ for(uint8 i = 0; i < 2; i++)
+ {
+ if(GlaiveGUID[i])
{
- IsWalking = false;
- if(IllidanGUID)
+ Unit* Glaive = Unit::GetUnit((*m_creature), GlaiveGUID[i]);
+ if(Glaive)
{
- Unit* Illidan = Unit::GetUnit((*m_creature), IllidanGUID);
- if(Illidan)
- {
- float dx = Illidan->GetPositionX() + rand()%15;
- float dy = Illidan->GetPositionY() + rand()%15;
- m_creature->GetMotionMaster()->MovePoint(13, dx, dy, Illidan->GetPositionZ());
- m_creature->SetUInt64Value(UNIT_FIELD_TARGET, IllidanGUID);
- }
+ Glaive->CastSpell(m_creature, SPELL_GLAIVE_RETURNS, false); // Make it look like the Glaive flies back up to us
+ Glaive->SetUInt32Value(UNIT_FIELD_DISPLAYID, 11686); // disappear but not die for now
}
}
- break;
- case 8:
- m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE);
- if(!IsReturningToIllidan)
+ }
+ Timer[EVENT_FLIGHT_SEQUENCE] = 2000;
+ break;
+ case 9://land
+ //m_creature->GetMotionMaster()->Clear(false);
+ m_creature->RemoveUnitMovementFlag(MOVEMENTFLAG_LEVITATING);
+ //m_creature->GetMotionMaster()->MovePoint(0, m_creature->GetPositionX(),m_creature->GetPositionY(),m_creature->GetPositionZ());
+ m_creature->StopMoving();
+ m_creature->HandleEmoteCommand(EMOTE_ONESHOT_LAND);
+ for(uint8 i = 0; i < 2; i++)
+ {
+ if(GlaiveGUID[i])
{
- IsWalking = false;
- BeginEvent(PlayerGUID);
+ if(GETUNIT(Glaive, GlaiveGUID[i]))
+ {
+ Glaive->SetVisibility(VISIBILITY_OFF);
+ Glaive->setDeathState(JUST_DIED); // Despawn the Glaive
+ }
+ GlaiveGUID[i] = 0;
}
- break;
- case 12:
- IsWalking = false;
- FightMinions = true;
- m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE);
- break;
+ }
+ Timer[EVENT_FLIGHT_SEQUENCE] = 2000;
+ break;
+ case 10://attack
+ DoResetThreat();
+ m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE + UNIT_FLAG_NOT_SELECTABLE);
+ //m_creature->GetMotionMaster()->Clear();
+ m_creature->SetByteValue(UNIT_FIELD_BYTES_2, 0, SHEATH_STATE_MELEE );
+ EnterPhase(PHASE_NORMAL_2);
+ break;
+ default:
+ break;
}
-
- ++WayPoint;
- WalkTimer = 200;
+ FlightCount++;
}
- void DeleteFromThreatList()
+ void HandleTransformSequence()
{
- if(!IllidanGUID) return; // If we do not have Illidan's GUID, do not proceed
- // Create a pointer to Illidan
- Creature* Illidan = ((Creature*)Unit::GetUnit((*m_creature), IllidanGUID));
- if(!Illidan) return; // No use to continue if Illidan does not exist
- std::list<HostilReference*>::iterator itr = Illidan->getThreatManager().getThreatList().begin();
- for( ; itr != Illidan->getThreatManager().getThreatList().end(); ++itr)
+ if(DemonTransformation[TransformCount].unaura)
+ m_creature->RemoveAurasDueToSpell(DemonTransformation[TransformCount].unaura);
+
+ if(DemonTransformation[TransformCount].aura)
+ DoCast(m_creature, DemonTransformation[TransformCount].aura, true);
+
+ if(DemonTransformation[TransformCount].displayid)
+ m_creature->SetUInt32Value(UNIT_FIELD_DISPLAYID, DemonTransformation[TransformCount].displayid); // It's morphin time!
+
+ if(DemonTransformation[TransformCount].equip)
{
- // Loop through threatlist till our GUID is found in it.
- if((*itr)->getUnitGuid() == m_creature->GetGUID())
- {
- (*itr)->removeReference(); // Delete ourself from his threatlist.
- return; // No need to continue anymore.
- }
+ m_creature->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_DISPLAY, 45479); // Requip warglaives if needed
+ m_creature->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_DISPLAY+1, 45481);
+ m_creature->SetByteValue(UNIT_FIELD_BYTES_2, 0, SHEATH_STATE_MELEE );
+ }
+ else
+ {
+ m_creature->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_DISPLAY, 0); // Unequip warglaives if needed
+ m_creature->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_DISPLAY+1, 0);
}
- // Now we delete our threatlist to prevent attacking anyone for now
- m_creature->DeleteThreatList();
+ switch(TransformCount)
+ {
+ case 2:
+ DoResetThreat();
+ break;
+ case 4:
+ EnterPhase(PHASE_DEMON);
+ break;
+ case 7:
+ DoResetThreat();
+ 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);
+ break;
+ default:
+ break;
+ }
+ if(Phase == PHASE_TRANSFORM_SEQUENCE)
+ Timer[EVENT_TRANSFORM_SEQUENCE] = DemonTransformation[TransformCount].timer;
+ TransformCount++;
}
void UpdateAI(const uint32 diff)
{
- if(IllidanGUID)
- {
- Creature* Illidan = ((Creature*)Unit::GetUnit((*m_creature), IllidanGUID));
- if(Illidan)
- {
- if(Illidan->IsInEvadeMode() && !m_creature->IsInEvadeMode())
- EnterEvadeMode();
+ if((!m_creature->SelectHostilTarget() || !m_creature->getVictim()) && Phase < PHASE_TALK_SEQUENCE)
+ return;
- if(((Illidan->GetHealth()*100 / Illidan->GetMaxHealth()) < 85) && InCombat && !FightMinions)
+ Event = EVENT_NULL;
+ for(uint32 i = 1; i <= MaxTimer[Phase]; i++)
+ if(Timer[i])
+ if(Timer[i] <= diff)
{
- if(TalkTimer < diff)
- {
- switch(TalkCount)
- {
- case 0:
- Illidan->Yell(SAY_AKAMA_MINION, LANG_UNIVERSAL, 0);
- DoPlaySoundToSet(Illidan, SOUND_AKAMA_MINION);
- TalkTimer = 8000;
- TalkCount = 1;
- break;
- case 1:
- DoYell(SAY_AKAMA_LEAVE, LANG_UNIVERSAL, NULL);
- DoPlaySoundToSet(m_creature, SOUND_AKAMA_LEAVE);
- TalkTimer = 3000;
- TalkCount = 2;
- break;
- case 2:
- IsTalking = true;
- TalkTimer = 2000;
- m_creature->RemoveAllAuras();
- m_creature->CombatStop();
- m_creature->AttackStop();
- m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE);
- TalkCount = 3;
- break;
- case 3:
- DeleteFromThreatList();
- IsWalking = true;
- WayPoint = WayPointList.begin();
- std::advance(WayPoint, 9);
- m_creature->RemoveUnitMovementFlag(MOVEMENTFLAG_WALK_MODE);
- break;
- }
- }else TalkTimer -= diff;
+ if(!Event)
+ Event = (EventIllidan)i;
}
+ else Timer[i] -= diff;
- if(((Illidan->GetHealth()*100 / Illidan->GetMaxHealth()) < 4) && !IsReturningToIllidan)
- ReturnToIllidan();
- }
- }else
- {
- if(pInstance)
- IllidanGUID = pInstance->GetData64(DATA_ILLIDANSTORMRAGE);
- }
+ switch(Phase)
+ {
+ case PHASE_NORMAL:
+ if(HPPCT(m_creature) < 65)
+ EnterPhase(PHASE_FLIGHT_SEQUENCE);
+ break;
+
+ case PHASE_NORMAL_2:
+ if(m_creature->GetHealth()*100 / m_creature->GetMaxHealth() < 30)
+ EnterPhase(PHASE_TALK_SEQUENCE);
+ break;
+
+ case PHASE_NORMAL_MAIEV:
+ if(m_creature->GetHealth()*100 / m_creature->GetMaxHealth() < 1)
+ EnterPhase(PHASE_TALK_SEQUENCE);
+ break;
+
+ case PHASE_TALK_SEQUENCE:
+ if(Event == EVENT_TALK_SEQUENCE)
+ HandleTalkSequence();
+ break;
+
+ case PHASE_FLIGHT_SEQUENCE:
+ if(Event == EVENT_FLIGHT_SEQUENCE)
+ HandleFlightSequence();
+ break;
+
+ case PHASE_TRANSFORM_SEQUENCE:
+ if(Event == EVENT_TRANSFORM_SEQUENCE)
+ HandleTransformSequence();
+ break;
+ }
- if(IsWalking && WalkTimer)
- {
- if(WalkTimer <= diff)
- {
- if(WayPoint == WayPointList.end())
+ if(m_creature->IsNonMeleeSpellCasted(false))
return;
- m_creature->GetMotionMaster()->MovePoint(WayPoint->id, WayPoint->x, WayPoint->y,WayPoint->z);
- WalkTimer = 0;
- }else WalkTimer -= diff;
- }
- if(StartChanneling)
- {
- if(ChannelTimer < diff)
- {
- switch(ChannelCount)
+ if(Phase == PHASE_NORMAL || Phase == PHASE_NORMAL_2 || Phase == PHASE_NORMAL_MAIEV && !m_creature->HasAura(SPELL_CAGED, 0))
{
- case 3:
- if(!DoorOpen)
+ switch(Event)
+ {
+ //PHASE_NORMAL
+ case EVENT_BERSERK:
+ DoYell(SAY_ENRAGE, LANG_UNIVERSAL, NULL);
+ DoPlaySoundToSet(m_creature, SOUND_ENRAGE);
+ DoCast(m_creature, SPELL_BERSERK, true);
+ Timer[EVENT_BERSERK] = 5000;//The buff actually lasts forever.
+ break;
+
+ case EVENT_TAUNT:
{
- m_creature->InterruptNonMeleeSpells(true);
- for(uint8 i = 0; i < 2; ++i)
- {
- if(SpiritGUID[i])
- {
- Unit* Spirit = Unit::GetUnit((*m_creature), SpiritGUID[i]);
- if(Spirit)
- Spirit->InterruptNonMeleeSpells(true);
- }
- }
- GameObject* Gate = GameObject::GetGameObject((*m_creature), pInstance->GetData64(DATA_GAMEOBJECT_ILLIDAN_GATE));
- if(Gate)
- Gate->SetGoState(0);
- ChannelCount++;
- ChannelTimer = 5000;
+ uint32 random = rand()%4;
+ char* yell = RandomTaunts[random].text;
+ uint32 soundid = RandomTaunts[random].sound;
+ if(yell)
+ DoYell(yell, LANG_UNIVERSAL, NULL);
+ if(soundid)
+ DoPlaySoundToSet(m_creature, soundid);
}
+ Timer[EVENT_TAUNT] = 32000;
break;
- case 4:
- m_creature->HandleEmoteCommand(EMOTE_ONESHOT_SALUTE);
- ChannelTimer = 2000;
- ChannelCount++;
+
+ case EVENT_SHEAR:
+ DoCast(m_creature->getVictim(), SPELL_SHEAR);
+ Timer[EVENT_SHEAR] = 25000 + (rand()%16 * 1000);
break;
- case 5:
- DoYell(SAY_AKAMA_BEWARE, LANG_UNIVERSAL, NULL);
- DoPlaySoundToSet(m_creature, SOUND_AKAMA_BEWARE);
- if(ChannelGUID)
- {
- Unit* ChannelTarget = Unit::GetUnit((*m_creature), ChannelGUID);
- if(ChannelTarget)
- ChannelTarget->setDeathState(JUST_DIED);
- }
- for(uint8 i = 0; i < 2; ++i)
+
+ case EVENT_FLAME_CRASH:
+ DoCast(m_creature->getVictim(), SPELL_FLAME_CRASH);
+ Timer[EVENT_FLAME_CRASH] = 35000;
+ break;
+
+ case EVENT_PARASITIC_SHADOWFIEND:
{
- if(SpiritGUID[i])
+ Unit* target = SelectUnit(SELECT_TARGET_RANDOM, 1);
+ if(!target) target = m_creature->getVictim();
+ if(target->GetTypeId() == TYPEID_PLAYER && !target->HasAura(SPELL_PARASITIC_SHADOWFIEND, 0))
{
- Unit* Spirit = Unit::GetUnit((*m_creature), SpiritGUID[i]);
- if(Spirit)
- Spirit->setDeathState(JUST_DIED);
+ target->CastSpell(target, SPELL_PARASITIC_SHADOWFIEND, true); // do not miss
+ ParasiteTargets.push_back(target->GetGUID());
+ Timer[EVENT_PARASITE_CHECK] += 1000; // do not check immediately
}
+ Timer[EVENT_PARASITIC_SHADOWFIEND] = 40000;
}
- ChannelTimer = 6000;
- ChannelCount++;
break;
- case 6:
- StartChanneling = false;
- if(WayPointList.empty())
- {
- error_log("SD2: Akama has no waypoints to start with!");
- return;
- }
- WayPoint = WayPointList.begin();
- m_creature->AddUnitMovementFlag(MOVEMENTFLAG_WALK_MODE);
- m_creature->GetMotionMaster()->MovePoint(WayPoint->id, WayPoint->x, WayPoint->y, WayPoint->z);
- IsWalking = true;
- break;
- default:
- if(ChannelGUID)
+ case EVENT_PARASITE_CHECK:
+ for(std::list<uint64>::iterator tIter = ParasiteTargets.begin(); tIter != ParasiteTargets.end();)
{
- Unit* Channel = Unit::GetUnit((*m_creature), ChannelGUID);
- if(Channel)
+ Unit* target = Unit::GetUnit((*m_creature), *tIter);
+ if(!target || !target->HasAura(SPELL_PARASITIC_SHADOWFIEND, 0))
{
- m_creature->InterruptNonMeleeSpells(true);
-
- for(uint8 i = 0; i < 2; ++i)
- {
- if(SpiritGUID[i])
- {
- Unit* Spirit = Unit::GetUnit((*m_creature), SpiritGUID[i]);
- if(Spirit)
- {
- Spirit->InterruptNonMeleeSpells(true);
- if(ChannelCount%2 == 0)
- {
- Spirit->CastSpell(Channel, SPELL_DEATHSWORN_DOOR_CHANNEL,false);
- DoCast(Channel, SPELL_AKAMA_DOOR_CHANNEL);
- }
- else
- {
- if(Spirit->GetVisibility() == VISIBILITY_OFF)
- Spirit->SetVisibility(VISIBILITY_ON);
- }
- }
- }
- }
- if(ChannelCount < 3)
- ChannelCount++;
- ChannelTimer = 10000;
+ if(target && target->isAlive())
+ target->CastSpell(target, SPELL_SUMMON_PARASITICS, true);
+ std::list<uint64>::iterator tIter2 = tIter;
+ ++tIter;
+ ParasiteTargets.erase(tIter2);
}
- break;
+ else
+ ++tIter;
}
+ if(ParasiteTargets.empty())
+ Timer[EVENT_PARASITE_CHECK] = 0;
+ else
+ Timer[EVENT_PARASITE_CHECK] = 1000;
+ break;
+
+ case EVENT_DRAW_SOUL:
+ DoCast(m_creature->getVictim(), SPELL_DRAW_SOUL);
+ Timer[EVENT_DRAW_SOUL] = 55000;
+ break;
+
+ //PHASE_NORMAL_2
+ case EVENT_AGONIZING_FLAMES:
+ DoCast(SelectUnit(SELECT_TARGET_RANDOM,0), SPELL_AGONIZING_FLAMES);
+ Timer[EVENT_AGONIZING_FLAMES] = 0;
+ break;
+
+ case EVENT_TRANSFORM_NORMAL:
+ EnterPhase(PHASE_TRANSFORM_SEQUENCE);
+ break;
+
+ //PHASE_NORMAL_MAIEV
+ case EVENT_ENRAGE:
+ DoCast(m_creature, SPELL_ENRAGE);
+ Timer[EVENT_ENRAGE] = 0;
+ break;
+
+ default:
+ break;
+ }
+ DoMeleeAttackIfReady();
}
- }else ChannelTimer -= diff;
- }
- if(FightMinions)
- {
- if(SummonMinionTimer < diff)
- {
- if(IllidanGUID)
+ if(Phase == PHASE_FLIGHT)
{
- Creature* Illidan = ((Creature*)Unit::GetUnit((*m_creature), IllidanGUID));
- if(!Illidan || Illidan->IsInEvadeMode())
+ switch(Event)
{
- Reset();
- EnterEvadeMode();
- return;
+ case EVENT_FIREBALL:
+ DoCast(SelectUnit(SELECT_TARGET_RANDOM, 0), SPELL_FIREBALL);
+ Timer[EVENT_FIREBALL] = 3000;
+ break;
+
+ case EVENT_DARK_BARRAGE:
+ DoCast(SelectUnit(SELECT_TARGET_RANDOM, 0), SPELL_DARK_BARRAGE);
+ Timer[EVENT_DARK_BARRAGE] = 0;
+ break;
+
+ case EVENT_EYE_BLAST:
+ CastEyeBlast();
+ Timer[EVENT_EYE_BLAST] = 0;
+ break;
+
+ case EVENT_MOVE_POINT:
+ Phase = PHASE_FLIGHT_SEQUENCE;
+ Timer[EVENT_FLIGHT_SEQUENCE] = 0;//do not start Event when changing hover point
+ for (uint8 i = 0; i <= rand()%3; i++)
+ {
+ HoverPoint++;
+ if(HoverPoint > 3)
+ HoverPoint = 0;
+ }
+ m_creature->AddUnitMovementFlag(MOVEMENTFLAG_ONTRANSPORT);
+ m_creature->GetMotionMaster()->MovePoint(0, HoverPosition[HoverPoint].x, HoverPosition[HoverPoint].y, HoverPosition[HoverPoint].z);
+ m_creature->RemoveUnitMovementFlag(MOVEMENTFLAG_ONTRANSPORT);
+ break;
+
+ default:
+ break;
}
}
- float x,y,z;
- m_creature->GetPosition(x,y,z);
- Creature* Elite = m_creature->SummonCreature(ILLIDARI_ELITE, x+rand()%10, y+rand()%10, z, 0, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, 30000);
- if(Elite)
+ if(Phase == PHASE_DEMON)
{
- Elite->AI()->AttackStart(m_creature);
- Elite->AddThreat(m_creature, 1000000.0f);
- AttackStart(Elite);
+ switch(Event)
+ {
+ case EVENT_SHADOW_BLAST:
+ m_creature->GetMotionMaster()->Clear(false);
+ if(!m_creature->IsWithinDistInMap(m_creature->getVictim(), 50)||!m_creature->IsWithinLOSInMap(m_creature->getVictim()))
+ m_creature->GetMotionMaster()->MoveChase(m_creature->getVictim(), 30);
+ else
+ m_creature->GetMotionMaster()->MoveIdle();
+ DoCast(m_creature->getVictim(), SPELL_SHADOW_BLAST);
+ Timer[EVENT_SHADOW_BLAST] = 4000;
+ break;
+ case EVENT_SHADOWDEMON:
+ SummonShadowDemon();
+ Timer[EVENT_SHADOWDEMON] = 0;
+ Timer[EVENT_FLAME_BURST] += 10000;
+ break;
+ case EVENT_FLAME_BURST:
+ DoCast(m_creature, SPELL_FLAME_BURST);
+ Timer[EVENT_FLAME_BURST] = 15000;
+ break;
+ case EVENT_TRANSFORM_DEMON:
+ EnterPhase(PHASE_TRANSFORM_SEQUENCE);
+ break;
+ default:
+ break;
+ }
}
- SummonMinionTimer = 10000 + rand()%6000;
- }else SummonMinionTimer -= diff;
- }
-
- // If we don't have a target, or is talking, or has run away, return
- if(!m_creature->SelectHostilTarget() || !m_creature->getVictim()) return;
-
- DoMeleeAttackIfReady();
}
};
-/************* Custom check used for Agonizing Flames ***************/
-class AgonizingFlamesTargetCheck
-{
- public:
- AgonizingFlamesTargetCheck(Unit const* unit) : pUnit(unit) {}
- bool operator() (Player* plr)
- {
- // Faster than square rooting
- if(!plr->isGameMaster() && pUnit->GetDistance2d(plr) > 225)
- return true;
-
- return false;
- }
-
- private:
- Unit const* pUnit;
-};
+/********************************** End of Illidan AI ******************************************/
-/************************************** Illidan's AI ***************************************/
-struct TRINITY_DLL_SPEC boss_illidan_stormrageAI : public ScriptedAI
+//This is used to sort the players by distance in preparation for being charged by the flames.
+struct TargetDistanceOrder : public std::binary_function<const Unit, const Unit, bool>
{
- boss_illidan_stormrageAI(Creature* c) : ScriptedAI(c)
+ const Unit* MainTarget;
+ TargetDistanceOrder(const Unit* Target) : MainTarget(Target) {};
+ // functor for operator ">"
+ bool operator()(const Unit* _Left, const Unit* _Right) const
{
- pInstance = ((ScriptedInstance*)c->GetInstanceData());
- Reset();
+ return (MainTarget->GetDistance(_Left) > MainTarget->GetDistance(_Right));
}
+};
- /** Instance Data **/
- ScriptedInstance* pInstance;
-
- /** Generic **/
- bool IsTalking;
- bool HasSummoned;
- bool RefaceVictim;
- bool InformAkama;
- uint32 Phase;
- uint32 GlobalTimer;
- uint32 TalkCount;
- uint32 DemonFormSequence;
-
- /** GUIDs **/
- uint64 FlameGUID[2];
- uint64 GlaiveGUID[2];
- uint64 AkamaGUID;
- uint64 MaievGUID;
+struct TRINITY_DLL_DECL flame_of_azzinothAI : public ScriptedAI
+{
+ flame_of_azzinothAI(Creature *c) : ScriptedAI(c) {Reset();}
- /** Timers **/
- uint32 ShearTimer;
- uint32 DrawSoulTimer;
- uint32 FlameCrashTimer;
- uint32 ParasiticShadowFiendTimer;
- uint32 FireballTimer;
- uint32 EyeBlastTimer;
- uint32 DarkBarrageTimer;
- uint32 SummonBladesTimer; // Animate summoning the Blades of Azzinoth in Phase 2
- uint32 SummonFlamesTimer; // Summon Flames of Azzinoth in Phase 2
- uint32 CheckFlamesTimer; // This is used to check the status of the Flames to see if we should begin entering Phase 3 or not.
- uint32 RetrieveBladesTimer; // Animate retrieving the Blades of Azzinoth in Phase 2 -> 3 transition
- uint32 LandTimer; // This is used at the end of phase 2 to signal Illidan landing after Flames are dead
- uint32 AgonizingFlamesTimer;
- uint32 ShadowBlastTimer;
- uint32 FlameBurstTimer;
- uint32 ShadowDemonTimer;
- uint32 TalkTimer;
- uint32 TransformTimer;
- uint32 EnrageTimer;
- uint32 CageTimer;
- uint32 LayTrapTimer;
- uint32 AnimationTimer;
- uint32 TauntTimer; // This is used for his random yells
- uint32 FaceVictimTimer;
- uint32 BerserkTimer;
+ uint32 FlameBlastTimer;
+ uint32 CheckTimer;
+ uint64 GlaiveGUID;
void Reset()
{
- Phase = PHASE_NORMAL;
+ FlameBlastTimer = 15000;
+ CheckTimer = 5000;
+ GlaiveGUID = 0;
+ }
- // Check if any flames/glaives are alive/existing. Kill if alive and set GUIDs to 0
- for(uint8 i = 0; i < 2; i++)
- {
- if(FlameGUID[i])
- {
- Unit* Flame = Unit::GetUnit((*m_creature), FlameGUID[i]);
- if(Flame)
- Flame->setDeathState(JUST_DIED);
- FlameGUID[i] = 0;
- }
+ void Aggro(Unit *who) {}
- if(GlaiveGUID[i])
- {
- Unit* Glaive = Unit::GetUnit((*m_creature), GlaiveGUID[i]);
- if(Glaive)
- Glaive->setDeathState(JUST_DIED);
- GlaiveGUID[i] = 0;
- }
- }
+ void ChargeCheck()
+ {
+ // Get the Threat List
+ std::list<HostilReference *> m_threatlist = m_creature->getThreatManager().getThreatList();
- if(AkamaGUID)
+ if(!m_threatlist.size()) return; // He doesn't have anyone in his threatlist, useless to continue
+
+ std::list<Unit *> targets;
+ std::list<HostilReference *>::iterator itr = m_threatlist.begin();
+ for( ; itr!= m_threatlist.end(); ++itr) //store the threat list in a different container
{
- Creature* Akama = ((Creature*)Unit::GetUnit((*m_creature), AkamaGUID));
- if(Akama)
- {
- if(!Akama->isAlive())
- Akama->Respawn();
- ((npc_akama_illidanAI*)Akama->AI())->Reset();
- ((npc_akama_illidanAI*)Akama->AI())->EnterEvadeMode();
- Akama->GetMotionMaster()->MoveTargetedHome();
- }
+ Unit *target = Unit::GetUnit(*m_creature, (*itr)->getUnitGuid());
+ if(target && target->isAlive() && target->GetTypeId() == TYPEID_PLAYER && target->GetPositionZ()>350) //only on alive players
+ targets.push_back(target);
}
- InformAkama = false;
- RefaceVictim = false;
- HasSummoned = false;
- AkamaGUID = 0;
- MaievGUID = 0;
-
- FaceVictimTimer = 1000;
- BerserkTimer = 1500000;
- GlobalTimer = 0;
- DemonFormSequence = 0;
-
- /** Normal Form **/
- ShearTimer = 20000 + (rand()%11 * 1000); // 20 to 30 seconds
- FlameCrashTimer = 30000; //30 seconds
- ParasiticShadowFiendTimer = 25000; // 25 seconds
- DrawSoulTimer = 50000; // 50 seconds
-
- /** Phase 2 **/
- SummonBladesTimer = 10000;
- SummonFlamesTimer = 20000; // Phase 2 timers may be incorrect
- FireballTimer = 5000;
- DarkBarrageTimer = 45000;
- EyeBlastTimer = 30000;
- CheckFlamesTimer = 5000;
- RetrieveBladesTimer = 5000;
- LandTimer = 0;
-
- /** Phase 3+ **/
- AgonizingFlamesTimer = 35000; // Phase 3+ timers may be incorrect
- ShadowBlastTimer = 3000;
- FlameBurstTimer = 10000;
- ShadowDemonTimer = 30000;
- TransformTimer = 90000;
- EnrageTimer = 40000;
- CageTimer = 30000;
- LayTrapTimer = CageTimer + 2000;
- AnimationTimer = 0;
-
- TauntTimer = 30000; // This timer may be off.
-
- m_creature->SetUInt32Value(UNIT_FIELD_DISPLAYID, 21135);
- m_creature->InterruptNonMeleeSpells(false);
- m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE);
- m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
- // Unequip warglaives if needed
- m_creature->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_DISPLAY, 0);
- m_creature->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_DISPLAY+1, 0);
- m_creature->RemoveUnitMovementFlag(MOVEMENTFLAG_LEVITATING);
-
- IsTalking = false;
-
- TalkCount = 0;
- TalkTimer = 0;
-
- if(pInstance)
- pInstance->SetData(DATA_ILLIDANSTORMRAGEEVENT, NOT_STARTED);
- }
-
- void Aggro(Unit *who) { DoZoneInCombat(); }
-
- void AttackStart(Unit *who)
- {
- if(!who || IsTalking || Phase == 2 || Phase == 4 || Phase == 6 || m_creature->HasAura(SPELL_KNEEL, 0))
+ if (!targets.size())
return;
- if (who->isTargetableForAttack() && who!= m_creature)
+ //Sort the list of players
+ targets.sort(TargetDistanceOrder(m_creature));
+ //Resize so we only get the furthest target
+ targets.resize(1);
+
+ Unit* target = (*targets.begin());
+ if(target && (!m_creature->IsWithinDistInMap(target, FLAME_CHARGE_DISTANCE)))
{
- //Begin melee attack if we are within range
- DoStartAttackAndMovement(who);
+ m_creature->AttackStop();
+ m_creature->GetMotionMaster()->Clear(false);
+ float x, y, z; // is it possible to fix charge?
+ target->GetContactPoint(m_creature, x, y, z);
+ m_creature->Relocate(x,y,z);
+ m_creature->SendMonsterMove(x, y, z, 0, MOVEMENTFLAG_WALK_MODE, 1);
+ //m_creature->GetMotionMaster()->MovePoint(0, m_creature->GetPositionX(), m_creature->GetPositionY(), m_creature->GetPositionZ());
+ m_creature->StopMoving();
+ //DoCast(target, SPELL_CHARGE);
+ m_creature->AddThreat(target, 5000000.0f);
+ DoTextEmote("sets its gaze on $N!", target);
}
}
- void MoveInLineOfSight(Unit *who)
+ void EnrageCheck()
{
- if (!who || m_creature->getVictim() || IsTalking || m_creature->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE))
- return;
-
- if (who->isTargetableForAttack() && who->isInAccessablePlaceFor(m_creature) && m_creature->IsHostileTo(who))
+ if(GETUNIT(Glaive, GlaiveGUID))
{
- if (!m_creature->canFly() && m_creature->GetDistanceZ(who) > CREATURE_Z_ATTACK_RANGE)
- return;
-
- float attackRadius = m_creature->GetAttackDistance(who);
- if (m_creature->IsWithinDistInMap(who, attackRadius) && m_creature->IsWithinLOSInMap(who))
+ if(!m_creature->IsWithinDistInMap(Glaive, FLAME_ENRAGE_DISTANCE))
{
- if(who->HasStealthAura())
- who->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH);
-
- DoStartAttackAndMovement(who);
+ Glaive->InterruptNonMeleeSpells(true);
+ DoCast(m_creature, SPELL_FLAME_ENRAGE, true);
+ DoResetThreat();
+ Unit* target = SelectUnit(SELECT_TARGET_RANDOM, 0);
+ if(target && target->isAlive())
+ {
+ m_creature->AddThreat(m_creature->getVictim(), 5000000.0f);
+ AttackStart(m_creature->getVictim());
+ }
+ }
+ else if(!m_creature->HasAura(SPELL_AZZINOTH_CHANNEL, 0))
+ {
+ Glaive->CastSpell(m_creature, SPELL_AZZINOTH_CHANNEL, false);
+ m_creature->RemoveAurasDueToSpell(SPELL_FLAME_ENRAGE);
}
}
}
- void JustDied(Unit *killer)
- {
- IsTalking = false;
- TalkCount = 0;
- TalkTimer = 0;
-
- m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
+ void SetGlaiveGUID(uint64 guid){ GlaiveGUID = guid; }
- if(!pInstance)
+ void UpdateAI(const uint32 diff)
+ {
+ if(!m_creature->SelectHostilTarget() || !m_creature->getVictim())
return;
- // Completed
- pInstance->SetData(DATA_ILLIDANSTORMRAGEEVENT, DONE);
- for(uint8 i = DATA_GAMEOBJECT_ILLIDAN_DOOR_R; i < DATA_GAMEOBJECT_ILLIDAN_DOOR_L + 1; ++i)
+ if(FlameBlastTimer < diff)
{
- GameObject* Door = GameObject::GetGameObject((*m_creature), pInstance->GetData64(i));
- if(Door)
- Door->SetGoState(0); // Open Doors
- }
-
- }
-
- void KilledUnit(Unit *victim)
- {
- if(victim == m_creature) return;
+ DoCast(m_creature->getVictim(), SPELL_BLAZE_SUMMON, true); //appear at victim
+ DoCast(m_creature->getVictim(), SPELL_FLAME_BLAST);
+ FlameBlastTimer = 15000; //10000 is official-like?
+ DoZoneInCombat(); //in case someone is revived
+ }else FlameBlastTimer -= diff;
- switch(rand()%2)
+ if(CheckTimer < diff)
{
- case 0:
- DoYell(SAY_KILL1, LANG_UNIVERSAL, victim);
- DoPlaySoundToSet(m_creature, SOUND_KILL1);
- break;
- case 1:
- DoYell(SAY_KILL2, LANG_UNIVERSAL, victim);
- DoPlaySoundToSet(m_creature, SOUND_KILL2);
- break;
- }
- }
+ ChargeCheck();
+ EnrageCheck();
+ CheckTimer = 5000;
+ }else CheckTimer -= diff;
- void DamageTaken(Unit *done_by, uint32 &damage)
- {
- if(damage > m_creature->GetHealth()) // Don't let ourselves be slain before we do our death speech
- {
- damage = 0;
- m_creature->SetHealth(m_creature->GetMaxHealth()/100);
- }
+ DoMeleeAttackIfReady();
}
+};
- void Cast(Unit* victim, uint32 Spell, bool triggered = false)
- {
- if(!victim)
- return;
- RefaceVictim = true;
- m_creature->SetUInt64Value(UNIT_FIELD_TARGET, victim->GetGUID());
- m_creature->CastSpell(victim, Spell, triggered);
- }
- /** This will handle the cast of eye blast **/
- void CastEyeBlast()
+/******* Functions and vars for Akama's AI ******/
+struct TRINITY_DLL_DECL npc_akama_illidanAI : public ScriptedAI
+{
+ npc_akama_illidanAI(Creature* c) : ScriptedAI(c)
{
- m_creature->InterruptNonMeleeSpells(false);
-
- DarkBarrageTimer += 10000;
+ pInstance = ((ScriptedInstance*)c->GetInstanceData());
+ Reset();
+ }
- DoYell(SAY_EYE_BLAST, LANG_UNIVERSAL, NULL);
- DoPlaySoundToSet(m_creature, SOUND_EYE_BLAST);
+ ScriptedInstance* pInstance;
- uint32 initial = rand()%4;
- uint32 final = 0;
- if(initial < 3)
- final = initial+1;
+ PhaseAkama Phase;
+ bool Event;
+ uint32 Timer;
- float initial_X = EyeBlast[initial].x;
- float initial_Y = EyeBlast[initial].y;
- float initial_Z = EyeBlast[initial].z;
+ uint64 IllidanGUID;
+ uint64 ChannelGUID;
+ uint64 SpiritGUID[2];
+ uint64 GateGUID;
+ uint64 DoorGUID[2];
- float final_X = EyeBlast[final].x;
- float final_Y = EyeBlast[final].y;
- float final_Z = EyeBlast[final].z;
+ uint32 ChannelCount;
+ uint32 WalkCount;
+ uint32 TalkCount;
- for(uint8 i = 0; i < 2; ++i)
+ void Reset()
+ {
+ if(pInstance)
{
- Creature* Trigger = NULL;
- Trigger = m_creature->SummonCreature(DEMON_FIRE, initial_X, initial_Y, initial_Z, 0, TEMPSUMMON_TIMED_DESPAWN, 20000);
- if(Trigger)
- {
- ((demonfireAI*)Trigger->AI())->IsTrigger = true;
- Trigger->GetMotionMaster()->MovePoint(0, final_X, final_Y, final_Z);
+ pInstance->SetData(DATA_ILLIDANSTORMRAGEEVENT, NOT_STARTED);
- if(!i)
- Trigger->CastSpell(Trigger, SPELL_EYE_BLAST_TRIGGER, true);
- else
- {
- Trigger->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
- m_creature->SetUInt64Value(UNIT_FIELD_TARGET, Trigger->GetGUID());
- DoCast(Trigger, SPELL_EYE_BLAST);
- }
- }
+ IllidanGUID = pInstance->GetData64(DATA_ILLIDANSTORMRAGE);
+ GateGUID = pInstance->GetData64(DATA_GAMEOBJECT_ILLIDAN_GATE);
+ DoorGUID[0] = pInstance->GetData64(DATA_GAMEOBJECT_ILLIDAN_DOOR_R);
+ DoorGUID[1] = pInstance->GetData64(DATA_GAMEOBJECT_ILLIDAN_DOOR_L);
+
+ if(GETGO(Gate, GateGUID))
+ Gate->SetUInt32Value(GAMEOBJECT_STATE, 1);
+ for(uint8 i = 0; i < 2; i++)
+ if(GETGO(Door, DoorGUID[i]))
+ Door->SetUInt32Value(GAMEOBJECT_STATE, 1);
+ }
+ else
+ {
+ IllidanGUID = 0;
+ GateGUID = 0;
+ DoorGUID[0] = 0;
+ DoorGUID[1] = 0;
}
- }
- // It's only cast on players that are greater than 15 yards away from Illidan. If no one is found, cast it on MT instead (since selecting someone in that 15 yard radius would cause the flames to hit the MT anyway).
- void CastAgonizingFlames()
- {
- // We'll use grid searching for this, using a custom searcher that selects a player that is at a distance >15 yards
- Player* target = NULL;
+ ChannelGUID = 0;
+ SpiritGUID[0] = 0;
+ SpiritGUID[1] = 0;
- CellPair pair(Trinity::ComputeCellPair(m_creature->GetPositionX(), m_creature->GetPositionY()));
- Cell cell(pair);
- cell.data.Part.reserved = ALL_DISTRICT;
- cell.SetNoCreate();
+ Phase = PHASE_AKAMA_NULL;
+ Timer = 0;
- AgonizingFlamesTargetCheck check(m_creature);
- Trinity::PlayerSearcher<AgonizingFlamesTargetCheck> searcher(target, check);
- TypeContainerVisitor
- <Trinity::PlayerSearcher<AgonizingFlamesTargetCheck>, GridTypeMapContainer> visitor(searcher);
+ ChannelCount = 0;
+ WalkCount = 0;
+ TalkCount = 0;
- CellLock<GridReadGuard> cell_lock(cell, pair);
- cell_lock->Visit(cell_lock, visitor, *(m_creature->GetMap()));
+ KillAllElites();
- if(target)
- DoCast(target, SPELL_AGONIZING_FLAMES);
- else
- DoCast(m_creature->getVictim(), SPELL_AGONIZING_FLAMES);
+ m_creature->SetUInt32Value(UNIT_NPC_FLAGS, 0); // Database sometimes has strange values..
+ m_creature->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP);
}
- void Talk(uint32 count)
+ // 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()
{
- if(!m_creature->isAlive()) return;
- uint32 sound = Conversation[count].sound;
- char* text = NULL;
- if(Conversation[count].text)
- text = Conversation[count].text;
- TalkTimer = Conversation[count].timer;
- uint32 emote = Conversation[count].emote;
- IsTalking = Conversation[count].Talk;
- Creature* creature = NULL;
- uint64 GUID = 0;
- if(Conversation[count].creature == ILLIDAN_STORMRAGE)
- creature = m_creature;
- else if(Conversation[count].creature == AKAMA)
- {
- if(!AkamaGUID)
- {
- if(pInstance)
- {
- AkamaGUID = pInstance->GetData64(DATA_AKAMA);
- if(!AkamaGUID)
- return;
- GUID = AkamaGUID;
- }
- }
- else GUID = AkamaGUID;
- }
- else if(Conversation[count].creature == MAIEV_SHADOWSONG)
- {
- if(!MaievGUID)
- return;
- GUID = MaievGUID;
- }
- else if(Conversation[count].creature == EMPTY) // This is just for special cases without speech/sounds/emotes.
- return;
+ m_creature->InterruptNonMeleeSpells(true);
+ m_creature->RemoveAllAuras();
+ m_creature->DeleteThreatList();
+ m_creature->CombatStop();
+ InCombat = false;
+ }
- if(GUID) // Now we check if we actually specified a GUID, if so:
- // we grab a pointer to that creature
- creature = ((Creature*)Unit::GetUnit((*m_creature), GUID));
+ void Aggro(Unit *who) {}
- if(creature)
- {
- creature->HandleEmoteCommand(emote); // Make the creature do some animation!
- if(text)
- creature->Yell(text, LANG_UNIVERSAL, 0); // Have the creature yell out some text
- if(sound)
- DoPlaySoundToSet(creature, sound); // Play some sound on the creature
- }
- }
+ void MovementInform(uint32 MovementType, uint32 Data) {Timer = 1;}
- void Move(float X, float Y, float Z, Creature* _Creature)
+ void DamageTaken(Unit *done_by, uint32 &damage)
{
- _Creature->GetMotionMaster()->MovePoint(0, X, Y, Z);
+ if(damage > m_creature->GetHealth() || done_by->GetGUID() != IllidanGUID)
+ damage = 0;
}
- void HandleDemonTransformAnimation(uint32 count)
+ void KillAllElites()
{
- uint32 unaura = DemonTransformation[count].unaura;
- uint32 aura = DemonTransformation[count].aura;
- uint32 displayid = DemonTransformation[count].displayid;
- AnimationTimer = DemonTransformation[count].timer;
- uint32 size = DemonTransformation[count].size;
-
- m_creature->InterruptNonMeleeSpells(false);
-
- if(DemonTransformation[count].phase != 8)
+ std::list<HostilReference*>::iterator itr;
+ for(itr = m_creature->getThreatManager().getThreatList().begin(); itr != m_creature->getThreatManager().getThreatList().end(); ++itr)
{
- m_creature->GetMotionMaster()->Clear();
- m_creature->GetMotionMaster()->MoveIdle();
+ Unit* pUnit = Unit::GetUnit((*m_creature), (*itr)->getUnitGuid());
+ if(pUnit && (pUnit->GetTypeId() == TYPEID_UNIT) && (pUnit->GetEntry() == ILLIDARI_ELITE))
+ pUnit->setDeathState(JUST_DIED);
}
+ EnterEvadeMode();
+ }
- if(unaura)
- m_creature->RemoveAurasDueToSpell(unaura);
-
- if(aura)
- DoCast(m_creature, aura, true);
-
- if(displayid)
- // It's morphin time!
- m_creature->SetUInt32Value(UNIT_FIELD_DISPLAYID, displayid);
- /*if(size)
- m_creature->SetUInt32Value(OBJECT_FIELD_SCALE_X, size); // Let us grow! (or shrink)*/
-
- if(DemonTransformation[count].equip)
- {
- // Requip warglaives if needed
- m_creature->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_DISPLAY, 45479);
- m_creature->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_DISPLAY+1, 45481);
- }
- else
- {
- // Unequip warglaives if needed
- m_creature->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_DISPLAY, 0);
- m_creature->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_DISPLAY+1, 0);
- }
+ void BeginTalk()
+ {
+ pInstance->SetData(DATA_ILLIDANSTORMRAGEEVENT, IN_PROGRESS);
- if(DemonTransformation[count].phase != 8)
- Phase = DemonTransformation[count].phase; // Set phase properly
- else
- {
- // Refollow and attack our old victim
- m_creature->GetMotionMaster()->MoveChase(m_creature->getVictim());
- if(MaievGUID) Phase = PHASE_NORMAL_MAIEV; // Depending on whether we summoned Maiev, we switch to either phase 5 or 3
- else Phase = PHASE_NORMAL_2;
- }
+ for(uint8 i = 0; i < 2; i++)
+ if(GETGO(Door, DoorGUID[i]))
+ Door->SetUInt32Value(GAMEOBJECT_STATE, 1);
- if(count == 7)
- {
- DoResetThreat();
- m_creature->RemoveAurasDueToSpell( SPELL_DEMON_FORM );
- }
- else if(count == 4)
+ if(GETCRE(Illidan, IllidanGUID))
{
- DoResetThreat();
- if(!m_creature->HasAura(SPELL_DEMON_FORM, 0))
- DoCast(m_creature, SPELL_DEMON_FORM, true);
+ Illidan->RemoveAurasDueToSpell(SPELL_KNEEL);
+ m_creature->SetInFront(Illidan);
+ Illidan->SetInFront(m_creature);
+ m_creature->StopMoving();
+ Illidan->StopMoving();
+ ((boss_illidan_stormrageAI*)Illidan->AI())->AkamaGUID = m_creature->GetGUID();
+ ((boss_illidan_stormrageAI*)Illidan->AI())->EnterPhase(PHASE_TALK_SEQUENCE);
}
}
- /** To reduce the amount of code in UpdateAI, we can seperate them into different functions and simply call them from UpdateAI **/
- void EnterPhase2()
+ void BeginChannel()
{
- DoYell(SAY_TAKEOFF, LANG_UNIVERSAL, NULL);
- DoPlaySoundToSet(m_creature, SOUND_TAKEOFF);
+ float x, y, z;
+ if(GETGO(Gate, GateGUID))
+ Gate->GetPosition(x, y, z);
- SummonBladesTimer = 10000; // Summon Glaives when this decrements
- SummonFlamesTimer = 20000; // Summon Flames when this decrements
- GlobalTimer += 20000;
- LandTimer = 0;
- Phase = PHASE_FLIGHT;
- m_creature->RemoveAllAuras();
- m_creature->SetUInt64Value(UNIT_FIELD_TARGET, 0);
- // So players don't shoot us down
- m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE);
- // Animate our take off!
- m_creature->HandleEmoteCommand(EMOTE_ONESHOT_LIFTOFF);
- // We now hover!
- m_creature->AddUnitMovementFlag(MOVEMENTFLAG_LEVITATING);
- m_creature->GetMotionMaster()->MovePoint(0, CENTER_X, CENTER_Y, CENTER_Z);
- for(uint8 i = 0; i < 2; ++i)
+ if(Creature* Channel = m_creature->SummonCreature(ILLIDAN_DOOR_TRIGGER, x, y, z+5, 0, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 360000))
{
- Creature* Glaive = m_creature->SummonCreature(BLADE_OF_AZZINOTH, GlaivePosition[i].x, GlaivePosition[i].y, GlaivePosition[i].z, 0, TEMPSUMMON_CORPSE_DESPAWN, 0);
- if(Glaive)
- {
- GlaiveGUID[i] = Glaive->GetGUID(); // We need this to remove them later on
- Glaive->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE);
- Glaive->SetVisibility(VISIBILITY_OFF);
- Glaive->setFaction(m_creature->getFaction());
- }
+ ChannelGUID = Channel->GetGUID();
+ Channel->SetUInt32Value(UNIT_FIELD_DISPLAYID, 11686); // Invisible but spell visuals can still be seen.
+ m_creature->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP);
+ DoCast(Channel, SPELL_AKAMA_DOOR_FAIL);
}
- }
-
- void SummonBladesOfAzzinoth()
- {
- m_creature->GetMotionMaster()->Clear(false);
- LandTimer = 0;
- RetrieveBladesTimer = 0;
-
- DoCast(m_creature, SPELL_THROW_GLAIVE2); // Make it look like we're throwing the glaives on the ground
- // We no longer wear the glaives!
- m_creature->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_DISPLAY, 0);
- // since they are now channeling the flames (or will be)
- m_creature->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_DISPLAY+1, 0);
for(uint8 i = 0; i < 2; ++i)
- {
- Creature* Glaive = NULL;
- Glaive = ((Creature*)Unit::GetUnit((*m_creature), GlaiveGUID[i]));
- if(Glaive)
+ if(Creature* Spirit = m_creature->SummonCreature(i ? SPIRIT_OF_OLUM : SPIRIT_OF_UDALO, SpiritSpawns[i].x, SpiritSpawns[i].y, SpiritSpawns[i].z, 0, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 360000))
{
- DoCast(Glaive, SPELL_THROW_GLAIVE, true);
- Glaive->SetVisibility(VISIBILITY_ON);
+ Spirit->SetVisibility(VISIBILITY_OFF);
+ SpiritGUID[i] = Spirit->GetGUID();
}
- }
}
- void SummonFlamesOfAzzinoth()
+ void BeginWalk()
{
- DoYell(SAY_SUMMONFLAMES, LANG_UNIVERSAL, NULL);
- DoPlaySoundToSet(m_creature, SOUND_SUMMONFLAMES);
+ m_creature->RemoveUnitMovementFlag(MOVEMENTFLAG_WALK_MODE);
+ m_creature->SetSpeed(MOVE_RUN, 1.0f);
+ m_creature->GetMotionMaster()->MovePoint(0, AkamaWP[WalkCount].x, AkamaWP[WalkCount].y, AkamaWP[WalkCount].z);
+ }
- for(uint8 i = 0; i < 2; ++i)
- {
- Creature* Flame = NULL;
- Creature* Glaive = NULL;
- Glaive = ((Creature*)Unit::GetUnit((*m_creature), GlaiveGUID[i]));
- if(Glaive)
+ void EnterPhase(PhaseAkama NextPhase)
+ {
+ if(!pInstance) return;
+ switch(NextPhase)
+ {
+ case PHASE_CHANNEL:
+ BeginChannel();
+ Timer = 5000;
+ ChannelCount = 0;
+ break;
+ case PHASE_WALK:
+ if(Phase == PHASE_CHANNEL)
+ WalkCount = 0;
+ else if(Phase == PHASE_TALK)
{
- Flame = m_creature->SummonCreature(FLAME_OF_AZZINOTH, GlaivePosition[i+2].x, GlaivePosition[i+2].y, GlaivePosition[i+2].z, 0, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 5000);
- if(Flame)
- {
- // Just in case the database has it as a different faction
- Flame->setFaction(m_creature->getFaction());
- // Attack our target!
- Flame->AI()->AttackStart(m_creature->getVictim());
- FlameGUID[i] = Flame->GetGUID(); // Record GUID in order to check if they're dead later on to move to the next phase
- // Glaives do some random Beam type channel on it.
- Glaive->CastSpell(Flame, SPELL_AZZINOTH_CHANNEL, true);
- if(m_creature->getVictim())
- Flame->AI()->AttackStart(m_creature->getVictim());
- }
- else
- {
- DoTextEmote("is unable to summon a Flame of Azzinoth.", NULL);
- error_log("SD2 ERROR: Illidan Stormrage AI: Unable to summon Flame of Azzinoth (entry: 22997), please check your database");
- EnterEvadeMode();
- }
+ if(GETCRE(Illidan, IllidanGUID))
+ ((boss_illidan_stormrageAI*)Illidan->AI())->DeleteFromThreatList(m_creature->GetGUID());
+ EnterEvadeMode();
+ m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE);
+ WalkCount++;
}
- else
+ BeginWalk();
+ Timer = 0;
+ break;
+ case PHASE_TALK:
+ if(Phase == PHASE_WALK)
{
- DoTextEmote("is unable to summon a Blade of Azzinoth.", NULL);
- error_log("SD2 ERROR: Illidan Stormrage AI: Unable to summon Blade of Azzinoth (entry: 22996), please check your database");
+ BeginTalk();
+ Timer = 0;
}
- }
- DoResetThreat(); // And now reset our threatlist
- HasSummoned = true;
- }
-
- void SummonMaiev()
- {
- TauntTimer += 4000;
- GlobalTimer += 4000;
-
- m_creature->InterruptNonMeleeSpells(false); // Interrupt any of our spells
- Creature* Maiev = NULL; // Summon Maiev near Illidan
- Maiev = m_creature->SummonCreature(MAIEV_SHADOWSONG, m_creature->GetPositionX() + 10, m_creature->GetPositionY() + 5, m_creature->GetPositionZ()+2, 0, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 45000);
- if(Maiev)
- {
- m_creature->GetMotionMaster()->Clear(false); // Stop moving, it's rude to walk and talk!
- m_creature->GetMotionMaster()->MoveIdle();
- // Just in case someone is unaffected by Shadow Prison
+ else if(Phase == PHASE_FIGHT_ILLIDAN)
+ {
+ Timer = 1;
+ TalkCount = 0;
+ }
+ break;
+ case PHASE_FIGHT_ILLIDAN:
+ if(GETUNIT(Illidan, IllidanGUID))
+ {
+ m_creature->AddThreat(Illidan, 10000000.0f);
+ m_creature->GetMotionMaster()->MoveChase(Illidan);
+ }
+ Timer = 30000; //chain lightning
+ break;
+ case PHASE_FIGHT_MINIONS:
+ m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE);
+ Timer = 10000 + rand()%6000;//summon minion
+ break;
+ case PHASE_RETURN:
m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE);
- DoCast(m_creature, SPELL_SHADOW_PRISON, true);
- TalkCount = 10;
- IsTalking = true; // We are now talking/
- Maiev->SetVisibility(VISIBILITY_OFF); // Leave her invisible until she has to talk
- Maiev->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE);
- MaievGUID = Maiev->GetGUID();
- }
- else // If Maiev cannot be summoned, reset the encounter and post some errors to the console.
- {
- EnterEvadeMode();
- DoTextEmote("is unable to summon Maiev Shadowsong and enter Phase 4. Resetting Encounter.", NULL);
- error_log("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)");
+ KillAllElites();
+ WalkCount = 0;
+ BeginWalk();
+ Timer = 1;
+ break;
+ default:
+ break;
}
+ Phase = NextPhase;
+ Event = false;
}
- void InitializeDeath()
+ void HandleTalkSequence()
{
- m_creature->RemoveAllAuras();
- DoCast(m_creature, SPELL_DEATH); // Animate his kneeling + stun him
- // Don't let the players interrupt our talk!
- m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE);
- m_creature->GetMotionMaster()->Clear(false); // No moving!
- m_creature->GetMotionMaster()->MoveIdle();
- if(MaievGUID)
+ switch(TalkCount)
{
- Creature* Maiev = ((Creature*)Unit::GetUnit((*m_creature), MaievGUID));
- if(Maiev)
+ case 0:
+ if(GETCRE(Illidan, IllidanGUID))
{
- Maiev->CombatStop(); // Maiev shouldn't do anything either. No point in her attacking us =]
- Maiev->GetMotionMaster()->Clear(false); // Stop her from moving as well
- Maiev->GetMotionMaster()->MoveIdle();
- float distance = 10.0f;
- float dx = m_creature->GetPositionX() + (distance*cos(m_creature->GetOrientation()));
- float dy = m_creature->GetPositionY() + (distance*sin(m_creature->GetOrientation()));
- Maiev->Relocate(dx,dy,Maiev->GetPositionZ());
- Maiev->SendMonsterMove(dx,dy,Maiev->GetPositionZ(), 0, 0, 0);
- Maiev->CastSpell(Maiev, SPELL_TELEPORT_VISUAL, true);
- Maiev->SetUInt64Value(UNIT_FIELD_TARGET, m_creature->GetGUID());
+ ((boss_illidan_stormrageAI*)Illidan->AI())->Timer[EVENT_TAUNT] += 30000;
+ Illidan->Yell(SAY_AKAMA_MINION, LANG_UNIVERSAL, 0);
+ DoPlaySoundToSet(Illidan, SOUND_AKAMA_MINION);
}
+ Timer = 8000;
+ break;
+ case 1:
+ DoYell(SAY_AKAMA_LEAVE, LANG_UNIVERSAL, NULL);
+ DoPlaySoundToSet(m_creature, SOUND_AKAMA_LEAVE);
+ Timer = 3000;
+ break;
+ case 2:
+ EnterPhase(PHASE_WALK);
+ break;
}
- IsTalking = true;
TalkCount++;
}
- void UpdateAI(const uint32 diff)
+ void HandleChannelSequence()
{
- /*** This section will handle the conversations ***/
- if(IsTalking) // Somewhat more efficient using a function rather than a long switch
+ Unit* Channel, *Spirit[2];
+ if(ChannelCount <= 5)
{
- if(TalkTimer < diff)
- {
- switch(TalkCount) // This is only for specialized cases
- {
- case 0:
- // Time to stand up!
- m_creature->RemoveAurasDueToSpell( SPELL_KNEEL );
- break;
- case 8:
- // Equip our warglaives!
- m_creature->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_DISPLAY, 45479);
- m_creature->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_DISPLAY+1, 45481);
- m_creature->setFaction(14); // Hostile if we weren't before
- break;
- case 9:
- if(AkamaGUID)
- {
- Creature* Akama = ((Creature*)Unit::GetUnit((*m_creature), AkamaGUID));
- if(Akama)
- {
- Akama->GetMotionMaster()->Clear(false);
- // Akama runs to us!
- Akama->GetMotionMaster()->MoveChase(m_creature);
- m_creature->GetMotionMaster()->Clear(false);
- // We run to Akama!
- m_creature->GetMotionMaster()->MoveChase(Akama);
- Akama->AddThreat(m_creature, 1000000.0f);
- AttackStart(Akama); // Start attacking Akama
- ((npc_akama_illidanAI*)Akama->AI())->IsTalking = false;
- // Akama starts attacking us
- ((npc_akama_illidanAI*)Akama->AI())->AttackStart(m_creature);
- }
- }
- // We are now attackable!
- m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE);
- break;
- case 11:
- if(MaievGUID)
- {
- Unit* Maiev = Unit::GetUnit((*m_creature), MaievGUID);
- if(Maiev)
- {
- // Maiev is now visible
- Maiev->SetVisibility(VISIBILITY_ON);
- // onoz she looks like she teleported!
- Maiev->CastSpell(Maiev, SPELL_TELEPORT_VISUAL, true);
- // Have her face us
- Maiev->SetUInt64Value(UNIT_FIELD_TARGET, m_creature->GetGUID());
- // Face her, so it's not rude =P
- m_creature->SetUInt64Value(UNIT_FIELD_TARGET, Maiev->GetGUID());
- }
- }
- break;
- case 14:
- if(MaievGUID)
- {
- Creature* Maiev = ((Creature*)Unit::GetUnit((*m_creature), MaievGUID));
- if(Maiev)
- {
- Maiev->GetMotionMaster()->Clear(false);
- Maiev->GetMotionMaster()->MoveChase(m_creature);
- // Have Maiev add a lot of threat on us so that players don't pull her off if they damage her via AOE
- Maiev->AddThreat(m_creature, 10000000.0f);
- // Force Maiev to attack us.
- Maiev->AI()->AttackStart(m_creature);
- Maiev->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
- }
- }
- m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE);
- m_creature->GetMotionMaster()->MoveChase(m_creature->getVictim());
- IsTalking = false;
- FaceVictimTimer = 2000;
- RefaceVictim = true;
- break;
- case 20: // Kill ourself.
- if(MaievGUID)
- {
- Creature* Maiev = ((Creature*)Unit::GetUnit((*m_creature), MaievGUID));
- if(Maiev) // Make Maiev leave
- {
- Maiev->CastSpell(Maiev, SPELL_TELEPORT_VISUAL, true);
- Maiev->setDeathState(JUST_DIED);
- }
- }
- IsTalking = false;
- if(m_creature->getVictim())
- m_creature->getVictim()->DealDamage(m_creature, m_creature->GetHealth(), NULL, DIRECT_DAMAGE,SPELL_SCHOOL_MASK_NORMAL, NULL, false);
- else
- // Now we kill ourself
- m_creature->DealDamage(m_creature, m_creature->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false);
- break;
- }
- Talk(TalkCount); // This function does most of the talking
- TalkCount++;
- }else TalkTimer -= diff;
+ Channel = Unit::GetUnit((*m_creature), ChannelGUID);
+ Spirit[0] = Unit::GetUnit((*m_creature), SpiritGUID[0]);
+ Spirit[1] = Unit::GetUnit((*m_creature), SpiritGUID[1]);
+ if(!Channel || !Spirit[0] || !Spirit[1])
+ return;
}
- // If we don't have a target, return.
- if(!m_creature->SelectHostilTarget() || !m_creature->getVictim() || IsTalking)
- return;
+ switch(ChannelCount)
+ {
+ case 0: // channel failed
+ m_creature->InterruptNonMeleeSpells(true);
+ Timer = 2000;
+ break;
+ case 1: // spirit appear
+ Spirit[0]->SetVisibility(VISIBILITY_ON);
+ Spirit[1]->SetVisibility(VISIBILITY_ON);
+ 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
+ m_creature->InterruptNonMeleeSpells(true);
+ Spirit[0]->InterruptNonMeleeSpells(true);
+ Spirit[1]->InterruptNonMeleeSpells(true);
+ if(GETGO(Gate, GateGUID))
+ Gate->SetUInt32Value(GAMEOBJECT_STATE, 0);
+ Timer = 2000;
+ break;
+ case 4:
+ m_creature->HandleEmoteCommand(EMOTE_ONESHOT_SALUTE);
+ Timer = 2000;
+ break;
+ case 5:
+ DoYell(SAY_AKAMA_BEWARE, LANG_UNIVERSAL, NULL);
+ DoPlaySoundToSet(m_creature, SOUND_AKAMA_BEWARE);
+ Channel->setDeathState(JUST_DIED);
+ Spirit[0]->setDeathState(JUST_DIED);
+ Spirit[1]->setDeathState(JUST_DIED);
+ Timer = 3000;
+ break;
+ case 6:
+ EnterPhase(PHASE_WALK);
+ break;
+ default:
+ break;
+ }
+ ChannelCount++;
+ }
- // If we are 'caged', then we shouldn't do anything such as cast spells or transform into Demon Form.
- if(m_creature->HasAura(SPELL_CAGED, 0))
- {
- EnrageTimer = 40000; // Just so that he doesn't immediately enrage after he stops being caged.
- CageTimer = 30000;
- return;
+ void HandleWalkSequence()
+ {
+ switch(WalkCount)
+ {
+ case 6:
+ for(uint8 i = 0; i < 2; i++)
+ if(GETGO(Door, DoorGUID[i]))
+ Door->SetUInt32Value(GAMEOBJECT_STATE, 0);
+ break;
+ case 8:
+ if(Phase == PHASE_WALK)
+ EnterPhase(PHASE_TALK);
+ else
+ EnterPhase(PHASE_FIGHT_ILLIDAN);
+ break;
+ case 12:
+ EnterPhase(PHASE_FIGHT_MINIONS);
+ break;
}
- // Berserk Timer - flat 25 minutes
- if(!m_creature->HasAura(SPELL_BERSERK, 0) && Phase != PHASE_DEMON_SEQUENCE)
- if(BerserkTimer < diff)
+ if(Phase == PHASE_WALK)
{
- DoYell(SAY_ENRAGE, LANG_UNIVERSAL, NULL);
- DoPlaySoundToSet(m_creature, SOUND_ENRAGE);
- DoCast(m_creature, SPELL_BERSERK, true);
- }else BerserkTimer -= diff;
+ Timer = 0;
+ WalkCount++;
+ m_creature->GetMotionMaster()->MovePoint(WalkCount, AkamaWP[WalkCount].x, AkamaWP[WalkCount].y, AkamaWP[WalkCount].z);
+ }
+ }
- if(RefaceVictim)
- if(FaceVictimTimer < diff)
- {
- m_creature->SetUInt64Value(UNIT_FIELD_TARGET, m_creature->getVictim()->GetGUID());
- FaceVictimTimer = 1000;
- RefaceVictim = false;
- }else FaceVictimTimer -= diff;
-
- /** Signal to change to phase 2 **/
- if(((m_creature->GetHealth()*100 / m_creature->GetMaxHealth()) < 65) && (Phase == PHASE_NORMAL))
- EnterPhase2();
-
- /** Signal to summon Maiev **/
- if(((m_creature->GetHealth()*100 / m_creature->GetMaxHealth()) < 30) && !MaievGUID &&
- ((Phase != PHASE_DEMON) || (Phase != PHASE_DEMON_SEQUENCE)))
- SummonMaiev();
-
- /** Time for the death speech **/
- if((m_creature->GetHealth()*100 / m_creature->GetMaxHealth() < 1) && (!IsTalking) &&
- ((Phase != PHASE_DEMON) || (Phase != PHASE_DEMON_SEQUENCE)))
- InitializeDeath();
-
- /***** Spells for Phase 1, 3 and 5 (Normal Form) ******/
- if(Phase == PHASE_NORMAL || Phase == PHASE_NORMAL_2 || Phase == PHASE_NORMAL_MAIEV)
+ void UpdateAI(const uint32 diff)
+ {
+ Event = false;
+ if(Timer)
{
- if(TauntTimer < diff) // His random taunt/yell timer.
- {
- uint32 random = rand()%4;
- char* yell = RandomTaunts[random].text;
- uint32 soundid = RandomTaunts[random].sound;
- if(yell)
- DoYell(yell, LANG_UNIVERSAL, NULL);
- if(soundid)
- DoPlaySoundToSet(m_creature, soundid);
- TauntTimer = 32000;
- }else TauntTimer -= diff;
-
- if(GlobalTimer < diff) // Global Timer so that spells do not overlap.
- {
- if(ShearTimer < diff)
- {
- DoCast(m_creature->getVictim(), SPELL_SHEAR);
- ShearTimer = 25000 + (rand()%16 * 1000);
- GlobalTimer += 2000;
- }else ShearTimer -= diff;
-
- if(FlameCrashTimer < diff)
- {
- // It spawns multiple flames sometimes. Therefore, we'll do this manually.
- //DoCast(m_creature->getVictim(), SPELL_FLAME_CRASH);
- DoSpawnCreature(FLAME_CRASH, 0, 0, 0, 0, TEMPSUMMON_TIMED_DESPAWN, 40000);
- FlameCrashTimer = 35000;
- GlobalTimer += 2000;
- }else FlameCrashTimer -= diff;
-
- if(ParasiticShadowFiendTimer < diff)
- {
- Unit* target = NULL;
- target = SelectUnit(SELECT_TARGET_RANDOM,1);
- if(target && target->isAlive() && !target->HasAura(SPELL_PARASITIC_SHADOWFIEND, 0))
- {
- Cast(target, SPELL_PARASITIC_SHADOWFIEND);
- ParasiticShadowFiendTimer = 40000;
- }
- }else ParasiticShadowFiendTimer -= diff;
-
- if(DrawSoulTimer < diff)
- {
- DoCast(m_creature->getVictim(), SPELL_DRAW_SOUL);
- DrawSoulTimer = 55000;
- GlobalTimer += 3000;
- }else DrawSoulTimer -= diff;
- }else GlobalTimer -= diff;
-
- if(!IsTalking)
- DoMeleeAttackIfReady();
+ if(Timer <= diff)
+ Event = true;
+ else Timer -= diff;
}
- /*** Phase 2 ***/
- if(Phase == PHASE_FLIGHT)
+ if(Event)
{
- // Check if we have summoned or not.
- if(!HasSummoned)
+ switch(Phase)
{
- if(SummonBladesTimer)
- if(SummonBladesTimer <= diff)
- {
- SummonBladesOfAzzinoth();
- SummonBladesTimer = 0;
- }else SummonBladesTimer -= diff;
-
- if(SummonFlamesTimer < diff)
- {
- SummonFlamesOfAzzinoth();
- }else SummonFlamesTimer -= diff;
- }
-
- if(!m_creature->GetMotionMaster()->empty() && (m_creature->GetMotionMaster()->GetCurrentMovementGeneratorType() != POINT_MOTION_TYPE))
- m_creature->GetMotionMaster()->Clear(false);
-
- if(HasSummoned)
- {
- if(CheckFlamesTimer)
- if(CheckFlamesTimer <= diff)
+ case PHASE_CHANNEL:
+ HandleChannelSequence();
+ break;
+ case PHASE_TALK:
+ HandleTalkSequence();
+ break;
+ case PHASE_WALK:
+ case PHASE_RETURN:
+ HandleWalkSequence();
+ break;
+ case PHASE_FIGHT_ILLIDAN:
{
- // Check if flames are dead or non-existant. If so, set GUID to 0.
- for(uint8 i = 0; i < 2; i++)
+ GETUNIT(Illidan, IllidanGUID);
+ if(Illidan && HPPCT(Illidan) < 90)
+ EnterPhase(PHASE_TALK);
+ else
{
- if(FlameGUID[i])
- {
- Unit* Flame = NULL;
- Flame = Unit::GetUnit((*m_creature), FlameGUID[i]);
-
- // If the flame dies, or somehow the pointer becomes invalid, reset GUID to 0.
- if(!Flame || !Flame->isAlive())
- FlameGUID[i] = 0;
- }
+ DoCast(m_creature->getVictim(), SPELL_CHAIN_LIGHTNING);
+ Timer = 30000;
}
- CheckFlamesTimer = 500;
- }else CheckFlamesTimer -= diff;
-
- // If both flames are dead/non-existant, kill glaives and change to phase 3.
- if(!FlameGUID[0] && !FlameGUID[1] && CheckFlamesTimer)
- {
- RetrieveBladesTimer = 5000; // Prepare for re-equipin!
- CheckFlamesTimer = 0;
- }
-
- if(RetrieveBladesTimer)
- if(RetrieveBladesTimer <= diff) // Time to get back our glaives!
+ }break;
+ case PHASE_FIGHT_MINIONS:
{
- // Interrupt any spells we might be doing *cough* DArk Barrage *cough*
- m_creature->InterruptNonMeleeSpells(false);
- for(uint8 i = 0; i < 2; i++)
+ float x, y, z;
+ m_creature->GetPosition(x, y, z);
+ Creature* Elite = m_creature->SummonCreature(ILLIDARI_ELITE, x+rand()%10, y+rand()%10, z, 0, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, 30000);
+ //Creature* Elite = m_creature->SummonCreature(ILLIDARI_ELITE, x, y, z, 0, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, 30000);
+ if(Elite)
{
- if(GlaiveGUID[i])
- {
- Unit* Glaive = NULL;
- Glaive = Unit::GetUnit((*m_creature), GlaiveGUID[i]);
- if(Glaive)
- {
- // Make it look like the Glaive flies back up to us
- Glaive->CastSpell(m_creature, SPELL_GLAIVE_RETURNS, true);
- // Despawn the Glaive
- Glaive->setDeathState(JUST_DIED);
- }
- GlaiveGUID[i] = 0;
- }
+ Elite->AI()->AttackStart(m_creature);
+ Elite->AddThreat(m_creature, 1000000.0f);
+ AttackStart(Elite);
}
- // Re-equip our warblades!
- m_creature->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_DISPLAY, 45479);
- m_creature->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_DISPLAY+1, 45481);
- LandTimer = 5000; // Prepare for landin'!
- RetrieveBladesTimer = 0;
- }else RetrieveBladesTimer -= diff;
-
- if(LandTimer)
- {
- if(LandTimer <= diff) // Time to land!
- {
- DoResetThreat();
- // anndddd touchdown!
- m_creature->HandleEmoteCommand(EMOTE_ONESHOT_LAND);
- m_creature->RemoveUnitMovementFlag(MOVEMENTFLAG_ONTRANSPORT + MOVEMENTFLAG_LEVITATING);
- Phase = PHASE_NORMAL_2;
- // We should let the raid fight us =)
- m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE);
- m_creature->SetUInt64Value(UNIT_FIELD_TARGET, m_creature->getVictim()->GetGUID());
- // Chase our victim!
- m_creature->GetMotionMaster()->MoveChase(m_creature->getVictim());
- }else LandTimer -= diff;
- return; // Do not continue past this point if LandTimer is not 0 and we are in phase 2.
+ Timer = 10000 + rand()%6000;
+ GETUNIT(Illidan, IllidanGUID);
+ if(Illidan && HPPCT(Illidan) < 10)
+ EnterPhase(PHASE_RETURN);
}
+ break;
+ default:
+ break;
}
+ }
- if(GlobalTimer < diff)
- {
- if(FireballTimer < diff)
- {
- Cast(SelectUnit(SELECT_TARGET_RANDOM, 0), SPELL_FIREBALL);
- FireballTimer = 5000;
- }else FireballTimer -= diff;
-
- if(DarkBarrageTimer < diff)
- {
- m_creature->InterruptNonMeleeSpells(false);
- DoCast(SelectUnit(SELECT_TARGET_RANDOM, 0), SPELL_DARK_BARRAGE);
- DarkBarrageTimer = 35000;
- GlobalTimer += 9000;
- }else DarkBarrageTimer -= diff;
+ if(!m_creature->SelectHostilTarget() || !m_creature->getVictim())
+ return;
- if(EyeBlastTimer < diff)
- {
- CastEyeBlast();
- EyeBlastTimer = 30000;
- }else EyeBlastTimer -= diff;
- }else GlobalTimer -= diff;
- }
+ if(m_creature->GetHealth()*100 / m_creature->GetMaxHealth() < 20)
+ DoCast(m_creature, SPELL_HEALING_POTION);
- /** Phase 3,5 spells only**/
- if(Phase == PHASE_NORMAL_2 || Phase == PHASE_NORMAL_MAIEV)
- {
- if(GlobalTimer < diff)
- {
- if(AgonizingFlamesTimer < diff)
- {
- CastAgonizingFlames();
- AgonizingFlamesTimer = 60000;
- }else AgonizingFlamesTimer -= diff;
- }else GlobalTimer -= diff;
+ DoMeleeAttackIfReady();
+ }
+};
- if(TransformTimer < diff)
- {
- uint32 CurHealth = m_creature->GetHealth()*100 / m_creature->GetMaxHealth();
- // Prevent Illidan from morphing if less than 32% or 5%, as this may cause issues with the phase transition or death speech
- if((CurHealth < 32 && !MaievGUID) || (CurHealth < 5))
- return;
- Phase = PHASE_DEMON_SEQUENCE; // Transform sequence
- DemonFormSequence = 0;
- AnimationTimer = 0;
- DoYell(SAY_MORPH, LANG_UNIVERSAL, NULL);
- DoPlaySoundToSet(m_creature, SOUND_MORPH);
- TransformTimer = 60000;
- FlameBurstTimer = 10000;
- ShadowDemonTimer = 30000;
- m_creature->GetMotionMaster()->Clear(false);// Stop moving
- }else TransformTimer -= diff;
- }
+struct TRINITY_DLL_DECL boss_maievAI : public ScriptedAI
+{
+ boss_maievAI(Creature *c) : ScriptedAI(c) { Reset(); };
- /** Phase 4 spells only (Demon Form) **/
- if(Phase == PHASE_DEMON)
- {
- // Stop moving if we are by clearing movement generators.
- if(!m_creature->GetMotionMaster()->empty())
- m_creature->GetMotionMaster()->Clear(false);
+ uint64 IllidanGUID;
- if(TransformTimer < diff)
- {
- Phase = PHASE_DEMON_SEQUENCE;
- DemonFormSequence = 5;
- AnimationTimer = 100;
- TransformTimer = 60000;
- }else TransformTimer -= diff;
+ PhaseIllidan Phase;
+ EventMaiev Event;
+ uint32 Timer[5];
+ uint32 MaxTimer;
- if(ShadowDemonTimer < diff)
- {
- m_creature->InterruptNonMeleeSpells(false);
- Creature* ShadowDemon = NULL;
- for(uint8 i = 0; i < 4; i++)
- {
- Unit* target = NULL;
- target = SelectUnit(SELECT_TARGET_RANDOM,0);
- // only on players.
- if(target && target->GetTypeId() == TYPEID_PLAYER)
- {
- ShadowDemon = DoSpawnCreature(SHADOW_DEMON, 0,0,0,0,TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN,25000);
- if(ShadowDemon)
- {
- ShadowDemon->AddThreat(target, 5000000.0f);
- ShadowDemon->AI()->AttackStart(target);
- DoZoneInCombat(ShadowDemon);
- }
- }
- }
- ShadowDemonTimer = 60000;
- }else ShadowDemonTimer -= diff;
+ void Reset()
+ {
+ MaxTimer = 0;
+ Phase = PHASE_NORMAL_MAIEV;
+ IllidanGUID = 0;
+ Timer[EVENT_MAIEV_STEALTH] = 0;
+ Timer[EVENT_MAIEV_TAUNT] = 22000 + rand()%21 * 1000;
+ Timer[EVENT_MAIEV_SHADOW_STRIKE] = 30000;
+ m_creature->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_DISPLAY, 44850);
+ m_creature->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_DISPLAY + 1, 0);
+ m_creature->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_DISPLAY + 2, 45738);
+ }
- if(GlobalTimer < diff)
- {
- if(ShadowBlastTimer < diff)
- {
- Unit* target = SelectUnit(SELECT_TARGET_TOPAGGRO, 0);
- if(target && target->isAlive())
- {
- m_creature->SetUInt64Value(UNIT_FIELD_TARGET, target->GetGUID());
- DoCast(target, SPELL_SHADOW_BLAST);
- ShadowBlastTimer = 4000;
- GlobalTimer += 1500;
- }
- if(!m_creature->HasAura(SPELL_DEMON_FORM, 0))
- DoCast(m_creature, SPELL_DEMON_FORM, true);
- }else ShadowBlastTimer -= diff;
+ void Aggro(Unit *who) {}
+ void MoveInLineOfSight(Unit *who) {}
+ void EnterEvadeMode() {}
+ void GetIllidanGUID(uint64 guid) { IllidanGUID = guid; }
- if(FlameBurstTimer < diff)
- {
- DoCast(m_creature, SPELL_FLAME_BURST);
- FlameBurstTimer = 15000;
- }else FlameBurstTimer -= diff;
- }else GlobalTimer -= diff;
+ void DamageTaken(Unit *done_by, uint32 &damage)
+ {
+ if(done_by->GetGUID() != IllidanGUID )
+ damage = 0;
+ else
+ {
+ GETUNIT(Illidan, IllidanGUID);
+ if(Illidan && Illidan->getVictim() == m_creature)
+ damage = m_creature->GetMaxHealth()/10;
+ if(damage >= m_creature->GetHealth())
+ damage = 0;
}
+ }
+
+ void AttackStart(Unit *who)
+ {
+ if(!who || Timer[EVENT_MAIEV_STEALTH])
+ return;
- /** Phase 5 timers. Enrage spell **/
- if(Phase == PHASE_NORMAL_MAIEV)
+ if (who->isTargetableForAttack())
{
- if(EnrageTimer < diff)
+ if(Phase == PHASE_TALK_SEQUENCE)
+ m_creature->Attack(who, false);
+ else if(Phase == PHASE_DEMON || Phase == PHASE_TRANSFORM_SEQUENCE )
{
- DoCast(m_creature, SPELL_ENRAGE);
- EnrageTimer = 40000;
- CageTimer = 30000;
- TransformTimer += 10000;
- }else EnrageTimer -= diff;
-
- // We'll handle Cage Trap in Illidan's script for simplicity's sake
- if(CageTimer < diff)
+ GETUNIT(Illidan, IllidanGUID);
+ if(Illidan && m_creature->IsWithinDistInMap(Illidan, 25))
+ BlinkToPlayer();//Do not let dread aura hurt her.
+ m_creature->Attack(who, false);
+ }
+ else
+ DoStartAttackAndMovement(who);
+
+ if (!InCombat)
{
- if(MaievGUID)
- {
- Unit* Maiev = Unit::GetUnit((*m_creature), MaievGUID);
- Unit* target = SelectUnit(SELECT_TARGET_RANDOM, 0);
- if(!Maiev || !target || (target->GetTypeId() != TYPEID_PLAYER))
- return;
- float X, Y, Z;
- target->GetPosition(X, Y, Z);
- Maiev->Relocate(X, Y, Z, Maiev->GetOrientation());
- // Make it look like she 'teleported'
- Maiev->CastSpell(Maiev, SPELL_TELEPORT_VISUAL, true);
- // summon the trap!
- Maiev->CastSpell(Maiev, SPELL_CAGE_TRAP_SUMMON, false);
- }
- CageTimer = 15000;
- }else CageTimer -= diff;
+ Aggro(who);
+ InCombat = true;
+ }
}
+ }
- if(Phase == PHASE_DEMON_SEQUENCE) // Demonic Transformation
+ void EnterPhase(PhaseIllidan NextPhase)//This is in fact Illidan's phase.
+ {
+ switch(NextPhase)
{
- if(AnimationTimer < diff)
+ case PHASE_TALK_SEQUENCE:
+ if(Timer[EVENT_MAIEV_STEALTH])
{
- HandleDemonTransformAnimation(DemonFormSequence);
- DemonFormSequence++;
- }else AnimationTimer -= diff;
+ m_creature->SetHealth(m_creature->GetMaxHealth());
+ m_creature->SetVisibility(VISIBILITY_ON);
+ Timer[EVENT_MAIEV_STEALTH] = 0;
+ }
+ m_creature->InterruptNonMeleeSpells(false);
+ m_creature->GetMotionMaster()->Clear(false);
+ //m_creature->GetMotionMaster()->MoveIdle();
+ m_creature->AttackStop();
+ m_creature->SetUInt64Value(UNIT_FIELD_TARGET, 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;
}
-};
-
-/*********************** End of Illidan AI ******************************************/
-void npc_akama_illidanAI::BeginEvent(uint64 PlayerGUID)
-{
- debug_log("SD2: Akama - Illidan Introduction started. Illidan event properly begun.");
- if(pInstance)
+ void BlinkTo(float x, float y, float z)
{
- IllidanGUID = pInstance->GetData64(DATA_ILLIDANSTORMRAGE);
- pInstance->SetData(DATA_ILLIDANSTORMRAGEEVENT, IN_PROGRESS);
+ m_creature->AttackStop();
+ m_creature->InterruptNonMeleeSpells(false);
+ m_creature->GetMotionMaster()->Clear(false);
+ //m_creature->GetMotionMaster()->MoveIdle();
+ m_creature->Relocate(x, y, z);
+ m_creature->SendMonsterMove(x, y, z, 0, 0, 0);
+ DoCast(m_creature, SPELL_TELEPORT_VISUAL, true);
}
- if(pInstance)
- for(uint8 i = DATA_GAMEOBJECT_ILLIDAN_DOOR_R; i < DATA_GAMEOBJECT_ILLIDAN_DOOR_L+1; ++i)
+ void BlinkToPlayer()
{
- GameObject* Door = GameObject::GetGameObject((*m_creature), pInstance->GetData64(i));
- if(Door)
- Door->SetGoState(1);
+ if(GETCRE(Illidan, IllidanGUID))
+ {
+ Unit* target = ((boss_illidan_stormrageAI*)Illidan->AI())->SelectUnit(SELECT_TARGET_RANDOM, 0);
+
+ if(!target || !m_creature->IsWithinDistInMap(target, 80) || Illidan->IsWithinDistInMap(target, 20))
+ {
+ uint8 pos = rand()%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);
+ }
+ }
}
- if(IllidanGUID)
+ void UpdateAI(const uint32 diff)
{
- m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE);
- Creature* Illidan = ((Creature*)Unit::GetUnit((*m_creature), IllidanGUID));
- if(Illidan)
- {
- Illidan->RemoveAurasDueToSpell(SPELL_KNEEL); // Time for Illidan to stand up.
- // First line of Akama-Illidan convo
- ((boss_illidan_stormrageAI*)Illidan->AI())->TalkCount = 0;
- // Begin Talking
- ((boss_illidan_stormrageAI*)Illidan->AI())->IsTalking = true;
- ((boss_illidan_stormrageAI*)Illidan->AI())->AkamaGUID = m_creature->GetGUID();
- m_creature->SetUInt64Value(UNIT_FIELD_TARGET, Illidan->GetGUID());
- Illidan->SetUInt64Value(UNIT_FIELD_TARGET, m_creature->GetGUID());
- IsTalking = true; // Prevent Akama from starting to attack him
- // Prevent players from talking again
- m_creature->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP);
- m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE);
- Illidan->GetMotionMaster()->Clear(false);
- Illidan->GetMotionMaster()->MoveIdle();
- m_creature->GetMotionMaster()->Clear(false);
- m_creature->GetMotionMaster()->MoveIdle();
+ if((!m_creature->SelectHostilTarget() || !m_creature->getVictim()) && !Timer[1])
+ return;
- if(PlayerGUID)
+ Event = EVENT_MAIEV_NULL;
+ for(uint8 i = 1; i <= MaxTimer; i++)
+ if(Timer[i])
{
- Unit* player = Unit::GetUnit((*m_creature), PlayerGUID);
- if(player)
- Illidan->AddThreat(player, 100.0f);
+ if(Timer[i] <= diff)
+ Event = (EventMaiev)i;
+ else Timer[i] -= diff;
}
- }
+
+ switch(Event)
+ {
+ case EVENT_MAIEV_STEALTH:
+ {
+ m_creature->SetHealth(m_creature->GetMaxHealth());
+ m_creature->SetVisibility(VISIBILITY_ON);
+ m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE);
+ Timer[EVENT_MAIEV_STEALTH] = 0;
+ BlinkToPlayer();
+ EnterPhase(Phase);
+ }break;
+ case EVENT_MAIEV_TAUNT:
+ {
+ uint32 random = rand()%4;
+ char* text = MaievTaunts[random].text;
+ uint32 sound = MaievTaunts[random].sound;
+ DoYell(text, LANG_UNIVERSAL, NULL);
+ DoPlaySoundToSet(m_creature, sound);
+ Timer[EVENT_MAIEV_TAUNT] = 22000 + rand()%21 * 1000;
+ }break;
+ case EVENT_MAIEV_SHADOW_STRIKE:
+ DoCast(m_creature->getVictim(), SPELL_SHADOW_STRIKE);
+ Timer[EVENT_MAIEV_SHADOW_STRIKE] = 60000;
+ break;
+ case EVENT_MAIEV_TRAP:
+ if(Phase == PHASE_NORMAL_MAIEV)
+ {
+ BlinkToPlayer();
+ DoCast(m_creature, SPELL_CAGE_TRAP_SUMMON);
+ Timer[EVENT_MAIEV_TRAP] = 22000;
+ }
+ else
+ {
+ if(!m_creature->IsWithinDistInMap(m_creature->getVictim(), 40))
+ m_creature->GetMotionMaster()->MoveChase(m_creature->getVictim(), 30);
+ DoCast(m_creature->getVictim(), SPELL_THROW_DAGGER);
+ Timer[EVENT_MAIEV_THROW_DAGGER] = 2000;
+ }
+ break;
+ default:
+ break;
+ }
+
+ if(m_creature->GetHealth()*100 / m_creature->GetMaxHealth() < 50)
+ {
+ m_creature->SetVisibility(VISIBILITY_OFF);
+ m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE);
+ if(GETCRE(Illidan, IllidanGUID))
+ ((boss_illidan_stormrageAI*)Illidan->AI())->DeleteFromThreatList(m_creature->GetGUID());
+ m_creature->AttackStop();
+ Timer[EVENT_MAIEV_STEALTH] = 60000; //reappear after 1 minute
+ MaxTimer = 1;
+ }
+
+ if(Phase == PHASE_NORMAL_MAIEV)
+ DoMeleeAttackIfReady();
}
-}
+};
+
bool GossipSelect_npc_akama_at_illidan(Player *player, Creature *_Creature, uint32 sender, uint32 action)
{
- if(action == GOSSIP_ACTION_INFO_DEF) // Time to begin the event
+ if(action == GOSSIP_ACTION_INFO_DEF) // Time to begin the Event
{
player->CLOSE_GOSSIP_MENU();
- ((npc_akama_illidanAI*)_Creature->AI())->BeginDoorEvent(player);
+ ((npc_akama_illidanAI*)_Creature->AI())->EnterPhase(PHASE_CHANNEL);
}
return true;
}
@@ -1941,71 +1706,11 @@ bool GossipHello_npc_akama_at_illidan(Player *player, Creature *_Creature) return true;
}
-struct TRINITY_DLL_SPEC boss_maievAI : public ScriptedAI
-{
- boss_maievAI(Creature *c) : ScriptedAI(c)
- {
- pInstance = ((ScriptedInstance*)c->GetInstanceData());
- Reset();
- };
-
- uint32 TauntTimer;
- uint64 IllidanGUID;
-
- ScriptedInstance* pInstance;
-
- void Reset()
- {
- TauntTimer = 12000;
- IllidanGUID = 0;
- }
-
- void Aggro(Unit *who) {}
-
- void UpdateAI(const uint32 diff)
- {
- if(!IllidanGUID)
- {
- if(pInstance)
- IllidanGUID = pInstance->GetData64(DATA_ILLIDANSTORMRAGE);
- }else
- {
- Creature* Illidan = NULL;
- Illidan = ((Creature*)Unit::GetUnit((*m_creature), IllidanGUID));
- if(!Illidan || !Illidan->isAlive() || Illidan->IsInEvadeMode())
- {
- m_creature->SetVisibility(VISIBILITY_OFF);
- m_creature->DealDamage(m_creature, m_creature->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false);
- }
- else if(Illidan && ((Illidan->GetHealth()*100 / Illidan->GetMaxHealth()) < 2))
- return;
- }
-
- // Return if we don't have a target
- if(!m_creature->SelectHostilTarget() || !m_creature->getVictim())
- return;
-
- if(TauntTimer < diff)
- {
- uint32 random = rand()%4;
- char* text = MaievTaunts[random].text;
- uint32 sound = MaievTaunts[random].sound;
- DoYell(text, LANG_UNIVERSAL, NULL);
- DoPlaySoundToSet(m_creature, sound);
- TauntTimer = 22000 + rand()%21 * 1000;
- }else TauntTimer -= diff;
-
- DoMeleeAttackIfReady();
- }
-};
-
struct TRINITY_DLL_DECL cage_trap_triggerAI : public ScriptedAI
{
cage_trap_triggerAI(Creature *c) : ScriptedAI(c) {Reset();}
uint64 IllidanGUID;
- uint64 CageTrapGUID;
-
uint32 DespawnTimer;
bool Active;
@@ -2014,7 +1719,6 @@ struct TRINITY_DLL_DECL cage_trap_triggerAI : public ScriptedAI void Reset()
{
IllidanGUID = 0;
- CageTrapGUID = 0;
Active = false;
SummonedBeams = false;
@@ -2033,19 +1737,17 @@ struct TRINITY_DLL_DECL cage_trap_triggerAI : public ScriptedAI if(who && (who->GetTypeId() != TYPEID_PLAYER))
{
- if(who->GetEntry() == ILLIDAN_STORMRAGE) // Check if who is Illidan
+ if(who->GetEntry() == ILLIDAN_STORMRAGE) // Check if who is Illidan
{
- if(!IllidanGUID && m_creature->IsWithinDistInMap(who, 3) && !who->HasAura(SPELL_CAGED, 0))
+ if(!IllidanGUID && m_creature->IsWithinDistInMap(who, 3) && (!who->HasAura(SPELL_CAGED, 0)))
{
IllidanGUID = who->GetGUID();
who->CastSpell(who, SPELL_CAGED, true);
DespawnTimer = 5000;
if(who->HasAura(SPELL_ENRAGE, 0))
- // Dispel his enrage
- who->RemoveAurasDueToSpell(SPELL_ENRAGE);
-
- if(GameObject* CageTrap = GameObject::GetGameObject(*m_creature, CageTrapGUID))
- CageTrap->SetLootState(GO_JUST_DEACTIVATED);
+ who->RemoveAurasDueToSpell(SPELL_ENRAGE); // Dispel his enrage
+ //if(GameObject* CageTrap = GameObject::GetGameObject(*m_creature, CageTrapGUID))
+ // CageTrap->SetLootState(GO_JUST_DEACTIVATED);
}
}
}
@@ -2056,15 +1758,15 @@ struct TRINITY_DLL_DECL cage_trap_triggerAI : public ScriptedAI if(DespawnTimer)
if(DespawnTimer < diff)
m_creature->DealDamage(m_creature, m_creature->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false);
- else DespawnTimer -= diff;
-
- //if(IllidanGUID && !SummonedBeams)
- //{
- // if(Unit* Illidan = Unit::GetUnit(*m_creature, IllidanGUID)
- // {
- // //TODO: Find proper spells and properly apply 'caged' Illidan effect
- // }
- //}
+ else DespawnTimer -= diff;
+
+ //if(IllidanGUID && !SummonedBeams)
+ //{
+ // if(Unit* Illidan = Unit::GetUnit(*m_creature, IllidanGUID)
+ // {
+ // //TODO: Find proper spells and properly apply 'caged' Illidan effect
+ // }
+ //}
}
};
@@ -2089,143 +1791,213 @@ bool GOHello_cage_trap(Player* plr, GameObject* go) CellLock<GridReadGuard> cell_lock(cell, pair);
cell_lock->Visit(cell_lock, cSearcher, *(plr->GetMap()));
- if(!trigger)
- {
- plr->GetSession()->SendNotification("SD2: Summon failed. This trap is now useless.", LANG_UNIVERSAL, 0);
- error_log("SD2: Cage Trap- Unable to find trigger. This Cage Trap is now useless");
- return false;
- }
-
((cage_trap_triggerAI*)trigger->AI())->Active = true;
- go->SetGoState(0);
+ go->SetUInt32Value(GAMEOBJECT_STATE, 0);
return true;
}
-//This is used to sort the players by distance in preparation for being charged by the flames.
-struct TargetDistanceOrder : public std::binary_function<const Unit, const Unit, bool>
+struct TRINITY_DLL_DECL shadow_demonAI : public ScriptedAI
{
- const Unit* MainTarget;
- TargetDistanceOrder(const Unit* Target) : MainTarget(Target) {};
- // functor for operator ">"
- bool operator()(const Unit* _Left, const Unit* _Right) const
- {
- return (MainTarget->GetDistance(_Left) > MainTarget->GetDistance(_Right));
- }
-};
+ shadow_demonAI(Creature *c) : ScriptedAI(c) {Reset();}
-struct TRINITY_DLL_DECL flame_of_azzinothAI : public ScriptedAI
-{
- flame_of_azzinothAI(Creature *c) : ScriptedAI(c) {Reset();}
+ uint64 TargetGUID;
- uint32 FlameBlastTimer;
- uint32 SummonBlazeTimer;
- uint32 ChargeTimer;
+ void Aggro(Unit *who) {}
void Reset()
{
- FlameBlastTimer = 15000 + rand()%15000;
- SummonBlazeTimer = 10000 + rand()%20000;
- ChargeTimer = 5000;
+ TargetGUID = 0;
+ DoCast(m_creature, SPELL_SHADOW_DEMON_PASSIVE, true);
}
- void Aggro(Unit *who) {}
+ void JustDied(Unit *killer)
+ {
+ Unit* target = Unit::GetUnit((*m_creature), TargetGUID);
+ if(target)
+ target->RemoveAurasDueToSpell(SPELL_PARALYZE);
+ }
- void Charge()
+ void UpdateAI(const uint32 diff)
{
- // Get the Threat List
- std::list<HostilReference*>& m_threatlist = m_creature->getThreatManager().getThreatList();
+ if(!m_creature->SelectHostilTarget() || !m_creature->getVictim()) return;
- if(!m_threatlist.size()) return; // He doesn't have anyone in his threatlist, useless to continue
+ if(m_creature->getVictim()->GetTypeId() != TYPEID_PLAYER) return; // Only cast the below on players.
- std::list<Unit*> targets;
- std::list<HostilReference *>::iterator itr = m_threatlist.begin();
- for( ; itr!= m_threatlist.end(); ++itr) //store the threat list in a different container
+ if(!m_creature->getVictim()->HasAura(SPELL_PARALYZE, 0))
{
- Unit *target = Unit::GetUnit(*m_creature, (*itr)->getUnitGuid());
- //only on alive players
- if(target && target->isAlive() && target->GetTypeId() == TYPEID_PLAYER )
- targets.push_back( target);
+ TargetGUID = m_creature->getVictim()->GetGUID();
+ m_creature->AddThreat(m_creature->getVictim(), 10000000.0f);
+ DoCast(m_creature->getVictim(), SPELL_PURPLE_BEAM, true);
+ DoCast(m_creature->getVictim(), SPELL_PARALYZE, true);
}
+ // Kill our target if we're very close.
+ if(m_creature->IsWithinDistInMap(m_creature->getVictim(), 3))
+ DoCast(m_creature->getVictim(), SPELL_CONSUME_SOUL);
+ }
+};
- //Sort the list of players
- targets.sort(TargetDistanceOrder(m_creature));
- //Resize so we only get the furthest target
- targets.resize(1);
+// Shadowfiends interact with Illidan, setting more targets in Illidan's hashmap
+struct TRINITY_DLL_DECL mob_parasitic_shadowfiendAI : public ScriptedAI
+{
+ mob_parasitic_shadowfiendAI(Creature* c) : ScriptedAI(c)
+ {
+ pInstance = ((ScriptedInstance*)c->GetInstanceData());
+ Reset();
+ }
- Unit* target = (*targets.begin());
- if(target && (!m_creature->IsWithinDistInMap(target, 40)))
+ ScriptedInstance* pInstance;
+ uint64 IllidanGUID;
+ uint32 CheckTimer;
+
+ void Reset()
+ {
+ if(pInstance)
+ IllidanGUID = pInstance->GetData64(DATA_ILLIDANSTORMRAGE);
+ else
+ IllidanGUID = 0;
+
+ CheckTimer = 5000;
+ DoCast(m_creature, SPELL_SHADOWFIEND_PASSIVE, true);
+ }
+
+ void Aggro(Unit* who) {}
+ void MoveInLineOfSight(Unit *who){}
+
+ void DoMeleeAttackIfReady()
+ {
+ if( m_creature->isAttackReady() && m_creature->IsWithinDistInMap(m_creature->getVictim(), ATTACK_DISTANCE))
{
- DoCast(m_creature, SPELL_ENRAGE, true);
- DoCast(target, SPELL_CHARGE);
+ if(!m_creature->getVictim()->HasAura(SPELL_PARASITIC_SHADOWFIEND, 0))
+ {
+ m_creature->getVictim()->CastSpell(m_creature->getVictim(), SPELL_PARASITIC_SHADOWFIEND, true); //do not stack
+ if(GETCRE(Illidan, IllidanGUID))
+ ((boss_illidan_stormrageAI*)Illidan->AI())->AddParasiteTarget(m_creature->getVictim()->GetGUID());
+ }
+ m_creature->AttackerStateUpdate(m_creature->getVictim());
+ m_creature->resetAttackTimer();
}
}
void UpdateAI(const uint32 diff)
{
- // Return if we don't have a target
- if(!m_creature->SelectHostilTarget() || !m_creature->getVictim())
- return;
-
- if(FlameBlastTimer < diff)
- {
- DoCast(m_creature->getVictim(), SPELL_FLAME_BLAST);
- FlameBlastTimer = 30000;
- }else FlameBlastTimer -= diff;
-
- if(SummonBlazeTimer < diff)
+ if(!m_creature->getVictim())
{
- DoCast(m_creature, SPELL_BLAZE_SUMMON);
- SummonBlazeTimer = 30000 + rand()%20000;
- }else SummonBlazeTimer -= diff;
+ if(GETCRE(Illidan, IllidanGUID))
+ {
+ if(Illidan->getVictim() && !Illidan->getVictim()->HasAura(SPELL_PARASITIC_SHADOWFIEND, 0))
+ AttackStart(Illidan->getVictim());
+ else
+ AttackStart(((boss_illidan_stormrageAI*)Illidan->AI())->SelectUnit(SELECT_TARGET_RANDOM, 1));
+ }
+ }
+ else
+ DoMeleeAttackIfReady();
- if(ChargeTimer < diff)
+ if(CheckTimer < diff)
{
- Charge();
- ChargeTimer = 5000;
- }else ChargeTimer -= diff;
-
- DoMeleeAttackIfReady();
+ GETUNIT(Illidan, IllidanGUID);
+ if(!Illidan || ((Creature*)Illidan)->IsInEvadeMode())
+ {
+ m_creature->SetVisibility(VISIBILITY_OFF);
+ m_creature->setDeathState(JUST_DIED);
+ return;
+ }else CheckTimer = 5000;
+ }else CheckTimer -= diff;
}
};
-struct TRINITY_DLL_DECL shadow_demonAI : public ScriptedAI
+struct TRINITY_DLL_DECL demonfireAI : public ScriptedAI
{
- shadow_demonAI(Creature *c) : ScriptedAI(c) {Reset();}
+ demonfireAI(Creature *c) : ScriptedAI(c)
+ {
+ pInstance = ((ScriptedInstance*)c->GetInstanceData());
+ Reset();
+ }
- uint64 TargetGUID;
+ ScriptedInstance* pInstance;
+ uint64 IllidanGUID;
+ bool IsTrigger;
+ bool DemonFire;
+ uint32 CheckTimer;
+ uint32 DespawnTimer;
+
+ void Reset()
+ {
+ if(pInstance)
+ IllidanGUID = pInstance->GetData64(DATA_ILLIDANSTORMRAGE);
+ else
+ IllidanGUID = 0;
+
+ IsTrigger = false;
+ DemonFire = false;
- void Reset() { TargetGUID = 0; }
+ CheckTimer = 5000;
+ DespawnTimer = 78000; //spell duration, core bug, cannot despawn self
+ }
void Aggro(Unit *who) {}
+ void AttackStart(Unit* who) {}
+ void MoveInLineOfSight(Unit *who){}
- void JustDied(Unit *killer)
+ void UpdateAI(const uint32 diff)
{
- if(TargetGUID)
+ if(IsTrigger)
+ return;
+
+ if(!DemonFire)
+ DoCast(m_creature, SPELL_DEMON_FIRE); //duration 60s
+
+ if(CheckTimer < diff)
{
- Unit* target = Unit::GetUnit((*m_creature), TargetGUID);
- if(target)
- target->RemoveAurasDueToSpell(SPELL_PARALYZE);
- }
+ GETUNIT(Illidan, IllidanGUID);
+ if(!Illidan || !Illidan->HasUnitMovementFlag(MOVEMENTFLAG_LEVITATING))
+ {
+ m_creature->SetVisibility(VISIBILITY_OFF);
+ m_creature->setDeathState(JUST_DIED);
+ return;
+ }else CheckTimer = 5000;
+ }else CheckTimer -= diff;
+
+ if(DespawnTimer < diff)
+ {
+ m_creature->SetVisibility(VISIBILITY_OFF);
+ m_creature->setDeathState(JUST_DIED);
+ }else DespawnTimer -= diff;
}
+};
- void UpdateAI(const uint32 diff)
+struct TRINITY_DLL_DECL blazeAI : public ScriptedAI
+{
+ blazeAI(Creature *c) : ScriptedAI(c) {Reset();}
+
+ uint32 BlazeTimer;
+ uint32 DespawnTimer;
+
+ void Reset()
{
- if(!m_creature->SelectHostilTarget() || !m_creature->getVictim()) return;
+ BlazeTimer = 3000;
+ DespawnTimer = 60000; // Spell duration = 1 min
+ //((TemporarySummon*)m_creature)->Summon(TEMPSUMMON_TIMED_DESPAWN, 0, false);
+ }
- // Only cast the below on players.
- if(m_creature->getVictim()->GetTypeId() != TYPEID_PLAYER) return;
+ void Aggro(Unit *who) {}
+ void AttackStart(Unit* who) { }
+ void MoveInLineOfSight(Unit *who){ }
- if(!m_creature->getVictim()->HasAura(SPELL_PARALYZE, 0))
+ void UpdateAI(const uint32 diff)
+ {
+ if(BlazeTimer)
+ if(BlazeTimer <= diff)
+ {
+ DoCast(m_creature, SPELL_BLAZE_EFFECT);//duration 60s
+ BlazeTimer = 0;
+ }else BlazeTimer -= diff;
+
+ if(DespawnTimer < diff)
{
- TargetGUID = m_creature->getVictim()->GetGUID();
- m_creature->AddThreat(m_creature->getVictim(), 10000000.0f);
- DoCast(m_creature, SPELL_SHADOW_DEMON_PASSIVE, true);
- DoCast(m_creature->getVictim(), SPELL_PURPLE_BEAM, true);
- DoCast(m_creature->getVictim(), SPELL_PARALYZE, true);
- }
- // Kill our target if we're very close.
- if(m_creature->IsWithinDistInMap(m_creature->getVictim(), 3))
- DoCast(m_creature->getVictim(), SPELL_CONSUME_SOUL);
+ m_creature->SetVisibility(VISIBILITY_OFF);
+ m_creature->setDeathState(JUST_DIED);
+ }else DespawnTimer -= diff;
}
};
@@ -2233,112 +2005,377 @@ struct TRINITY_DLL_DECL flamecrashAI : public ScriptedAI {
flamecrashAI(Creature *c) : ScriptedAI(c) {Reset();}
- uint32 FlameCrashTimer;
uint32 DespawnTimer;
void Reset()
{
- FlameCrashTimer = 3000 +rand()%5000;
- DespawnTimer = 60000;
+ DoCast(m_creature, SPELL_FLAME_CRASH_EFFECT);//duration inf
+ DespawnTimer = 120000; // summon spell duration
}
- void Aggro(Unit *who){ return; }
-
+ void Aggro(Unit *who) {}
void AttackStart(Unit *who) { }
-
void MoveInLineOfSight(Unit *who){ }
void UpdateAI(const uint32 diff)
{
- if(FlameCrashTimer < diff)
- {
- DoCast(m_creature, SPELL_FLAME_CRASH_EFFECT);
- FlameCrashTimer = 15000;
- }else FlameCrashTimer -= diff;
-
if(DespawnTimer < diff)
{
- m_creature->SetVisibility(VISIBILITY_OFF); // So that players don't see the sparkly effect when we die.
- m_creature->DealDamage(m_creature, m_creature->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false);
+ m_creature->SetVisibility(VISIBILITY_OFF);
+ m_creature->setDeathState(JUST_DIED);
}else DespawnTimer -= diff;
}
};
-// Shadowfiends interact with Illidan, setting more targets in Illidan's hashmap
-struct TRINITY_DLL_SPEC mob_parasitic_shadowfiendAI : public ScriptedAI
+struct TRINITY_DLL_DECL blade_of_azzinothAI : public ScriptedAI
{
- mob_parasitic_shadowfiendAI(Creature* c) : ScriptedAI(c)
+ blade_of_azzinothAI(Creature* c) : ScriptedAI(c) {}
+ void Reset() {}
+ void Aggro(Unit *who) {}
+ void AttackStart(Unit* who) { }
+ void MoveInLineOfSight(Unit* who) { }
+
+ void SpellHit(Unit *caster, const SpellEntry *spell)
{
- Reset();
+ if(spell->Id == SPELL_THROW_GLAIVE2 || spell->Id == SPELL_THROW_GLAIVE)
+ m_creature->SetUInt32Value(UNIT_FIELD_DISPLAYID, 21431);//appear when hit by Illidan's glaive
}
+};
- void Reset() {}
+void boss_illidan_stormrageAI::Reset()
+{
+ if(pInstance)
+ pInstance->SetData(DATA_ILLIDANSTORMRAGEEVENT, NOT_STARTED);
- void Aggro(Unit* who) {}
+ for(uint8 i = 0; i < 2; i++)
+ {
+ if(FlameGUID[i])
+ {
+ if(GETUNIT(Flame, FlameGUID[i]))
+ Flame->setDeathState(JUST_DIED);
+ FlameGUID[i] = 0;
+ }
- void DoMeleeAttackIfReady()
+ if(GlaiveGUID[i])
+ {
+ if(GETUNIT(Glaive, GlaiveGUID[i]))
+ Glaive->setDeathState(JUST_DIED);
+ GlaiveGUID[i] = 0;
+ }
+ }
+
+ if(AkamaGUID)
{
- //If we are within range melee the target
- if( m_creature->IsWithinDistInMap(m_creature->getVictim(), ATTACK_DISTANCE))
+ if(GETCRE(Akama, AkamaGUID))
{
- //Make sure our attack is ready and we aren't currently casting
- if( m_creature->isAttackReady() && !m_creature->IsNonMeleeSpellCasted(false))
+ if(!Akama->isAlive())
+ Akama->Respawn();
+ else
{
- if(!m_creature->getVictim()->HasAura(SPELL_PARASITIC_SHADOWFIEND, 0))
- DoCast(m_creature->getVictim(), SPELL_PARASITIC_SHADOWFIEND, true);
- m_creature->AttackerStateUpdate(m_creature->getVictim());
- m_creature->resetAttackTimer();
+ ((npc_akama_illidanAI*)Akama->AI())->EnterEvadeMode();
+ Akama->GetMotionMaster()->MoveTargetedHome();
+ ((npc_akama_illidanAI*)Akama->AI())->Reset();
}
}
+ AkamaGUID = 0;
}
-};
-struct TRINITY_DLL_DECL blazeAI : public ScriptedAI
-{
- blazeAI(Creature *c) : ScriptedAI(c) {Reset();}
+ if(MaievGUID)
+ {
+ GETUNIT(Maiev, MaievGUID);
+ if(Maiev && Maiev->isAlive())
+ {
+ Maiev->CastSpell(Maiev, SPELL_TELEPORT_VISUAL, true);
+ Maiev->setDeathState(JUST_DIED);
+ }
+ MaievGUID = 0;
+ }
- uint32 BlazeTimer;
- uint32 DespawnTimer;
+ Phase = PHASE_NULL;
+ Event = EVENT_NULL;
+ Timer[EVENT_BERSERK] = 1500000;
- void Reset()
+ HoverPoint = 0;
+ TalkCount = 0;
+ FlightCount = 0;
+ TransformCount = 0;
+
+ ParasiteTargets.clear();
+
+ m_creature->SetUInt32Value(UNIT_FIELD_DISPLAYID, 21135);
+ m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE);
+ m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
+ m_creature->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_DISPLAY, 0);
+ m_creature->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_DISPLAY+1, 0);
+ m_creature->RemoveUnitMovementFlag(MOVEMENTFLAG_LEVITATING);
+
+ DoCast(m_creature, SPELL_DUAL_WIELD, true);
+}
+
+void boss_illidan_stormrageAI::HandleTalkSequence()
+{
+ switch(TalkCount)
{
- BlazeTimer = 2000;
- DespawnTimer = 15000;
+ case 0:
+ m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
+ break;
+ case 8:
+ m_creature->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_DISPLAY, 45479); // Equip our warglaives!
+ m_creature->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_DISPLAY+1, 45481);
+ m_creature->SetByteValue(UNIT_FIELD_BYTES_2, 0, SHEATH_STATE_MELEE );
+ m_creature->RemoveUnitMovementFlag(MOVEMENTFLAG_WALK_MODE);
+ break;
+ case 9:
+ if(GETCRE(Akama, AkamaGUID))
+ {
+ m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE + UNIT_FLAG_NOT_SELECTABLE);
+ m_creature->AddThreat(Akama, 100.0f);
+ ((npc_akama_illidanAI*)Akama->AI())->EnterPhase(PHASE_FIGHT_ILLIDAN);
+ EnterPhase(PHASE_NORMAL);
+ }
+ break;
+ case 10:
+ SummonMaiev();
+ break;
+ case 11:
+ if(GETUNIT(Maiev, MaievGUID))
+ {
+ Maiev->SetVisibility(VISIBILITY_ON); // Maiev is now visible
+ Maiev->CastSpell(Maiev, SPELL_TELEPORT_VISUAL, true); // onoz she looks like she teleported!
+ Maiev->SetInFront(m_creature); // Have her face us
+ m_creature->SetInFront(Maiev); // Face her, so it's not rude =P
+ Maiev->StopMoving();
+ m_creature->StopMoving();
+ }break;
+ case 14:
+ if(GETCRE(Maiev, MaievGUID))
+ {
+ m_creature->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(m_creature, 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(m_creature); // Force Maiev to attack us.
+ EnterPhase(PHASE_NORMAL_MAIEV);
+ }break;
+ case 15:
+ DoCast(m_creature, SPELL_DEATH); // Animate his kneeling + stun him
+ break;
+ case 17:
+ if(GETUNIT(Akama, AkamaGUID))
+ {
+ if(!m_creature->IsWithinDistInMap(Akama, 15))
+ {
+ float x, y, z;
+ m_creature->GetPosition(x, y, z);
+ x += 10; y += 10;
+ Akama->GetMotionMaster()->Clear(false);
+ //Akama->GetMotionMaster()->MoveIdle();
+ Akama->Relocate(x, y, z);
+ Akama->SendMonsterMove(x, y, z, 0, 0, 0);//Illidan must not die until Akama arrives.
+ Akama->GetMotionMaster()->MoveChase(m_creature);
+ }
+ }
+ break;
+ case 19: // Make Maiev leave
+ if(GETUNIT(Maiev, MaievGUID))
+ {
+ Maiev->CastSpell(Maiev, SPELL_TELEPORT_VISUAL, true);
+ Maiev->setDeathState(JUST_DIED);
+ m_creature->SetUInt32Value(UNIT_FIELD_BYTES_1,PLAYER_STATE_DEAD);
+ }
+ break;
+ case 21: // Kill ourself.
+ m_creature->DealDamage(m_creature, m_creature->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++;
+}
- void Aggro(Unit *who){ }
- void AttackStart(Unit* who) { }
+void boss_illidan_stormrageAI::CastEyeBlast()
+{
+ m_creature->InterruptNonMeleeSpells(false);
- void MoveInLineOfSight(Unit *who){ }
+ DoYell(SAY_EYE_BLAST, LANG_UNIVERSAL, NULL);
+ DoPlaySoundToSet(m_creature, SOUND_EYE_BLAST);
- void UpdateAI(const uint32 diff)
+ float distx, disty, dist[2];
+ for(uint8 i = 0; i < 2; ++i)
+ {
+ distx = EyeBlast[i].x - HoverPosition[HoverPoint].x;
+ disty = EyeBlast[i].y - HoverPosition[HoverPoint].y;
+ dist[i] = distx * distx + disty * disty;
+ }
+ Locations initial = EyeBlast[dist[0] < dist[1] ? 0 : 1];
+ for(uint8 i = 0; i < 2; ++i)
{
- if(BlazeTimer < diff)
+ distx = GlaivePosition[i].x - HoverPosition[HoverPoint].x;
+ disty = GlaivePosition[i].y - HoverPosition[HoverPoint].y;
+ dist[i] = distx * distx + disty * disty;
+ }
+ Locations final = GlaivePosition[dist[0] < dist[1] ? 0 : 1];
+
+ final.x = 2 * final.x - initial.x;
+ final.y = 2 * final.y - initial.y;
+
+ for(uint8 i = 0; i < 2; ++i)//core bug, two buff do not coexist
+ {
+ Creature* Trigger = NULL;
+ Trigger = m_creature->SummonCreature(DEMON_FIRE, initial.x, initial.y, initial.z, 0, TEMPSUMMON_TIMED_DESPAWN, 13000);
+ if(Trigger)
{
- DoCast(m_creature, SPELL_BLAZE_EFFECT);
- BlazeTimer = 15000;
- }else BlazeTimer -= diff;
+ ((demonfireAI*)Trigger->AI())->IsTrigger = true;
+ Trigger->SetSpeed(MOVE_WALK, 3);
+ Trigger->SetUnitMovementFlags(MOVEMENTFLAG_WALK_MODE);
+ Trigger->GetMotionMaster()->MovePoint(0, final.x, final.y, final.z);
- if(DespawnTimer < diff)
+ if(!i)
+ Trigger->CastSpell(Trigger, SPELL_EYE_BLAST_TRIGGER, true);
+ else
+ {
+ Trigger->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
+ m_creature->SetUInt64Value(UNIT_FIELD_TARGET, Trigger->GetGUID());
+ DoCast(Trigger, SPELL_EYE_BLAST);
+ }
+ }
+ }
+}
+
+void boss_illidan_stormrageAI::SummonFlamesOfAzzinoth()
+{
+ DoYell(SAY_SUMMONFLAMES, LANG_UNIVERSAL, NULL);
+ DoPlaySoundToSet(m_creature, SOUND_SUMMONFLAMES);
+
+ for(uint8 i = 0; i < 2; ++i)
+ {
+ if(GETUNIT(Glaive, GlaiveGUID[i]))
{
- m_creature->SetVisibility(VISIBILITY_OFF);
- m_creature->DealDamage(m_creature, m_creature->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false);
- }else DespawnTimer -= diff;
+ Creature* Flame = m_creature->SummonCreature(FLAME_OF_AZZINOTH, GlaivePosition[i+2].x, GlaivePosition[i+2].y, GlaivePosition[i+2].z, 0, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 5000);
+ if(Flame)
+ {
+ Flame->setFaction(m_creature->getFaction()); // Just in case the database has it as a different faction
+ Flame->SetMeleeDamageSchool(SPELL_SCHOOL_FIRE);
+ Flame->AI()->AttackStart(m_creature->getVictim()); // Attack our target!
+ FlameGUID[i] = Flame->GetGUID(); // Record GUID in order to check if they're dead later on to move to the next phase
+ ((flame_of_azzinothAI*)Flame->AI())->SetGlaiveGUID(GlaiveGUID[i]);
+ DoZoneInCombat(Flame);
+ Glaive->CastSpell(Flame, SPELL_AZZINOTH_CHANNEL, false); // Glaives do some random Beam type channel on it.
+ }
+ }
}
-};
+}
-struct TRINITY_DLL_DECL blade_of_azzinothAI : public ScriptedAI
+void boss_illidan_stormrageAI::SummonMaiev()
{
- blade_of_azzinothAI(Creature* c) : ScriptedAI(c) { Reset(); }
+ DoCast(m_creature, SPELL_SHADOW_PRISON, true);
+ Creature* Maiev = m_creature->SummonCreature(MAIEV_SHADOWSONG, m_creature->GetPositionX() + 10, m_creature->GetPositionY() + 5, m_creature->GetPositionZ(), 0, TEMPSUMMON_CORPSE_DESPAWN, 0);
+ if(Maiev)
+ {
+ Maiev->SetVisibility(VISIBILITY_OFF); // Leave her invisible until she has to talk
+ Maiev->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE);
+ MaievGUID = Maiev->GetGUID();
+ ((boss_maievAI*)Maiev->AI())->GetIllidanGUID(m_creature->GetGUID());
+ ((boss_maievAI*)Maiev->AI())->EnterPhase(PHASE_TALK_SEQUENCE);
+ }
+ else // If Maiev cannot be summoned, reset the encounter and post some errors to the console.
+ {
+ EnterEvadeMode();
+ DoTextEmote("is unable to summon Maiev Shadowsong and enter Phase 4. Resetting Encounter.", NULL);
+ error_log("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)");
+ }
+}
- void Reset() {}
- // Do-Nothing-But-Stand-There
- void Aggro(Unit* who) { }
- void AttackStart(Unit* who) { }
- void MoveInLineOfSight(Unit* who) { }
-};
+void boss_illidan_stormrageAI::EnterPhase(PhaseIllidan NextPhase)
+{
+ DoZoneInCombat();
+ switch(NextPhase)
+ {
+ case PHASE_NORMAL:
+ case PHASE_NORMAL_2:
+ case PHASE_NORMAL_MAIEV:
+ AttackStart(m_creature->getVictim());
+ Timer[EVENT_TAUNT] = 32000;
+ Timer[EVENT_SHEAR] = 10000 + rand()%15 * 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] = 30000 + rand()%10 * 1000;
+ break;
+ case PHASE_FLIGHT:
+ Timer[EVENT_FIREBALL] = 1000;
+ if(!(rand()%4))
+ Timer[EVENT_DARK_BARRAGE] = 10000;
+ Timer[EVENT_EYE_BLAST] = 10000 + rand()%15 * 1000;
+ Timer[EVENT_MOVE_POINT] = 20000 + rand()%20 * 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(m_creature->getVictim());
+ break;
+ case PHASE_TALK_SEQUENCE:
+ Timer[EVENT_TALK_SEQUENCE] = 100;
+ m_creature->RemoveAllAuras();
+ m_creature->InterruptNonMeleeSpells(false);
+ m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE + UNIT_FLAG_NOT_SELECTABLE);
+ m_creature->GetMotionMaster()->Clear(false);
+ //m_creature->GetMotionMaster()->MoveIdle();
+ m_creature->AttackStop();
+ break;
+ case PHASE_FLIGHT_SEQUENCE:
+ if(Phase == PHASE_FLIGHT) //land
+ Timer[EVENT_FLIGHT_SEQUENCE] = 2000;
+ else //lift off
+ {
+ FlightCount = 1;
+ Timer[EVENT_FLIGHT_SEQUENCE] = 1;
+ m_creature->RemoveAllAuras();
+ m_creature->InterruptNonMeleeSpells(false);
+ m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE + UNIT_FLAG_NOT_SELECTABLE);
+ m_creature->GetMotionMaster()->Clear(false);
+ //m_creature->GetMotionMaster()->MoveIdle();
+ m_creature->AttackStop();
+ }
+ break;
+ case PHASE_TRANSFORM_SEQUENCE:
+ if(Phase == PHASE_DEMON)
+ Timer[EVENT_TRANSFORM_SEQUENCE] = 500;
+ else
+ {
+ TransformCount = 0;
+ Timer[EVENT_TRANSFORM_SEQUENCE] = 500;
+ DoYell(SAY_MORPH, LANG_UNIVERSAL, NULL);
+ DoPlaySoundToSet(m_creature, SOUND_MORPH);
+ }
+ m_creature->GetMotionMaster()->Clear();
+ //m_creature->GetMotionMaster()->MoveIdle();
+ m_creature->AttackStop();
+ break;
+ default:
+ break;
+ }
+ if(MaievGUID)
+ {
+ GETCRE(Maiev, MaievGUID);
+ if(Maiev && Maiev->isAlive())
+ ((boss_maievAI*)Maiev->AI())->EnterPhase(NextPhase);
+ }
+ Phase = NextPhase;
+ Event = EVENT_NULL;
+}
CreatureAI* GetAI_boss_illidan_stormrage(Creature *_Creature)
{
@@ -2347,12 +2384,7 @@ CreatureAI* GetAI_boss_illidan_stormrage(Creature *_Creature) CreatureAI* GetAI_npc_akama_at_illidan(Creature *_Creature)
{
- npc_akama_illidanAI* Akama_AI = new npc_akama_illidanAI(_Creature);
-
- for(uint8 i = 0; i < 13; ++i)
- Akama_AI->AddWaypoint(i, AkamaWP[i].x, AkamaWP[i].y, AkamaWP[i].z);
-
- return ((CreatureAI*)Akama_AI);
+ return new npc_akama_illidanAI(_Creature);
}
CreatureAI* GetAI_boss_maiev(Creature *_Creature)
diff --git a/src/bindings/scripts/scripts/zone/black_temple/boss_mother_shahraz.cpp b/src/bindings/scripts/scripts/zone/black_temple/boss_mother_shahraz.cpp index d4e08f47f49..3c7345fa477 100644 --- a/src/bindings/scripts/scripts/zone/black_temple/boss_mother_shahraz.cpp +++ b/src/bindings/scripts/scripts/zone/black_temple/boss_mother_shahraz.cpp @@ -32,7 +32,7 @@ EndScriptData */ #define SPELL_ATTRACTION 40871
#define SPELL_SILENCING_SHRIEK 40823
#define SPELL_ENRAGE 23537
-#define SPELL_SABER_LASH 43267
+#define SPELL_SABER_LASH 40810//43267
#define SPELL_SABER_LASH_IMM 43690
#define SPELL_TELEPORT_VISUAL 40869
#define SPELL_BERSERK 45078
@@ -115,6 +115,7 @@ struct TRINITY_DLL_DECL boss_shahrazAI : public ScriptedAI uint32 FatalAttractionTimer;
uint32 FatalAttractionExplodeTimer;
uint32 ShriekTimer;
+ uint32 SaberTimer;
uint32 RandomYellTimer;
uint32 EnrageTimer;
uint32 ExplosionCount;
@@ -129,13 +130,14 @@ struct TRINITY_DLL_DECL boss_shahrazAI : public ScriptedAI for(uint8 i = 0; i<3; i++)
TargetGUID[i] = 0;
- BeamTimer = 60000; // Timers may be incorrect
+ BeamTimer = 20000; // Timers may be incorrect
BeamCount = 0;
CurrentBeam = 0; // 0 - Sinister, 1 - Vile, 2 - Wicked, 3 - Sinful
PrismaticShieldTimer = 0;
FatalAttractionTimer = 60000;
FatalAttractionExplodeTimer = 70000;
ShriekTimer = 30000;
+ SaberTimer = 35000;
RandomYellTimer = 70000 + rand()%41 * 1000;
EnrageTimer = 600000;
ExplosionCount = 0;
@@ -301,9 +303,15 @@ struct TRINITY_DLL_DECL boss_shahrazAI : public ScriptedAI if(ShriekTimer < diff)
{
DoCast(m_creature->getVictim(), SPELL_SILENCING_SHRIEK);
- ShriekTimer = 30000;
+ ShriekTimer = 25000+rand()%10 * 1000;
}else ShriekTimer -= diff;
+ if(SaberTimer < diff)
+ {
+ DoCast(m_creature->getVictim(), SPELL_SABER_LASH);
+ SaberTimer = 25000+rand()%10 * 1000;
+ }else SaberTimer -= diff;
+
//Enrage
if(!m_creature->HasAura(SPELL_BERSERK, 0))
if(EnrageTimer < diff)
diff --git a/src/bindings/scripts/scripts/zone/black_temple/boss_reliquary_of_souls.cpp b/src/bindings/scripts/scripts/zone/black_temple/boss_reliquary_of_souls.cpp index 1623847ded5..dc7539442f4 100644 --- a/src/bindings/scripts/scripts/zone/black_temple/boss_reliquary_of_souls.cpp +++ b/src/bindings/scripts/scripts/zone/black_temple/boss_reliquary_of_souls.cpp @@ -1,28 +1,29 @@ /* Copyright (C) 2006 - 2008 ScriptDev2 <https://scriptdev2.svn.sourceforge.net/>
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
+* This program is free software; you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation; either version 2 of the License, or
+* (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software
+* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
/* ScriptData
SDName: Boss_Reliquary_of_Souls
SD%Complete: 90
-SDComment: Persistent Area Auras for each Essence (Aura of Suffering, Aura of Desire, Aura of Anger) requires core support.
+SDComment:
SDCategory: Black Temple
EndScriptData */
#include "precompiled.h"
#include "def_black_temple.h"
+#include "Spell.h"
//Sound'n'speech
//Suffering
@@ -34,8 +35,8 @@ EndScriptData */ #define SUFF_SOUND_SLAY1 11417
#define SUFF_SAY_SLAY2 "I didn't ask for this!"
#define SUFF_SOUND_SLAY2 11418
-#define SUFF_SAY_SLAY3 "The pain is only beginning!"
-#define SUFF_SOUND_SLAY3 11419
+#define SUFF_SAY_ENRAGE "The pain is only beginning!"
+#define SUFF_SOUND_ENRAGE 11419
#define SUFF_SAY_RECAP "I don't want to go back!"
#define SUFF_SOUND_RECAP 11420
#define SUFF_SAY_AFTER "Now what do I do?"
@@ -60,8 +61,8 @@ EndScriptData */ //Anger
#define ANGER_SAY_FREED "Beware... I live."
#define ANGER_SOUND_FREED 11399
-#define ANGER_SAY_FREED2 "So... foolish."
-#define ANGER_SOUND_FREED2 11400
+#define ANGER_SAY_SCREAM "So... foolish."
+#define ANGER_SOUND_SCREAM 11400
#define ANGER_SOUND_SLAY1 11401
#define ANGER_SAY_SLAY2 "Enough. No more."
#define ANGER_SOUND_SLAY2 11402
@@ -74,29 +75,32 @@ EndScriptData */ //Spells
#define AURA_OF_SUFFERING 41292
-#define AURA_OF_SUFFERING_ARMOR 42017
-#define ESSENCE_OF_SUFFERING_PASSIVE 41296
+#define AURA_OF_SUFFERING_ARMOR 42017 // linked aura, need core support
+#define ESSENCE_OF_SUFFERING_PASSIVE 41296 // periodic trigger 41294
+#define ESSENCE_OF_SUFFERING_PASSIVE2 41623
+#define SPELL_FIXATE_TARGET 41294 // dummy, select target
+#define SPELL_FIXATE_TAUNT 41295 // force taunt
#define SPELL_ENRAGE 41305
#define SPELL_SOUL_DRAIN 41303
-#define SPELL_FIXATE 41295
#define AURA_OF_DESIRE 41350
+#define AURA_OF_DESIRE_DAMAGE 41352
#define SPELL_RUNE_SHIELD 41431
#define SPELL_DEADEN 41410
#define SPELL_SOUL_SHOCK 41426
#define AURA_OF_ANGER 41337
-#define SPELL_SELF_SEETHE 41364
+#define SPELL_SELF_SEETHE 41364 // force cast 41520
#define SPELL_ENEMY_SEETHE 41520
#define SPELL_SOUL_SCREAM 41545
-#define SPELL_SPITE 41377
+#define SPELL_SPITE_TARGET 41376 // cast 41377 after 6 sec
+#define SPELL_SPITE_DAMAGE 41377
#define ENSLAVED_SOUL_PASSIVE 41535
#define SPELL_SOUL_RELEASE 41542
-#define SPELL_RESTORE_MANA 32848
-#define SPELL_RESTORE_HEALTH 25329
#define CREATURE_ENSLAVED_SOUL 23469
+#define NUMBER_ENSLAVED_SOUL 8
struct Position
{
@@ -119,31 +123,12 @@ struct TRINITY_DLL_DECL npc_enslaved_soulAI : public ScriptedAI uint64 ReliquaryGUID;
- void Reset()
- {
- ReliquaryGUID = 0;
- }
+ void Reset() {ReliquaryGUID = 0;}
- void Aggro(Unit* who) {}
-
- void DamageTaken(Unit *done_by, uint32 &damage)
+ void Aggro(Unit* who)
{
- if(damage >= m_creature->GetHealth())
- {
- if(done_by->GetTypeId() == TYPEID_PLAYER)
- {
- done_by->CastSpell(done_by, SPELL_RESTORE_HEALTH, true);
- if(done_by->GetMaxPower(POWER_MANA) > 0)
- {
- if((done_by->GetPower(POWER_MANA) / done_by->GetMaxPower(POWER_MANA)) < 70)
- {
- uint32 mana = done_by->GetPower(POWER_MANA) + (uint32)(done_by->GetMaxPower(POWER_MANA)*0.3);
- done_by->SetPower(POWER_MANA, mana);
- }else done_by->SetPower(POWER_MANA, done_by->GetMaxPower(POWER_MANA));
- }
- }
- DoCast(done_by, SPELL_SOUL_RELEASE);
- }
+ m_creature->CastSpell(m_creature, ENSLAVED_SOUL_PASSIVE, true);
+ DoZoneInCombat();
}
void JustDied(Unit *killer);
@@ -151,137 +136,93 @@ struct TRINITY_DLL_DECL npc_enslaved_soulAI : public ScriptedAI struct TRINITY_DLL_DECL boss_reliquary_of_soulsAI : public ScriptedAI
{
- boss_reliquary_of_soulsAI(Creature *c) : ScriptedAI(c)
+ boss_reliquary_of_soulsAI(Creature *c) : ScriptedAI(c)
{
pInstance = ((ScriptedInstance*)c->GetInstanceData());
+ EssenceGUID = 0;
Reset();
}
ScriptedInstance* pInstance;
- uint64 SufferingGUID;
- uint64 DesireGUID;
- uint64 AngerGUID;
+ uint64 EssenceGUID;
- uint32 SoulDeathCount;
- // 0 = Out of Combat, 1 = Not started, 2 = Suffering, 3 = Souls, 4 = Desire, 5 = Souls, 6 = Anger
uint32 Phase;
- uint32 SummonEssenceTimer;
- uint32 DespawnEssenceTimer;
- uint32 SoulCount;
- uint32 SummonSoulTimer;
- uint32 AnimationTimer;
+ uint32 Counter;
+ uint32 Timer;
- bool IsDead;
- bool EndingPhase;
+ uint32 SoulCount;
+ uint32 SoulDeathCount;
void Reset()
{
if(pInstance)
pInstance->SetData(DATA_RELIQUARYOFSOULSEVENT, NOT_STARTED);
- DespawnEssences();
-
- SufferingGUID = 0;
- DesireGUID = 0;
- AngerGUID = 0;
+ if(EssenceGUID)
+ {
+ if(Unit* Essence = Unit::GetUnit(*m_creature, EssenceGUID))
+ {
+ Essence->SetVisibility(VISIBILITY_OFF);
+ Essence->setDeathState(DEAD);
+ }
+ EssenceGUID = 0;
+ }
- SoulDeathCount = 0;
Phase = 0;
- SummonEssenceTimer = 8000;
- DespawnEssenceTimer = 2000;
- SoulCount = 0;
- SummonSoulTimer = 1000;
- AnimationTimer = 8000;
- IsDead = false;
- EndingPhase = false;
-
- m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
m_creature->SetUInt32Value(UNIT_NPC_EMOTESTATE,0);
- m_creature->GetMotionMaster()->Clear(false);
}
- void Aggro(Unit* who) { }
+ void Aggro(Unit* who)
+ {
+ m_creature->AddThreat(who, 10000.0f);
+ DoZoneInCombat();
+ if(pInstance)
+ pInstance->SetData(DATA_RELIQUARYOFSOULSEVENT, IN_PROGRESS);
- void AttackStart(Unit* who) { }
+ Phase = 1;
+ Counter = 0;
+ Timer = 0;
+ }
void MoveInLineOfSight(Unit *who)
{
- if (who->isTargetableForAttack() && who->isInAccessablePlaceFor(m_creature) && m_creature->IsHostileTo(who))
+ if( !m_creature->getVictim() && who->isTargetableForAttack() && ( m_creature->IsHostileTo( who )) && who->isInAccessablePlaceFor(m_creature) )
{
+ if (m_creature->GetDistanceZ(who) > CREATURE_Z_ATTACK_RANGE)
+ return;
+
float attackRadius = m_creature->GetAttackDistance(who);
- if (m_creature->IsWithinDistInMap(who, attackRadius) && m_creature->GetDistanceZ(who) <= CREATURE_Z_ATTACK_RANGE && m_creature->IsWithinLOSInMap(who))
+ if( m_creature->IsWithinDistInMap(who, attackRadius) && m_creature->IsWithinLOSInMap(who) )
{
- if(who->HasStealthAura())
- who->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH);
+ who->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH);
- if(!InCombat)
+ if (!InCombat)
{
- if(pInstance)
- pInstance->SetData(DATA_RELIQUARYOFSOULSEVENT, IN_PROGRESS);
-
- Phase = 1;
- // I R ANNNGRRRY!
- m_creature->SetUInt32Value(UNIT_NPC_EMOTESTATE,375);
- SummonEssenceTimer = 8000;
- AnimationTimer = 5100;
- m_creature->AddThreat(who, 1.0f);
-
+ Aggro(who);
InCombat = true;
}
}
}
}
- void SummonSoul()
+ void AttackStart(Unit*) {}
+
+ bool SummonSoul()
{
uint32 random = rand()%6;
float x = Coords[random].x;
float y = Coords[random].y;
- Creature* Soul = m_creature->SummonCreature(CREATURE_ENSLAVED_SOUL, x, y, m_creature->GetPositionZ(), m_creature->GetOrientation(), TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 45000);
- Unit* target = SelectUnit(SELECT_TARGET_RANDOM, 0);
- if (target && Soul)
+ Creature* Soul = m_creature->SummonCreature(CREATURE_ENSLAVED_SOUL, x, y, m_creature->GetPositionZ(), m_creature->GetOrientation(), TEMPSUMMON_CORPSE_DESPAWN, 0);
+ if(!Soul) return false;
+ if(Unit* target = SelectUnit(SELECT_TARGET_RANDOM, 0))
{
((npc_enslaved_soulAI*)Soul->AI())->ReliquaryGUID = m_creature->GetGUID();
- Soul->CastSpell(Soul, ENSLAVED_SOUL_PASSIVE, true);
- Soul->AddThreat(target, 1.0f);
- SoulCount++;
- }
- }
-
- void MergeThreatList(Creature* target)
- {
- if(!target) return;
-
- std::list<HostilReference*>& m_threatlist = target->getThreatManager().getThreatList();
- std::list<HostilReference*>::iterator itr = m_threatlist.begin();
- for( ; itr != m_threatlist.end(); itr++)
- {
- Unit* pUnit = Unit::GetUnit((*m_creature), (*itr)->getUnitGuid());
- if(pUnit)
- {
- m_creature->AddThreat(pUnit, 1.0f); // This is so that we make sure the unit is in Reliquary's threat list before we reset the unit's threat.
- m_creature->getThreatManager().modifyThreatPercent(pUnit, -100);
- float threat = target->getThreatManager().getThreat(pUnit);
- m_creature->AddThreat(pUnit, threat); // This makes it so that the unit has the same amount of threat in Reliquary's threatlist as in the target creature's (One of the Essences).
- }
- }
- }
-
- void DespawnEssences()
- {
- // Despawn Essences
- Unit* Essence = NULL;
- if(SufferingGUID)
- Essence = ((Creature*)Unit::GetUnit((*m_creature), SufferingGUID));
- else if(DesireGUID)
- Essence = ((Creature*)Unit::GetUnit((*m_creature), DesireGUID));
- else if(AngerGUID)
- Essence = ((Creature*)Unit::GetUnit((*m_creature), AngerGUID));
- if(Essence && Essence->isAlive())
- Essence->setDeathState(JUST_DIED);
+ Soul->AI()->AttackStart(target);
+ }else EnterEvadeMode();
+ return true;
}
void JustDied(Unit* killer)
@@ -297,277 +238,108 @@ struct TRINITY_DLL_DECL boss_reliquary_of_soulsAI : public ScriptedAI if(!Phase)
return;
- // Reset if event is begun and we don't have a threatlist
- if(Phase && m_creature->getThreatManager().getThreatList().empty())
- EnterEvadeMode();
-
- if(Phase == 1)
+ if(m_creature->getThreatManager().getThreatList().empty()) // Reset if event is begun and we don't have a threatlist
{
- if(AnimationTimer < diff)
- {
- // Release the cube
- m_creature->SetUInt32Value(UNIT_NPC_EMOTESTATE,374);
- AnimationTimer = 8300;
- }else AnimationTimer -= diff;
-
- if(SummonEssenceTimer < diff)
- {
- // Ribs: open
- m_creature->SetUInt32Value(UNIT_NPC_EMOTESTATE,373);
- Creature* EssenceSuffering = NULL;
- EssenceSuffering = m_creature->SummonCreature(23418, m_creature->GetPositionX(), m_creature->GetPositionY(), m_creature->GetPositionZ(), 1.57, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 10000);
-
- if(EssenceSuffering)
- {
- EssenceSuffering->Yell(SUFF_SAY_FREED, LANG_UNIVERSAL, 0);
- DoPlaySoundToSet(m_creature, SUFF_SOUND_FREED);
- Unit* target = SelectUnit(SELECT_TARGET_TOPAGGRO, 0);
- if(target)
- {
- EssenceSuffering->AddThreat(target, 1.0f);
- EssenceSuffering->AI()->AttackStart(target);
- }
- SufferingGUID = EssenceSuffering->GetGUID();
- }
-
- EndingPhase = false;
- Phase = 2;
- }else SummonEssenceTimer -= diff;
+ EnterEvadeMode();
+ return;
}
- if(Phase == 2)
+ Creature* Essence;
+ if(EssenceGUID)
{
- if(SufferingGUID)
+ Essence = (Creature*)Unit::GetUnit(*m_creature, EssenceGUID);
+ if(!Essence)
{
- Creature* EssenceSuffering = NULL;
- EssenceSuffering = ((Creature*)Unit::GetUnit((*m_creature), SufferingGUID));
-
- if(!EssenceSuffering || (!EssenceSuffering->isAlive()))
- EnterEvadeMode();
-
- if(!EndingPhase)
- {
- if(EssenceSuffering)
- {
- if(EssenceSuffering->GetHealth() < (EssenceSuffering->GetMaxHealth()*0.1))
- {
- MergeThreatList(EssenceSuffering);
- EssenceSuffering->RemoveAllAuras();
- EssenceSuffering->DeleteThreatList();
- EssenceSuffering->GetMotionMaster()->MoveFollow(m_creature,0.0f,0.0f);
- EssenceSuffering->Yell(SUFF_SAY_RECAP,LANG_UNIVERSAL,0);
- DoPlaySoundToSet(m_creature, SUFF_SOUND_RECAP);
- EssenceSuffering->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
- DespawnEssenceTimer = 4000;
- AnimationTimer = 2200;
- EndingPhase = true;
- }
- }
- }
-
- if((EndingPhase) && (EssenceSuffering) && (EssenceSuffering->isAlive()))
- {
- if(AnimationTimer < diff)
- {
- // Return
- EssenceSuffering->SetUInt32Value(UNIT_NPC_EMOTESTATE,374);
- AnimationTimer = 10000;
- }else AnimationTimer -= diff;
-
- if(DespawnEssenceTimer < diff)
- {
- EssenceSuffering->DeleteThreatList();
- EssenceSuffering->Yell(SUFF_SAY_AFTER,LANG_UNIVERSAL,0);
- DoPlaySoundToSet(m_creature, SUFF_SOUND_AFTER);
- EssenceSuffering->SetUInt32Value(UNIT_FIELD_DISPLAYID, 11686);
- EssenceSuffering->setFaction(35);
- m_creature->SetUInt32Value(UNIT_NPC_EMOTESTATE,0);
- SummonEssenceTimer = 20000; //60000;
- AnimationTimer = 18200; //58100;
- SoulDeathCount = 0;
- SoulCount = 0;
- SummonSoulTimer = 1000;
- EndingPhase = false;
- Phase = 3;
- SufferingGUID = 0;
- }else DespawnEssenceTimer -= diff;
- }
+ EnterEvadeMode();
+ return;
}
}
- if(Phase == 3)
+ if(Timer < diff)
{
- if(SoulCount < 36)
+ switch(Counter)
{
- if(SummonSoulTimer < diff)
- {
- SummonSoul();
- SummonSoulTimer = 500;
- }else SummonSoulTimer -= diff;
- }
-
- if(SoulDeathCount >= SoulCount)
- {
- if(AnimationTimer < diff)
- {
- // Release the cube
- m_creature->SetUInt32Value(UNIT_NPC_EMOTESTATE,374);
- AnimationTimer = 10000;
- }else AnimationTimer -= diff;
-
- if(SummonEssenceTimer < diff)
+ case 0:
+ m_creature->SetUInt32Value(UNIT_NPC_EMOTESTATE,375); // I R ANNNGRRRY!
+ Timer = 3000;
+ break;
+ case 1:
+ Timer = 2800;
+ m_creature->SetUInt32Value(UNIT_NPC_EMOTESTATE,374); // Release the cube
+ break;
+ case 2:
+ Timer = 5000;
+ if(Creature* Summon = DoSpawnCreature(23417+Phase, 0, 0, 0, 0, TEMPSUMMON_DEAD_DESPAWN, 0))
{
- // Ribs: open
- m_creature->SetUInt32Value(UNIT_NPC_EMOTESTATE,373);
- Creature* EssenceDesire = NULL;
- EssenceDesire = m_creature->SummonCreature(23419, m_creature->GetPositionX(), m_creature->GetPositionY(), m_creature->GetPositionZ(), 1.57, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 10000);
-
- if(EssenceDesire)
- {
- EssenceDesire->Yell(DESI_SAY_FREED, LANG_UNIVERSAL, NULL);
- DoPlaySoundToSet(m_creature, DESI_SOUND_FREED);
- Unit* target = NULL;
- target = SelectUnit(SELECT_TARGET_RANDOM, 0);
- if(target)
- {
- EssenceDesire->AddThreat(target, 1.0f);
- EssenceDesire->AI()->AttackStart(target);
- }
- DesireGUID = EssenceDesire->GetGUID();
- SoulDeathCount = 0;
- }
-
- Phase = 4;
- }else SummonEssenceTimer -= diff;
- }
- }
-
- if(Phase == 4)
- {
- if(DesireGUID)
- {
- Creature* EssenceDesire = NULL;
- EssenceDesire = ((Creature*)Unit::GetUnit((*m_creature), DesireGUID));
-
- if(!EssenceDesire || !EssenceDesire->isAlive())
- EnterEvadeMode();
-
- if(!EndingPhase && EssenceDesire)
+ m_creature->SetUInt32Value(UNIT_NPC_EMOTESTATE,373); // Ribs: open
+ Summon->AI()->AttackStart(SelectUnit(SELECT_TARGET_TOPAGGRO, 0));
+ EssenceGUID = Summon->GetGUID();
+ }else EnterEvadeMode();
+ break;
+ case 3:
+ Timer = 1000;
+ if(Phase == 3)
{
- if(EssenceDesire->GetHealth() < (EssenceDesire->GetMaxHealth()*0.1))
- {
- MergeThreatList(EssenceDesire);
- EssenceDesire->GetMotionMaster()->MoveFollow(m_creature,0.0f,0.0f);
- EssenceDesire->RemoveAllAuras();
- EssenceDesire->DeleteThreatList();
- EssenceDesire->Yell(DESI_SAY_RECAP,LANG_UNIVERSAL,0);
- DoPlaySoundToSet(m_creature, DESI_SOUND_RECAP);
- EssenceDesire->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
- DespawnEssenceTimer = 4000;
- AnimationTimer = 2200;
- EndingPhase = true;
- }
+ if(!Essence->isAlive())
+ m_creature->CastSpell(m_creature, 7, true);
+ else return;
}
-
- if(EndingPhase && EssenceDesire)
+ else
{
- if(EssenceDesire->isAlive())
+ if(Essence->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE))
{
- if(AnimationTimer < diff)
- {
- // Return
- EssenceDesire->SetUInt32Value(UNIT_NPC_EMOTESTATE,374);
- AnimationTimer = 10000;
- }else AnimationTimer -= diff;
-
- if(DespawnEssenceTimer < diff)
- {
- EssenceDesire->DeleteThreatList();
- EssenceDesire->setFaction(35);
- EssenceDesire->Yell(DESI_SAY_AFTER, LANG_UNIVERSAL, 0);
- DoPlaySoundToSet(m_creature, DESI_SOUND_AFTER);
- EssenceDesire->SetUInt32Value(UNIT_FIELD_DISPLAYID, 11686);
- m_creature->SetUInt32Value(UNIT_NPC_EMOTESTATE,0);
- SummonEssenceTimer = 20000;
- AnimationTimer = 18200;
- SoulDeathCount = 0;
- SoulCount = 0;
- SummonSoulTimer = 1000;
- EndingPhase = false;
- Phase = 5;
- DesireGUID = 0;
- }else DespawnEssenceTimer -= diff;
- }
+ Essence->AI()->EnterEvadeMode();
+ Essence->GetMotionMaster()->MoveFollow(m_creature, 0, 0);
+ }else return;
}
- }
- }
-
- if(Phase == 5)
- {
- if(SoulCount < 36)
- {
- if(SummonSoulTimer < diff)
+ break;
+ case 4:
+ Timer = 1500;
+ if(Essence->IsWithinDistInMap(m_creature, 10))
+ Essence->SetUInt32Value(UNIT_NPC_EMOTESTATE, 374); //rotate and disappear
+ else
+ return;
+ break;
+ case 5:
+ if(Phase == 1)
{
- SummonSoul();
- SummonSoulTimer = 500;
- }else SummonSoulTimer -= diff;
- }
-
- if(SoulDeathCount >= SoulCount)
- {
- if(AnimationTimer < diff)
+ Essence->Yell(SUFF_SAY_AFTER,LANG_UNIVERSAL,0);
+ DoPlaySoundToSet(Essence, SUFF_SOUND_AFTER);
+ }
+ else
{
- // Release the cube
- m_creature->SetUInt32Value(UNIT_NPC_EMOTESTATE,374);
- AnimationTimer = 10000;
- }else AnimationTimer -= diff;
-
- if(SummonEssenceTimer < diff)
+ Essence->Yell(DESI_SAY_AFTER,LANG_UNIVERSAL,0);
+ DoPlaySoundToSet(Essence, DESI_SOUND_AFTER);
+ }
+ Essence->SetVisibility(VISIBILITY_OFF);
+ Essence->setDeathState(DEAD);
+ m_creature->SetUInt32Value(UNIT_NPC_EMOTESTATE,0);
+ EssenceGUID = 0;
+ SoulCount = 0;
+ SoulDeathCount = 0;
+ Timer = 3000;
+ break;
+ case 6:
+ if(SoulCount < NUMBER_ENSLAVED_SOUL)
{
- // Ribs: open
- m_creature->SetUInt32Value(UNIT_NPC_EMOTESTATE,373);
- Creature* EssenceAnger = NULL;
- EssenceAnger = m_creature->SummonCreature(23420, m_creature->GetPositionX(), m_creature->GetPositionY(), m_creature->GetPositionZ(), 1.57, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, 45000);
-
- if(EssenceAnger)
- {
- Unit* target = SelectUnit(SELECT_TARGET_TOPAGGRO, 0);
- if(target)
- {
- EssenceAnger->AddThreat(target, 1.0f);
- EssenceAnger->AI()->AttackStart(target);
- }
- AngerGUID = EssenceAnger->GetGUID();
- DoPlaySoundToSet(m_creature, ANGER_SOUND_FREED);
- EssenceAnger->Yell(ANGER_SAY_FREED, LANG_UNIVERSAL, 0);
- SoulDeathCount = 0;
- }
-
- Phase = 6;
- }else SummonEssenceTimer -= diff;
- }
- }
-
- if(Phase == 6)
- {
- if(AngerGUID)
- {
- Creature* EssenceAnger = NULL;
- EssenceAnger = ((Creature*)Unit::GetUnit((*m_creature), AngerGUID));
-
- if(!EssenceAnger)
- EnterEvadeMode();
-
- if(m_creature->isAlive() && EssenceAnger)
+ if(SummonSoul())
+ SoulCount++;
+ Timer = 500;
+ return;
+ }break;
+ case 7:
+ if(SoulDeathCount >= SoulCount)
{
- if(!EssenceAnger->isAlive())
- {
- AngerGUID = 0;
- m_creature->DealDamage(m_creature, m_creature->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false);
- }
+ Counter = 1;
+ Phase++;
+ Timer = 5000;
}
+ return;
+ default:
+ break;
}
- }
+ Counter++;
+ }else Timer -= diff;
}
};
@@ -593,259 +365,215 @@ struct TRINITY_DLL_DECL boss_essence_of_sufferingAI : public ScriptedAI uint32 FixateTimer;
uint32 EnrageTimer;
uint32 SoulDrainTimer;
+ uint32 AuraTimer;
void Reset()
{
StatAuraGUID = 0;
AggroYellTimer = 5000;
- FixateTimer = 5000;
+ FixateTimer = 8000;
EnrageTimer = 30000;
- SoulDrainTimer = 150000;
+ SoulDrainTimer = 45000;
+ AuraTimer = 5000;
}
void DamageTaken(Unit *done_by, uint32 &damage)
{
- if((damage >= m_creature->GetHealth()) && (done_by != m_creature))
+ if(damage >= m_creature->GetHealth())
{
damage = 0;
- // 10% of total health, signalling time to return
- m_creature->SetHealth(m_creature->GetMaxHealth()/10);
- if(StatAuraGUID)
- {
- Unit* pUnit = Unit::GetUnit((*m_creature), StatAuraGUID);
- if(pUnit)
- pUnit->RemoveAurasDueToSpell(AURA_OF_SUFFERING_ARMOR);
- }
+ m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
+ m_creature->Yell(SUFF_SAY_RECAP,LANG_UNIVERSAL,0);
+ DoPlaySoundToSet(m_creature, SUFF_SOUND_RECAP);
}
}
void Aggro(Unit *who)
{
+ m_creature->Yell(SUFF_SAY_FREED, LANG_UNIVERSAL, 0);
+ DoPlaySoundToSet(m_creature, SUFF_SOUND_FREED);
DoZoneInCombat();
- DoCast(who, AURA_OF_SUFFERING, true);
- DoCast(m_creature, ESSENCE_OF_SUFFERING_PASSIVE, true);
+ m_creature->CastSpell(m_creature, AURA_OF_SUFFERING, true); // linked aura need core support
+ m_creature->CastSpell(m_creature, ESSENCE_OF_SUFFERING_PASSIVE, true);
+ m_creature->CastSpell(m_creature, ESSENCE_OF_SUFFERING_PASSIVE2, true);
}
void KilledUnit(Unit *victim)
{
- switch(rand()%3)
+ switch(rand()%2)
{
- case 0:
- DoYell(SUFF_SAY_SLAY1,LANG_UNIVERSAL,NULL);
- DoPlaySoundToSet(m_creature, SUFF_SOUND_SLAY1);
- break;
- case 1:
- DoYell(SUFF_SAY_SLAY2,LANG_UNIVERSAL,NULL);
- DoPlaySoundToSet(m_creature, SUFF_SOUND_SLAY2);
- break;
- case 2:
- DoYell(SUFF_SAY_SLAY3,LANG_UNIVERSAL,NULL);
- DoPlaySoundToSet(m_creature, SUFF_SOUND_SLAY3);
- break;
+ case 0:
+ DoYell(SUFF_SAY_SLAY1,LANG_UNIVERSAL,NULL);
+ DoPlaySoundToSet(m_creature, SUFF_SOUND_SLAY1);
+ break;
+ case 1:
+ DoYell(SUFF_SAY_SLAY2,LANG_UNIVERSAL,NULL);
+ DoPlaySoundToSet(m_creature, SUFF_SOUND_SLAY2);
+ break;
}
}
- void JustDied(Unit* killer)
- {
- }
-
void CastFixate()
{
std::list<HostilReference*>& m_threatlist = m_creature->getThreatManager().getThreatList();
if(m_threatlist.empty())
- return; // No point continuing if empty threatlist.
+ return; // No point continuing if empty threatlist.
std::list<Unit*> targets;
std::list<HostilReference*>::iterator itr = m_threatlist.begin();
for( ; itr != m_threatlist.end(); ++itr)
{
Unit* pUnit = Unit::GetUnit((*m_creature), (*itr)->getUnitGuid());
- // Only alive players
- if(pUnit && pUnit->isAlive() && (pUnit->GetTypeId() == TYPEID_PLAYER))
+ if(pUnit && pUnit->isAlive() && (pUnit->GetTypeId() == TYPEID_PLAYER)) // Only alive players
targets.push_back(pUnit);
}
if(targets.empty())
- return; // No targets added for some reason. No point continuing.
- targets.sort(TargetDistanceOrder(m_creature)); // Sort players by distance.
- targets.resize(1); // Only need closest target.
- Unit* target = targets.front(); // Get the first target.
- // Add threat equivalent to threat on victim.
- m_creature->AddThreat(target, m_creature->getThreatManager().getThreat(m_creature->getVictim()));
- DoCast(target, SPELL_FIXATE);
+ return; // No targets added for some reason. No point continuing.
+ targets.sort(TargetDistanceOrder(m_creature)); // Sort players by distance.
+ targets.resize(1); // Only need closest target.
+ Unit* target = targets.front(); // Get the first target.
+ target->CastSpell(m_creature, SPELL_FIXATE_TAUNT, true);
}
void UpdateAI(const uint32 diff)
{
//Return since we have no target
- if (!m_creature->SelectHostilTarget() || !m_creature->getVictim())
+ if (!m_creature->SelectHostilTarget() && !m_creature->getVictim())
return;
- if(m_creature->GetHealth() <= (m_creature->GetMaxHealth()*0.1))
- {
- if(StatAuraGUID)
- {
- Unit* pUnit = NULL;
- pUnit = Unit::GetUnit((*m_creature), StatAuraGUID);
- if(pUnit)
- pUnit->RemoveAurasDueToSpell(AURA_OF_SUFFERING_ARMOR);
- }
- }
-
- if(m_creature->GetHealth() <= (m_creature->GetMaxHealth()*0.1))
- {
- if(m_creature->getVictim())
- m_creature->DeleteThreatList(); // Delete our threatlist if below 10% as we should no longer attack.
- return;
- }
-
- // Prevent overlapping yells
- if(AggroYellTimer)
- if(AggroYellTimer < diff)
- {
- DoYell(SUFF_SAY_AGGRO, LANG_UNIVERSAL, NULL);
- DoPlaySoundToSet(m_creature, SUFF_SOUND_AGGRO);
- AggroYellTimer = 0;
- }else AggroYellTimer -= diff;
-
//Supposed to be cast on nearest target
if(FixateTimer < diff)
{
CastFixate();
FixateTimer = 5000;
+ if(!(rand()%16))
+ {
+ DoYell(SUFF_SAY_AGGRO,LANG_UNIVERSAL,NULL);
+ DoPlaySoundToSet(m_creature, SUFF_SOUND_AGGRO);
+ }
}else FixateTimer -= diff;
if(EnrageTimer < diff)
{
DoCast(m_creature, SPELL_ENRAGE);
EnrageTimer = 60000;
+ DoYell(SUFF_SAY_ENRAGE,LANG_UNIVERSAL,NULL);
+ DoPlaySoundToSet(m_creature, SUFF_SOUND_ENRAGE);
}else EnrageTimer -= diff;
if(SoulDrainTimer < diff)
{
- Unit* target = NULL;
- target = SelectUnit(SELECT_TARGET_RANDOM, 0);
-
- if(target)
- DoCast(target, SPELL_SOUL_DRAIN);
+ DoCast(m_creature, SPELL_SOUL_DRAIN);
SoulDrainTimer = 60000;
}else SoulDrainTimer -= diff;
DoMeleeAttackIfReady();
}
};
+
struct TRINITY_DLL_DECL boss_essence_of_desireAI : public ScriptedAI
{
boss_essence_of_desireAI(Creature *c) : ScriptedAI(c) {Reset();}
- uint32 AggroYellTimer;
uint32 RuneShieldTimer;
uint32 DeadenTimer;
uint32 SoulShockTimer;
void Reset()
{
- AggroYellTimer = 5000;
RuneShieldTimer = 60000;
- DeadenTimer = 15000;
- SoulShockTimer = 40000;
+ DeadenTimer = 30000;
+ SoulShockTimer = 5000;
+ m_creature->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_MOD_CONFUSE, true);
}
void DamageTaken(Unit *done_by, uint32 &damage)
{
- if((damage >= m_creature->GetHealth()) && (done_by != m_creature))
+ if(done_by == m_creature)
+ return;
+
+ if(damage >= m_creature->GetHealth())
{
damage = 0;
- // 10% of total health, signalling time to return
- m_creature->SetHealth(m_creature->GetMaxHealth()/10);
+ m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
+ m_creature->Yell(DESI_SAY_RECAP,LANG_UNIVERSAL,0);
+ DoPlaySoundToSet(m_creature, DESI_SOUND_RECAP);
}
else
{
- if(done_by && (done_by->GetTypeId() == TYPEID_PLAYER) && done_by->isAlive())
- done_by->DealDamage(done_by, damage/2, NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false);
+ int32 bp0 = damage / 2;
+ m_creature->CastCustomSpell(done_by, AURA_OF_DESIRE_DAMAGE, &bp0, NULL, NULL, true);
}
}
- void Aggro(Unit *who) { DoZoneInCombat(); }
-
- void KilledUnit(Unit *victim)
+ void SpellHit(Unit *caster, const SpellEntry *spell)
{
- switch(rand()%3)
- {
- case 0:
- DoYell(DESI_SAY_SLAY1,LANG_UNIVERSAL,NULL);
- DoPlaySoundToSet(m_creature, DESI_SOUND_SLAY1);
- break;
- case 1:
- DoYell(DESI_SAY_SLAY2,LANG_UNIVERSAL,NULL);
- DoPlaySoundToSet(m_creature, DESI_SOUND_SLAY2);
- break;
- case 2:
- DoYell(DESI_SAY_SLAY3,LANG_UNIVERSAL,NULL);
- DoPlaySoundToSet(m_creature, DESI_SOUND_SLAY3);
- break;
- }
+ if(m_creature->m_currentSpells[CURRENT_GENERIC_SPELL])
+ for(uint8 i = 0; i < 3; ++i)
+ if(spell->Effect[i] == SPELL_EFFECT_INTERRUPT_CAST)
+ if(m_creature->m_currentSpells[CURRENT_GENERIC_SPELL]->m_spellInfo->Id == SPELL_SOUL_SHOCK
+ || m_creature->m_currentSpells[CURRENT_GENERIC_SPELL]->m_spellInfo->Id == SPELL_DEADEN)
+ m_creature->InterruptSpell(CURRENT_GENERIC_SPELL, false);
}
- void MoveInLineOfSight(Unit *who)
+ void Aggro(Unit *who)
{
- if (!who || m_creature->getVictim())
- return;
+ m_creature->Yell(DESI_SAY_FREED, LANG_UNIVERSAL, 0);
+ DoPlaySoundToSet(m_creature, DESI_SOUND_FREED);
+ DoZoneInCombat();
+ DoCast(m_creature, AURA_OF_DESIRE, true);
+ }
- if (who->isTargetableForAttack() && who->isInAccessablePlaceFor(m_creature) && m_creature->IsHostileTo(who))
+ void KilledUnit(Unit *victim)
+ {
+ switch(rand()%3)
{
- float attackRadius = m_creature->GetAttackDistance(who);
- if (m_creature->IsWithinDistInMap(who, attackRadius) && m_creature->GetDistanceZ(who) <= CREATURE_Z_ATTACK_RANGE && m_creature->IsWithinLOSInMap(who))
- {
- if(who->HasStealthAura())
- who->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH);
-
- //Begin melee attack if we are within range
- DoStartAttackAndMovement(who);
-
- if (!InCombat)
- {
- DoCast(who, AURA_OF_DESIRE);
- }
- }
+ case 0:
+ DoYell(DESI_SAY_SLAY1,LANG_UNIVERSAL,NULL);
+ DoPlaySoundToSet(m_creature, DESI_SOUND_SLAY1);
+ break;
+ case 1:
+ DoYell(DESI_SAY_SLAY2,LANG_UNIVERSAL,NULL);
+ DoPlaySoundToSet(m_creature, DESI_SOUND_SLAY2);
+ break;
+ case 2:
+ DoYell(DESI_SAY_SLAY3,LANG_UNIVERSAL,NULL);
+ DoPlaySoundToSet(m_creature, DESI_SOUND_SLAY3);
+ break;
}
}
void UpdateAI(const uint32 diff)
{
- //Return since we have no target
- if (!m_creature->SelectHostilTarget() || !m_creature->getVictim())
+ if (!m_creature->SelectHostilTarget() && !m_creature->getVictim())
return;
- if(m_creature->GetHealth() <= (m_creature->GetMaxHealth()*0.1))
- {
- if(m_creature->getVictim())
- m_creature->DeleteThreatList(); // Delete our threatlist if below 10% as we should no longer attack.
- return;
- }
-
if(RuneShieldTimer < diff)
{
- DoCast(m_creature, SPELL_RUNE_SHIELD);
+ m_creature->InterruptNonMeleeSpells(false);
+ m_creature->CastSpell(m_creature, SPELL_RUNE_SHIELD, true);
+ SoulShockTimer += 2000;
+ DeadenTimer += 2000;
RuneShieldTimer = 60000;
}else RuneShieldTimer -= diff;
- if(DeadenTimer < diff)
- {
- DoCast(m_creature->getVictim(), SPELL_DEADEN);
- DeadenTimer = 30000 + rand()%30001;
- }else DeadenTimer -= diff;
-
if(SoulShockTimer < diff)
{
DoCast(m_creature->getVictim(), SPELL_SOUL_SHOCK);
- SoulShockTimer = 40000;
- if(rand()%2 == 0)
+ SoulShockTimer = 5000;
+ }else SoulShockTimer -= diff;
+
+ if(DeadenTimer < diff)
+ {
+ m_creature->InterruptNonMeleeSpells(false);
+ DoCast(m_creature->getVictim(), SPELL_DEADEN);
+ DeadenTimer = 25000 + rand()%10000;
+ if(!(rand()%2))
{
DoYell(DESI_SAY_SPEC,LANG_UNIVERSAL,NULL);
DoPlaySoundToSet(m_creature, DESI_SOUND_SPEC);
}
-
- }else SoulShockTimer -= diff;
+ }else DeadenTimer -= diff;
DoMeleeAttackIfReady();
}
@@ -857,53 +585,33 @@ struct TRINITY_DLL_DECL boss_essence_of_angerAI : public ScriptedAI uint64 AggroTargetGUID;
- uint32 AggroYellTimer;
uint32 CheckTankTimer;
uint32 SoulScreamTimer;
uint32 SpiteTimer;
+ std::list<uint64> SpiteTargetGUID;
+
bool CheckedAggro;
void Reset()
{
AggroTargetGUID = 0;
- AggroYellTimer = 5000;
CheckTankTimer = 5000;
SoulScreamTimer = 10000;
SpiteTimer = 30000;
+ SpiteTargetGUID.clear();
+
CheckedAggro = false;
}
void Aggro(Unit *who)
{
+ m_creature->Yell(ANGER_SAY_FREED, LANG_UNIVERSAL, 0);
+ DoPlaySoundToSet(m_creature, ANGER_SOUND_FREED);
DoZoneInCombat();
- DoCast(m_creature->getVictim(), AURA_OF_ANGER, true);
- }
-
- void MoveInLineOfSight(Unit *who)
- {
- if (!who || m_creature->getVictim())
- return;
-
- if (who->isTargetableForAttack() && who->isInAccessablePlaceFor(m_creature) && m_creature->IsHostileTo(who))
- {
- float attackRadius = m_creature->GetAttackDistance(who);
- if (m_creature->IsWithinDistInMap(who, attackRadius) && m_creature->GetDistanceZ(who) <= CREATURE_Z_ATTACK_RANGE && m_creature->IsWithinLOSInMap(who))
- {
- if(who->HasStealthAura())
- who->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH);
-
- //Begin melee attack if we are within range
- DoStartAttackAndMovement(who);
-
- if (!InCombat)
- {
- DoCast(who, AURA_OF_ANGER);
- }
- }
- }
+ DoCast(m_creature, AURA_OF_ANGER, true);
}
void JustDied(Unit *victim)
@@ -916,20 +624,59 @@ struct TRINITY_DLL_DECL boss_essence_of_angerAI : public ScriptedAI {
switch(rand()%2)
{
- case 0:
- DoPlaySoundToSet(m_creature, ANGER_SOUND_SLAY1);
- break;
- case 1:
- DoYell(ANGER_SAY_SLAY2,LANG_UNIVERSAL,NULL);
- DoPlaySoundToSet(m_creature, ANGER_SOUND_SLAY2);
- break;
+ case 0:
+ DoPlaySoundToSet(m_creature, ANGER_SOUND_SLAY1);
+ break;
+ case 1:
+ DoYell(ANGER_SAY_SLAY2,LANG_UNIVERSAL,NULL);
+ DoPlaySoundToSet(m_creature, ANGER_SOUND_SLAY2);
+ break;
+ }
+ }
+
+ void SelectSpiteTarget(uint32 num, float max_range = 999)
+ {
+ if(!num) return;
+
+ CellPair p(Trinity::ComputeCellPair(m_creature->GetPositionX(), m_creature->GetPositionY()));
+ Cell cell(p);
+ cell.data.Part.reserved = ALL_DISTRICT;
+ cell.SetNoCreate();
+
+ std::list<Unit *> tempUnitMap;
+
+ {
+ Trinity::AnyAoETargetUnitInObjectRangeCheck u_check(m_creature, m_creature, max_range);
+ Trinity::UnitListSearcher<Trinity::AnyAoETargetUnitInObjectRangeCheck> searcher(tempUnitMap, u_check);
+
+ TypeContainerVisitor<Trinity::UnitListSearcher<Trinity::AnyAoETargetUnitInObjectRangeCheck>, WorldTypeMapContainer > world_unit_searcher(searcher);
+ TypeContainerVisitor<Trinity::UnitListSearcher<Trinity::AnyAoETargetUnitInObjectRangeCheck>, GridTypeMapContainer > grid_unit_searcher(searcher);
+
+ CellLock<GridReadGuard> cell_lock(cell, p);
+ cell_lock->Visit(cell_lock, world_unit_searcher, *(m_creature->GetMap()));
+ cell_lock->Visit(cell_lock, grid_unit_searcher, *(m_creature->GetMap()));
+ }
+
+ std::list<Unit*>::iterator itr;
+ while(tempUnitMap.size() && SpiteTargetGUID.size() < num)
+ {
+ itr = tempUnitMap.begin();
+ advance(itr, rand()%tempUnitMap.size());
+ SpiteTargetGUID.push_back((*itr)->GetGUID());
+ tempUnitMap.erase(itr);
}
+
+ for(itr = tempUnitMap.begin(); itr != tempUnitMap.end(); ++itr)
+ (*itr)->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
+ m_creature->CastSpell(m_creature, SPELL_SPITE_TARGET, true); // must true
+ for(itr = tempUnitMap.begin(); itr != tempUnitMap.end(); ++itr)
+ (*itr)->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
}
void UpdateAI(const uint32 diff)
{
//Return since we have no target
- if (!m_creature->SelectHostilTarget() || !m_creature->getVictim())
+ if (!m_creature->SelectHostilTarget() && !m_creature->getVictim())
return;
if(!CheckedAggro)
@@ -938,22 +685,13 @@ struct TRINITY_DLL_DECL boss_essence_of_angerAI : public ScriptedAI CheckedAggro = true;
}
- if(AggroYellTimer)
- if(AggroYellTimer < diff)
- {
- DoYell(ANGER_SAY_FREED2,LANG_UNIVERSAL,NULL);
- DoPlaySoundToSet(m_creature, ANGER_SOUND_FREED2);
- AggroYellTimer = 0;
- }else AggroYellTimer -= diff;
-
if(CheckTankTimer < diff)
{
if(m_creature->getVictim()->GetGUID() != AggroTargetGUID)
- {
+ {
DoYell(ANGER_SAY_BEFORE,LANG_UNIVERSAL,NULL);
DoPlaySoundToSet(m_creature, ANGER_SOUND_BEFORE);
- DoCast(m_creature, SPELL_SELF_SEETHE);
- DoCast(m_creature->getVictim(), SPELL_ENEMY_SEETHE, true);
+ DoCast(m_creature, SPELL_SELF_SEETHE, true);
AggroTargetGUID = m_creature->getVictim()->GetGUID();
}
CheckTankTimer = 2000;
@@ -963,23 +701,35 @@ struct TRINITY_DLL_DECL boss_essence_of_angerAI : public ScriptedAI {
DoCast(m_creature->getVictim(), SPELL_SOUL_SCREAM);
SoulScreamTimer = 10000;
+ if(!(rand()%3))
+ {
+ DoYell(ANGER_SAY_SCREAM,LANG_UNIVERSAL,NULL);
+ DoPlaySoundToSet(m_creature, ANGER_SOUND_SCREAM);
+ }
}else SoulScreamTimer -= diff;
if(SpiteTimer < diff)
{
- for(uint8 i = 0; i < 4; i++)
+ if(!SpiteTargetGUID.empty())
{
- Unit* target = NULL;
- target = SelectUnit(SELECT_TARGET_RANDOM, 0);
-
- if(target)
- DoCast(target, SPELL_SPITE);
-
+ for (std::list<uint64>::iterator itr = SpiteTargetGUID.begin(); itr != SpiteTargetGUID.end(); ++itr)
+ {
+ if(Unit* target = Unit::GetUnit(*m_creature, *itr))
+ {
+ target->RemoveAurasDueToSpell(SPELL_SPITE_TARGET);
+ m_creature->CastSpell(target, SPELL_SPITE_DAMAGE, true);
+ }
+ }
+ SpiteTargetGUID.clear();
+ SpiteTimer = 24000;
+ }
+ else
+ {
+ SelectSpiteTarget(3);
+ SpiteTimer = 6000;
+ DoYell(ANGER_SAY_SPEC,LANG_UNIVERSAL,NULL);
+ DoPlaySoundToSet(m_creature, ANGER_SOUND_SPEC);
}
-
- SpiteTimer = 30000;
- DoYell(ANGER_SAY_SPEC,LANG_UNIVERSAL,NULL);
- DoPlaySoundToSet(m_creature, ANGER_SOUND_SPEC);
}else SpiteTimer -= diff;
DoMeleeAttackIfReady();
@@ -994,6 +744,7 @@ void npc_enslaved_soulAI::JustDied(Unit *killer) if(Reliquary)
((boss_reliquary_of_soulsAI*)Reliquary->AI())->SoulDeathCount++;
}
+ DoCast(m_creature, SPELL_SOUL_RELEASE, true);
}
CreatureAI* GetAI_boss_reliquary_of_souls(Creature *_Creature)
diff --git a/src/bindings/scripts/scripts/zone/black_temple/boss_supremus.cpp b/src/bindings/scripts/scripts/zone/black_temple/boss_supremus.cpp index 5cac0a0c23c..b3555c12816 100644 --- a/src/bindings/scripts/scripts/zone/black_temple/boss_supremus.cpp +++ b/src/bindings/scripts/scripts/zone/black_temple/boss_supremus.cpp @@ -116,32 +116,27 @@ struct TRINITY_DLL_DECL npc_volcanoAI : public ScriptedAI SupremusGUID = 0;
FireballTimer = 500;
GeyserTimer = 0;
+ m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_DISABLE_MOVE);
+ m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
}
void Aggro(Unit *who) {}
void AttackStart(Unit* who) {}
void MoveInLineOfSight(Unit* who) {}
- void SetSupremusGUID(uint64 guid) { SupremusGUID = guid; }
void UpdateAI(const uint32 diff)
{
- if(CheckTimer < diff)
- {
- if(SupremusGUID)
- {
- Unit* Supremus = NULL;
- Supremus = Unit::GetUnit((*m_creature), SupremusGUID);
- if(Supremus && (!Supremus->isAlive()))
- m_creature->DealDamage(m_creature, m_creature->GetHealth(), 0, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false);
- }
- CheckTimer = 2000;
- }else CheckTimer -= diff;
-
if(GeyserTimer < diff)
{
DoCast(m_creature, SPELL_VOLCANIC_GEYSER);
GeyserTimer = 18000;
}else GeyserTimer -= diff;
+
+ if(FireballTimer < diff)
+ {
+ DoCast(m_creature, SPELL_VOLCANIC_FIREBALL, true);
+ FireballTimer = 1000;
+ }else FireballTimer -= diff;
}
};
@@ -271,7 +266,7 @@ struct TRINITY_DLL_DECL boss_supremusAI : public ScriptedAI if(!m_creature->HasAura(SPELL_BERSERK, 0))
if(BerserkTimer < diff)
DoCast(m_creature, SPELL_BERSERK);
- else BerserkTimer -= diff;
+ else BerserkTimer -= diff;
if(SummonFlameTimer < diff)
{
@@ -332,15 +327,7 @@ struct TRINITY_DLL_DECL boss_supremusAI : public ScriptedAI if(target)
{
- Creature* Volcano = NULL;
- Volcano = SummonCreature(CREATURE_VOLCANO, target);
-
- if(Volcano)
- {
- DoCast(target, SPELL_VOLCANIC_ERUPTION);
- ((npc_volcanoAI*)Volcano->AI())->SetSupremusGUID(m_creature->GetGUID());
- }
-
+ DoCast(target, SPELL_VOLCANIC_ERUPTION);
DoTextEmote("roars and the ground begins to crack open!", NULL);
SummonVolcanoTimer = 10000;
}
@@ -355,6 +342,7 @@ struct TRINITY_DLL_DECL boss_supremusAI : public ScriptedAI DoResetThreat();
PhaseSwitchTimer = 60000;
m_creature->SetSpeed(MOVE_RUN, 1.0f);
+ DoZoneInCombat();
}
else
{
@@ -364,6 +352,7 @@ struct TRINITY_DLL_DECL boss_supremusAI : public ScriptedAI SummonVolcanoTimer = 2000;
PhaseSwitchTimer = 60000;
m_creature->SetSpeed(MOVE_RUN, 0.9f);
+ DoZoneInCombat();
}
}else PhaseSwitchTimer -= diff;
diff --git a/src/bindings/scripts/scripts/zone/black_temple/boss_warlord_najentus.cpp b/src/bindings/scripts/scripts/zone/black_temple/boss_warlord_najentus.cpp index 34da1225787..6e2f20394d5 100644 --- a/src/bindings/scripts/scripts/zone/black_temple/boss_warlord_najentus.cpp +++ b/src/bindings/scripts/scripts/zone/black_temple/boss_warlord_najentus.cpp @@ -16,8 +16,8 @@ /* ScriptData
SDName: Boss_Warlord_Najentus
-SD%Complete: 90
-SDComment: Using a creature workaround instead of a GO for Impaling Spine.
+SD%Complete: 95
+SDComment:
SDCategory: Black Temple
EndScriptData */
@@ -58,164 +58,82 @@ EndScriptData */ #define SOUND_DEATH 11459
//Spells
-#define SPELL_CRASHINGWAVE 40100
#define SPELL_NEEDLE_SPINE 39835
#define SPELL_NEEDLE_AOE 39968
#define SPELL_TIDAL_BURST 39878
-#define SPELL_TIDAL_SHIELD 39872 // Not going to use this since Hurl Spine doesn't dispel it.
+#define SPELL_TIDAL_SHIELD 39872
#define SPELL_IMPALING_SPINE 39837
#define SPELL_CREATE_NAJENTUS_SPINE 39956
#define SPELL_HURL_SPINE 39948
-#define SPELL_SHIELD_VISUAL 37136
#define SPELL_BERSERK 45078
-#define DISPLAYID_SPINE 7362
-
-struct TRINITY_DLL_DECL mob_najentus_spineAI : public ScriptedAI
-{
- mob_najentus_spineAI(Creature *c) : ScriptedAI(c)
- {
- Reset();
- }
-
- uint64 SpineVictimGUID;
-
- void Reset() { SpineVictimGUID = 0; }
-
- void SetSpineVictimGUID(uint64 guid){ SpineVictimGUID = guid; }
-
- void JustDied(Unit *killer)
- {
- // Make the killer have the Najentus Spine item to pierce Tidal Shield
- if(killer)
- killer->CastSpell(killer, SPELL_CREATE_NAJENTUS_SPINE, true);
- }
-
- void DamageTaken(Unit *done_by, uint32 &damage)
- {
- if(damage < m_creature->GetHealth()) return;
-
- // Remove the Impaling Spine DoT from whoever was affected
- if(SpineVictimGUID)
- {
- Unit* victim = Unit::GetUnit((*m_creature), SpineVictimGUID);
- if(victim && ((victim->HasAura(SPELL_IMPALING_SPINE, 0)) || (victim->HasAura(SPELL_IMPALING_SPINE, 1)) || (victim->HasAura(SPELL_IMPALING_SPINE, 2))))
- victim->RemoveAurasDueToSpell(SPELL_IMPALING_SPINE);
- }
- }
-
- void Aggro(Unit* who) {}
- void AttackStart(Unit* who) {}
- void MoveInLineOfSight(Unit* who) {}
- void UpdateAI(const uint32 diff) {}
-};
+#define GOBJECT_SPINE 185584
struct TRINITY_DLL_DECL boss_najentusAI : public ScriptedAI
{
- boss_najentusAI(Creature *c) : ScriptedAI(c)
+ boss_najentusAI(Creature *c) : ScriptedAI(c)
{
pInstance = ((ScriptedInstance*)c->GetInstanceData());
Reset();
}
ScriptedInstance* pInstance;
- uint32 CrashingWaveTimer;
+
uint32 NeedleSpineTimer;
uint32 EnrageTimer;
uint32 SpecialYellTimer;
uint32 TidalShieldTimer;
uint32 ImpalingSpineTimer;
- uint32 CheckTimer; // This timer checks if Najentus is Tidal Shielded and if so, regens health. If not, sets IsShielded to false
- uint32 DispelShieldTimer; // This shield is only supposed to last 30 seconds, but the SPELL_SHIELD_VISUAL lasts forever
uint64 SpineTargetGUID;
- uint64 SpineGUID;
-
- bool IsShielded;
void Reset()
{
- IsShielded = false;
-
- CrashingWaveTimer = 28000;
- NeedleSpineTimer = 10000;
EnrageTimer = 480000;
SpecialYellTimer = 45000 + (rand()%76)*1000;
- TidalShieldTimer = 60000;
- ImpalingSpineTimer = 45000;
- CheckTimer = 2000;
- DispelShieldTimer = 30000;
+
+ ResetTimer();
SpineTargetGUID = 0;
- SpineGUID = 0;
if(pInstance)
- {
- if(m_creature->isAlive())
- {
- pInstance->SetData(DATA_HIGHWARLORDNAJENTUSEVENT, NOT_STARTED);
- ToggleGate(true);
- }
- else ToggleGate(false);
- }
+ pInstance->SetData(DATA_HIGHWARLORDNAJENTUSEVENT, NOT_STARTED);
}
void KilledUnit(Unit *victim)
{
switch(rand()%2)
{
- case 0:
- DoYell(SAY_SLAY1,LANG_UNIVERSAL,NULL);
- DoPlaySoundToSet(m_creature, SOUND_SLAY1);
- break;
- case 1:
- DoYell(SAY_SLAY2,LANG_UNIVERSAL,NULL);
- DoPlaySoundToSet(m_creature, SOUND_SLAY2);
- break;
+ case 0:
+ DoYell(SAY_SLAY1,LANG_UNIVERSAL,NULL);
+ DoPlaySoundToSet(m_creature, SOUND_SLAY1);
+ break;
+ case 1:
+ DoYell(SAY_SLAY2,LANG_UNIVERSAL,NULL);
+ DoPlaySoundToSet(m_creature, SOUND_SLAY2);
+ break;
}
}
void JustDied(Unit *victim)
{
if(pInstance)
- {
pInstance->SetData(DATA_HIGHWARLORDNAJENTUSEVENT, DONE);
- ToggleGate(false);
- }
DoYell(SAY_DEATH, LANG_UNIVERSAL, NULL);
DoPlaySoundToSet(m_creature,SOUND_DEATH);
}
- void ToggleGate(bool close)
- {
- if(GameObject* Gate = GameObject::GetGameObject(*m_creature, pInstance->GetData64(DATA_GAMEOBJECT_NAJENTUS_GATE)))
- if(close) Gate->SetGoState(0); // Closed
- else Gate->SetGoState(2); // Opened
- }
-
void SpellHit(Unit *caster, const SpellEntry *spell)
{
- if(IsShielded)
+ if(spell->Id == SPELL_HURL_SPINE && m_creature->HasAura(SPELL_TIDAL_SHIELD, 0))
{
- if(spell->Id == SPELL_HURL_SPINE)
- {
- if(m_creature->HasAura(SPELL_SHIELD_VISUAL, 0))
- m_creature->RemoveAurasDueToSpell(SPELL_SHIELD_VISUAL);
- if(m_creature->HasAura(SPELL_TIDAL_SHIELD, 0))
- m_creature->RemoveAurasDueToSpell(SPELL_TIDAL_SHIELD);
- DoCast(m_creature->getVictim(), SPELL_TIDAL_BURST);
- IsShielded = false;
- }
+ m_creature->RemoveAurasDueToSpell(SPELL_TIDAL_SHIELD);
+ m_creature->CastSpell(m_creature, SPELL_TIDAL_BURST, true);
+ ResetTimer();
}
}
- void DamageTaken(Unit *done_by, uint32 &damage)
- {
- if(IsShielded)
- damage = 0;
- }
-
void Aggro(Unit *who)
{
if(pInstance)
@@ -223,90 +141,44 @@ struct TRINITY_DLL_DECL boss_najentusAI : public ScriptedAI DoYell(SAY_AGGRO, LANG_UNIVERSAL, NULL);
DoPlaySoundToSet(m_creature, SOUND_AGGRO);
-
DoZoneInCombat();
}
- // This is a workaround since we cannot summon GameObjects at will.
- // Instead, we create a custom creature on top of the player.
- // When someone kills the creature, the killer gets the "Naj'entus Spine" item.
- // This item is the only item that should be able to pierce Tidal Shield
- void DoImpalingSpineWorkaround(Unit* target)
+ bool RemoveImpalingSpine()
{
- Creature* Spine = NULL;
- Spine = m_creature->SummonCreature(500000, target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), 0, TEMPSUMMON_DEAD_DESPAWN, 10000);
- if(Spine)
- {
- Spine->setFaction(m_creature->getFaction());
- ((mob_najentus_spineAI*)Spine->AI())->SetSpineVictimGUID(target->GetGUID());
- SpineTargetGUID = target->GetGUID();
- }
+ if(!SpineTargetGUID) return false;
+ Unit* target = Unit::GetUnit(*m_creature, SpineTargetGUID);
+ if(target && target->HasAura(SPELL_IMPALING_SPINE, 1))
+ target->RemoveAurasDueToSpell(SPELL_IMPALING_SPINE);
+ SpineTargetGUID=0;
+ return true;
}
- bool RemoveImpalingSpine(uint64 guid)
+ void ResetTimer(uint32 inc = 0)
{
- if(!IsShielded || guid == SpineTargetGUID) return false;
-
- if(SpineTargetGUID)
- {
- Unit* target = Unit::GetUnit((*m_creature), SpineTargetGUID);
- if(target && target->HasAura(SPELL_IMPALING_SPINE, 0))
- {
- target->RemoveAurasDueToSpell(SPELL_IMPALING_SPINE);
- return true;
- }
- }
-
- return false;
+ NeedleSpineTimer = 10000 + inc;
+ TidalShieldTimer = 60000 + inc;
+ ImpalingSpineTimer = 20000 + inc;
}
void UpdateAI(const uint32 diff)
{
- //Return since we have no target
if (!m_creature->SelectHostilTarget() || !m_creature->getVictim())
return;
- if(CheckTimer < diff)
- {
- // if(m_creature->HasAura(SPELL_TIDAL_SHIELD, 0))
- if(m_creature->HasAura(SPELL_SHIELD_VISUAL, 0))
- m_creature->SetHealth(m_creature->GetHealth() + (m_creature->GetMaxHealth()/100));
- else
- IsShielded = false;
-
- CheckTimer = 2000;
- }else CheckTimer -= diff;
-
- if(IsShielded)
- {
- m_creature->GetMotionMaster()->Clear(false);
- m_creature->GetMotionMaster()->MoveIdle();
- if(!m_creature->HasAura(SPELL_SHIELD_VISUAL, 0))
- DoCast(m_creature, SPELL_SHIELD_VISUAL);
- if(DispelShieldTimer < diff)
- {
- m_creature->GetMotionMaster()->MoveChase(m_creature->getVictim());
- if(m_creature->HasAura(SPELL_SHIELD_VISUAL, 0))
- m_creature->RemoveAurasDueToSpell(SPELL_SHIELD_VISUAL);
- IsShielded = false;
- }else DispelShieldTimer -= diff;
-
- return; // Don't cast or do anything while Shielded
- }
-
- // Crashing Wave
- if(CrashingWaveTimer < diff)
+ if(TidalShieldTimer < diff)
{
- DoCast(m_creature->getVictim(), SPELL_CRASHINGWAVE);
- CrashingWaveTimer = 28500;
- }else CrashingWaveTimer -= diff;
+ m_creature->InterruptNonMeleeSpells(false);
+ DoCast(m_creature, SPELL_TIDAL_SHIELD, true);
+ ResetTimer(45000);
+ }else TidalShieldTimer -= diff;
- if(!m_creature->HasAura(SPELL_BERSERK, 0))
- if(EnrageTimer < diff)
+ if(EnrageTimer < diff)
{
DoYell(SAY_ENRAGE, LANG_UNIVERSAL, NULL);
DoPlaySoundToSet(m_creature, SOUND_ENRAGE);
- DoCast(m_creature, SPELL_BERSERK);
+ m_creature->CastSpell(m_creature, SPELL_BERSERK, true);
+ EnrageTimer = 600000;
}else EnrageTimer -= diff;
// Needle
@@ -315,27 +187,24 @@ struct TRINITY_DLL_DECL boss_najentusAI : public ScriptedAI for(uint8 i = 0; i < 3; ++i)
{
Unit* target = SelectUnit(SELECT_TARGET_RANDOM, 1);
- if(!target)
- target = m_creature->getVictim();
-
- DoCast(target, SPELL_NEEDLE_AOE, true);
- DoCast(target, SPELL_NEEDLE_SPINE);
+ if(!target) target = m_creature->getVictim();
+ m_creature->CastSpell(target, SPELL_NEEDLE_SPINE, true);
}
-
- NeedleSpineTimer = 60000;
+ m_creature->SetInFront(m_creature->getVictim());
+ NeedleSpineTimer = 30000;
}else NeedleSpineTimer -= diff;
if(SpecialYellTimer < diff)
{
switch(rand()%2)
{
- case 0:
- DoPlaySoundToSet(m_creature, SOUND_SPECIAL1);
- break;
- case 1:
- DoYell(SAY_SPECIAL2, LANG_UNIVERSAL, NULL);
- DoPlaySoundToSet(m_creature, SOUND_SPECIAL2);
- break;
+ case 0:
+ DoPlaySoundToSet(m_creature, SOUND_SPECIAL1);
+ break;
+ case 1:
+ DoYell(SAY_SPECIAL2, LANG_UNIVERSAL, NULL);
+ DoPlaySoundToSet(m_creature, SOUND_SPECIAL2);
+ break;
}
SpecialYellTimer = 25000 + (rand()%76)*1000;
}else SpecialYellTimer -= diff;
@@ -343,73 +212,43 @@ struct TRINITY_DLL_DECL boss_najentusAI : public ScriptedAI if(ImpalingSpineTimer < diff)
{
Unit* target = SelectUnit(SELECT_TARGET_RANDOM, 1);
- if(!target)
- target = m_creature->getVictim();
+ if(!target) target = m_creature->getVictim();
+ m_creature->CastSpell(target, SPELL_IMPALING_SPINE, true);
+ m_creature->SetInFront(m_creature->getVictim());
+ SpineTargetGUID = target->GetGUID();
+ m_creature->SummonGameObject(GOBJECT_SPINE, target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), m_creature->GetOrientation(), 0, 0, 0, 0, 30);
- if(target && (target->GetTypeId() == TYPEID_PLAYER))
+ switch(rand()%2)
{
- DoCast(target, SPELL_IMPALING_SPINE);
- //DoImpalingSpineWorkaround(target);
- SpineTargetGUID = target->GetGUID();
- ImpalingSpineTimer = 45000;
-
- switch(rand()%2)
- {
- case 0:
- DoYell(SAY_NEEDLE1, LANG_UNIVERSAL, NULL);
- DoPlaySoundToSet(m_creature, SOUND_NEEDLE1);
- break;
- case 1:
- DoYell(SAY_NEEDLE2, LANG_UNIVERSAL, NULL);
- DoPlaySoundToSet(m_creature, SOUND_NEEDLE2);
- break;
- }
+ case 0:
+ DoYell(SAY_NEEDLE1, LANG_UNIVERSAL, NULL);
+ DoPlaySoundToSet(m_creature, SOUND_NEEDLE1);
+ break;
+ case 1:
+ DoYell(SAY_NEEDLE2, LANG_UNIVERSAL, NULL);
+ DoPlaySoundToSet(m_creature, SOUND_NEEDLE2);
+ break;
}
+ ImpalingSpineTimer = 21000;
}else ImpalingSpineTimer -= diff;
- if(TidalShieldTimer < diff)
- {
- m_creature->InterruptNonMeleeSpells(false);
- DoCast(m_creature, SPELL_SHIELD_VISUAL, true);
- // DoCast(m_creature, SPELL_TIDAL_SHIELD);
- m_creature->GetMotionMaster()->Clear(false);
- m_creature->GetMotionMaster()->MoveIdle();
- IsShielded = true;
- TidalShieldTimer = 60000;
- CheckTimer = 2000;
- DispelShieldTimer = 30000;
- }else TidalShieldTimer -= diff;
-
DoMeleeAttackIfReady();
}
};
bool GOHello_go_najentus_spine(Player *player, GameObject* _GO)
{
- ScriptedInstance* pInstance = ((ScriptedInstance*)_GO->GetInstanceData());
- if(pInstance)
- {
- uint64 NajentusGUID = pInstance->GetData64(DATA_HIGHWARLORDNAJENTUS);
- if(NajentusGUID)
- {
- Creature* Najentus = ((Creature*)Unit::GetUnit((*_GO), NajentusGUID));
- if(Najentus)
+ if(ScriptedInstance* pInstance = (ScriptedInstance*)_GO->GetInstanceData())
+ if(Creature* Najentus = (Creature*)Unit::GetUnit(*_GO, pInstance->GetData64(DATA_HIGHWARLORDNAJENTUS)))
+ if(((boss_najentusAI*)Najentus->AI())->RemoveImpalingSpine())
{
- if(((boss_najentusAI*)Najentus->AI())->RemoveImpalingSpine(player->GetGUID()))
- return true;
- }else error_log("ERROR: Na'entus Spine GameObject unable to find Naj'entus");
- }else error_log("ERROR: Invalid GUID acquired for Naj'entus by Naj'entus Spine GameObject");
- }
- else error_log("ERROR: Naj'entus Spine spawned in invalid instance or location");
-
+ player->CastSpell(player, SPELL_CREATE_NAJENTUS_SPINE, true);
+ _GO->SetLootState(GO_NOT_READY);
+ _GO->SetRespawnTime(0);
+ }
return true;
}
-CreatureAI* GetAI_mob_najentus_spine(Creature *_Creature)
-{
- return new mob_najentus_spineAI (_Creature);
-}
-
CreatureAI* GetAI_boss_najentus(Creature *_Creature)
{
return new boss_najentusAI (_Creature);
@@ -424,11 +263,6 @@ void AddSC_boss_najentus() m_scripts[nrscripts++] = newscript;
newscript = new Script;
- newscript->Name = "mob_najentus_spine";
- newscript->GetAI = GetAI_mob_najentus_spine;
- m_scripts[nrscripts++] = newscript;
-
- newscript = new Script;
newscript->Name = "go_najentus_spine";
newscript->pGOHello = &GOHello_go_najentus_spine;
m_scripts[nrscripts++] = newscript;
diff --git a/src/bindings/scripts/scripts/zone/black_temple/instance_black_temple.cpp b/src/bindings/scripts/scripts/zone/black_temple/instance_black_temple.cpp index b42a796b5f4..c28f56df959 100644 --- a/src/bindings/scripts/scripts/zone/black_temple/instance_black_temple.cpp +++ b/src/bindings/scripts/scripts/zone/black_temple/instance_black_temple.cpp @@ -126,12 +126,15 @@ struct TRINITY_DLL_DECL instance_black_temple : public ScriptedInstance break;
case 185905: // Gate leading to Temple Summit
IllidanGate = go->GetGUID();
+ go->SetUInt32Value(GAMEOBJECT_FLAGS,GO_FLAG_NODESPAWN+GO_FLAG_INTERACT_COND);
break;
case 186261: // Right door at Temple Summit
IllidanDoor[0] = go->GetGUID();
+ go->SetUInt32Value(GAMEOBJECT_FLAGS,GO_FLAG_NODESPAWN+GO_FLAG_INTERACT_COND);
break;
case 186262: // Left door at Temple Summit
IllidanDoor[1] = go->GetGUID();
+ go->SetUInt32Value(GAMEOBJECT_FLAGS,GO_FLAG_NODESPAWN+GO_FLAG_INTERACT_COND);
break;
}
}
diff --git a/src/bindings/scripts/scripts/zone/karazhan/boss_maiden_of_virtue.cpp b/src/bindings/scripts/scripts/zone/karazhan/boss_maiden_of_virtue.cpp index 382691eb5b7..51600364139 100644 --- a/src/bindings/scripts/scripts/zone/karazhan/boss_maiden_of_virtue.cpp +++ b/src/bindings/scripts/scripts/zone/karazhan/boss_maiden_of_virtue.cpp @@ -27,6 +27,7 @@ EndScriptData */ #define SPELL_HOLYFIRE 29522
#define SPELL_HOLYWRATH 32445
#define SPELL_HOLYGROUND 29512
+#define SPELL_BERSERK 26662
#define SAY_AGGRO "Your behavior will not be tolerated!"
#define SAY_SLAY1 "Ah ah ah..."
@@ -52,6 +53,9 @@ struct TRINITY_DLL_DECL boss_maiden_of_virtueAI : public ScriptedAI uint32 Holyfire_Timer;
uint32 Holywrath_Timer;
uint32 Holyground_Timer;
+ uint32 Enrage_Timer;
+
+ bool Enraged;
void Reset()
{
@@ -59,6 +63,12 @@ struct TRINITY_DLL_DECL boss_maiden_of_virtueAI : public ScriptedAI Holyfire_Timer = 8000+(rand()%17000);
Holywrath_Timer = 20000+(rand()%10000);
Holyground_Timer = 3000;
+ Enrage_Timer = 600000;
+
+ Enraged = false;
+
+ m_creature->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_MOD_TAUNT, true);
+ m_creature->ApplySpellImmune(1, IMMUNITY_EFFECT,SPELL_EFFECT_ATTACK_ME, true);
}
void KilledUnit(Unit* Victim)
@@ -67,18 +77,18 @@ struct TRINITY_DLL_DECL boss_maiden_of_virtueAI : public ScriptedAI switch(rand()%3)
{
- case 0:
- DoYell(SAY_SLAY1,LANG_UNIVERSAL,Victim);
- DoPlaySoundToSet(m_creature, SOUND_SLAY1);
- break;
- case 1:
- DoYell(SAY_SLAY2,LANG_UNIVERSAL,Victim);
- DoPlaySoundToSet(m_creature, SOUND_SLAY2);
- break;
- case 2:
- DoYell(SAY_SLAY3,LANG_UNIVERSAL,Victim);
- DoPlaySoundToSet(m_creature, SOUND_SLAY3);
- break;
+ case 0:
+ DoYell(SAY_SLAY1,LANG_UNIVERSAL,Victim);
+ DoPlaySoundToSet(m_creature, SOUND_SLAY1);
+ break;
+ case 1:
+ DoYell(SAY_SLAY2,LANG_UNIVERSAL,Victim);
+ DoPlaySoundToSet(m_creature, SOUND_SLAY2);
+ break;
+ case 2:
+ DoYell(SAY_SLAY3,LANG_UNIVERSAL,Victim);
+ DoPlaySoundToSet(m_creature, SOUND_SLAY3);
+ break;
}
}
@@ -99,6 +109,12 @@ struct TRINITY_DLL_DECL boss_maiden_of_virtueAI : public ScriptedAI if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() )
return;
+ if (Enrage_Timer < diff && !Enraged)
+ {
+ DoCast(m_creature, SPELL_BERSERK,true);
+ Enraged = true;
+ }else Enrage_Timer -=diff;
+
if (Holyground_Timer < diff)
{
DoCast(m_creature, SPELL_HOLYGROUND, true); //Triggered so it doesn't interrupt her at all
@@ -111,37 +127,28 @@ struct TRINITY_DLL_DECL boss_maiden_of_virtueAI : public ScriptedAI switch(rand()%2)
{
- case 0:
- DoYell(SAY_REPENTANCE1,LANG_UNIVERSAL,NULL);
- DoPlaySoundToSet(m_creature, SOUND_REPENTANCE1);
- break;
- case 1:
- DoYell(SAY_REPENTANCE2,LANG_UNIVERSAL,NULL);
- DoPlaySoundToSet(m_creature, SOUND_REPENTANCE2);
- break;
+ case 0:
+ DoYell(SAY_REPENTANCE1,LANG_UNIVERSAL,NULL);
+ DoPlaySoundToSet(m_creature, SOUND_REPENTANCE1);
+ break;
+ case 1:
+ DoYell(SAY_REPENTANCE2,LANG_UNIVERSAL,NULL);
+ DoPlaySoundToSet(m_creature, SOUND_REPENTANCE2);
+ break;
}
Repentance_Timer = 30000 + rand()%15000; //A little randomness on that spell
}else Repentance_Timer -= diff;
if (Holyfire_Timer < diff)
{
- //Time for an omgwtfpwn code to make maiden cast holy fire only on units outside the holy ground's 18 yard range
Unit* target = NULL;
- std::list<HostilReference *> t_list = m_creature->getThreatManager().getThreatList();
- std::vector<Unit *> target_list;
- for(std::list<HostilReference *>::iterator itr = t_list.begin(); itr!= t_list.end(); ++itr)
+ target = SelectUnit(SELECT_TARGET_RANDOM,0);
+
+ if(target)
{
- target = Unit::GetUnit(*m_creature, (*itr)->getUnitGuid());
- if(target && target->GetDistance2d(m_creature) > 12 )
- target_list.push_back(target);
- target = NULL;
+ DoCast(target,SPELL_HOLYFIRE);
+ Holyfire_Timer = 8000 + rand()%17000; //Anywhere from 8 to 25 seconds, good luck having several of those in a row!
}
- if(target_list.size())
- target = *(target_list.begin()+rand()%target_list.size());
-
- DoCast(target,SPELL_HOLYFIRE);
-
- Holyfire_Timer = 8000 + rand()%17000; //Anywhere from 8 to 25 seconds, good luck having several of those in a row!
}else Holyfire_Timer -= diff;
if (Holywrath_Timer < diff)
diff --git a/src/bindings/scripts/scripts/zone/tempest_keep/the_eye/boss_void_reaver.cpp b/src/bindings/scripts/scripts/zone/tempest_keep/the_eye/boss_void_reaver.cpp index 09d1ca3de91..dcb8113cd3d 100644 --- a/src/bindings/scripts/scripts/zone/tempest_keep/the_eye/boss_void_reaver.cpp +++ b/src/bindings/scripts/scripts/zone/tempest_keep/the_eye/boss_void_reaver.cpp @@ -25,7 +25,7 @@ EndScriptData */ #include "def_the_eye.h"
#define SPELL_POUNDING 34162
-#define SPELL_ARCANE_ORB_TRIGGER 34172
+#define SPELL_ARCANE_ORB 34172
#define SPELL_KNOCK_AWAY 11130
#define SPELL_BERSERK 27680
@@ -45,8 +45,6 @@ EndScriptData */ #define SOUND_POUNDING1 11218
#define SOUND_POUNDING2 11219
-#define CREATURE_ORB_TARGET 19577
-
struct TRINITY_DLL_DECL boss_void_reaverAI : public ScriptedAI
{
boss_void_reaverAI(Creature *c) : ScriptedAI(c)
@@ -64,8 +62,11 @@ struct TRINITY_DLL_DECL boss_void_reaverAI : public ScriptedAI void Reset()
{
+ m_creature->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_MOD_TAUNT, true);
+ m_creature->ApplySpellImmune(0, IMMUNITY_EFFECT, SPELL_EFFECT_ATTACK_ME, true);
+
Pounding_Timer = 12000;
- ArcaneOrb_Timer = 3000;
+ ArcaneOrb_Timer = 6000;
KnockAway_Timer = 30000;
Berserk_Timer = 600000;
@@ -143,8 +144,8 @@ struct TRINITY_DLL_DECL boss_void_reaverAI : public ScriptedAI for(std::list<HostilReference *>::iterator itr = t_list.begin(); itr!= t_list.end(); ++itr)
{
target = Unit::GetUnit(*m_creature, (*itr)->getUnitGuid());
- //15 yard radius minimum
- if(target && target->GetDistance2d(m_creature) > 15)
+ //18 yard radius minimum
+ if(target && target->GetDistance2d(m_creature) > 18)
target_list.push_back(target);
target = NULL;
}
@@ -152,14 +153,9 @@ struct TRINITY_DLL_DECL boss_void_reaverAI : public ScriptedAI target = *(target_list.begin()+rand()%target_list.size());
if (target)
- {
- Unit* Spawn = NULL;
- Spawn = m_creature->SummonCreature(CREATURE_ORB_TARGET, target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN, 10000);
- if (Spawn)
- m_creature->CastSpell(Spawn, SPELL_ARCANE_ORB_TRIGGER, true);
- }
+ m_creature->CastSpell(target, SPELL_ARCANE_ORB, true);
- ArcaneOrb_Timer = 3000;
+ ArcaneOrb_Timer = 6000;
}else ArcaneOrb_Timer -= diff;
// Single Target knock back, reduces aggro
diff --git a/src/game/SpellAuras.cpp b/src/game/SpellAuras.cpp index c536531ff14..0027d0b3f68 100644 --- a/src/game/SpellAuras.cpp +++ b/src/game/SpellAuras.cpp @@ -1650,8 +1650,21 @@ void Aura::TriggerSpell() // case 40867: break; // // Prismatic Shield // case 40879: break; -// // Aura of Desire -// case 41350: break; + // Aura of Desire + case 41350: + { + Unit::AuraList const& mMod = m_target->GetAurasByType(SPELL_AURA_MOD_INCREASE_ENERGY_PERCENT); + for(Unit::AuraList::const_iterator i = mMod.begin(); i != mMod.end(); ++i) + { + if ((*i)->GetId() == 41350) + { + (*i)->ApplyModifier(false); + (*i)->GetModifier()->m_amount -= 5; + (*i)->ApplyModifier(true); + break; + } + } + }break; // // Dementia // case 41404: break; // // Chaos Form @@ -5614,6 +5627,21 @@ void Aura::PeriodicTick() } break; } + case 41337:// aura of anger + { + Unit::AuraList const& mMod = m_target->GetAurasByType(SPELL_AURA_MOD_DAMAGE_PERCENT_DONE); + for(Unit::AuraList::const_iterator i = mMod.begin(); i != mMod.end(); ++i) + { + if ((*i)->GetId() == 41337) + { + (*i)->ApplyModifier(false); + (*i)->GetModifier()->m_amount += 5; + (*i)->ApplyModifier(true); + break; + } + } + m_modifier.m_amount += 100; + }break; default: break; } diff --git a/src/game/SpellEffects.cpp b/src/game/SpellEffects.cpp index 75e01781923..f7d9861dd03 100644 --- a/src/game/SpellEffects.cpp +++ b/src/game/SpellEffects.cpp @@ -4665,15 +4665,6 @@ void Spell::EffectScriptEffect(uint32 effIndex) break; } - // Dreaming Glory - case 28698: - { - if(!unitTarget) - return; - unitTarget->CastSpell(unitTarget, 28694, true); - break; - } - // Netherbloom case 28702: { @@ -4748,22 +4739,6 @@ void Spell::EffectScriptEffect(uint32 effIndex) } break; } - case 41126: // Flame Crash - { - if(!unitTarget) - return; - - unitTarget->CastSpell(unitTarget, 41131, true); - break; - } - case 44876: // Force Cast - Portal Effect: Sunwell Isle - { - if(!unitTarget) - return; - - unitTarget->CastSpell(unitTarget, 44870, true); - break; - } // Goblin Weather Machine case 46203: @@ -4790,14 +4765,32 @@ void Spell::EffectScriptEffect(uint32 effIndex) unitTarget->CastSpell(unitTarget, spellId, true); break; } + + } + + if(!unitTarget || !unitTarget->isAlive()) // can we remove this check? + { + sLog.outError("Spell %u in EffectScriptEffect does not have unitTarget", m_spellInfo->Id); + return; + } + + switch(m_spellInfo->Id) + { + // Dreaming Glory + case 28698: unitTarget->CastSpell(unitTarget, 28694, true); break; + // Needle Spine + case 39835: unitTarget->CastSpell(unitTarget, 39968, true); break; + // Draw Soul + case 40904: unitTarget->CastSpell(m_caster, 40903, true); break; + // Flame Crash + case 41126: unitTarget->CastSpell(unitTarget, 41131, true); break; + // Force Cast - Portal Effect: Sunwell Isle + case 44876: unitTarget->CastSpell(unitTarget, 44870, true); break; //5,000 Gold case 46642: { - if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER) - return; - - ((Player*)unitTarget)->ModifyMoney(50000000); - + if(unitTarget->GetTypeId() == TYPEID_PLAYER) + ((Player*)unitTarget)->ModifyMoney(50000000); break; } } @@ -4809,8 +4802,6 @@ void Spell::EffectScriptEffect(uint32 effIndex) // Judgement case 0x800000: { - if(!unitTarget || !unitTarget->isAlive()) - return; uint32 spellId2 = 0; // all seals have aura dummy @@ -4861,9 +4852,6 @@ void Spell::EffectScriptEffect(uint32 effIndex) } // normal DB scripted effect - if(!unitTarget) - return; - sLog.outDebug("Spell ScriptStart spellid %u in EffectScriptEffect ", m_spellInfo->Id); sWorld.ScriptsStart(sSpellScripts, m_spellInfo->Id, m_caster, unitTarget); } |