Changeset 57
- Timestamp:
- 11/19/08 13:29:59 (17 years ago)
- Location:
- trunk/src
- Files:
-
- 10 modified
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/bindings/scripts/scripts/zone/black_temple/boss_illidan.cpp
r48 r57 18 18 SDName: boss_illidan_stormrage 19 19 SD%Complete: 90 20 SDComment: 20 SDComment: Somewhat of a workaround for Parasitic Shadowfiend, unable to summon GOs for Cage Trap. 21 21 SDCategory: Black Temple 22 22 EndScriptData */ … … 24 24 #include "precompiled.h" 25 25 #include "def_black_temple.h" 26 #include "WorldPacket.h" 26 27 #define GETGO(obj, guid) GameObject* obj = GameObject::GetGameObject(*m_creature, guid) 28 #define GETUNIT(unit, guid) Unit* unit = Unit::GetUnit(*m_creature, guid) 29 #define GETCRE(cre, guid) Creature* cre = (Creature*)Unit::GetUnit(*m_creature, guid) 30 #define HPPCT(unit) unit->GetHealth()*100 / unit->GetMaxHealth() 27 31 28 32 /************* Quotes and Sounds ***********************/ 29 33 // Gossip for when a player clicks Akama 30 #define GOSSIP_ITEM "We are ready to face Illidan"34 #define GOSSIP_ITEM "We are ready to face Illidan" 31 35 32 36 // Yells for/by Akama … … 64 68 /************** Spells *************/ 65 69 // Normal Form 66 #define SPELL_SHEAR 41032// Reduces Max. Health by 60% for 7 seconds. Can stack 19 times. 1.5 second cast67 #define SPELL_FLAME_CRASH 40832 68 #define SPELL_DRAW_SOUL 40904 69 #define SPELL_PARASITIC_SHADOWFIEND 41917 70 #define SPELL_SUMMON_PARASITICS 41915 71 #define SPELL_AGONIZING_FLAMES 40932 72 #define SPELL_ENRAGE 40683 70 #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 71 #define SPELL_FLAME_CRASH 40832 // Summons an invis/unselect passive mob that has an aura of flame in a circle around him. 72 #define SPELL_DRAW_SOUL 40904 // 5k Shadow Damage in front of him. Heals Illidan for 100k health (script effect) 73 #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) 74 #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 :( 75 #define SPELL_AGONIZING_FLAMES 40932 // 4k fire damage initial to target and anyone w/i 5 yards. PHASE 3 ONLY 76 #define SPELL_ENRAGE 40683 // Increases damage by 50% and attack speed by 30%. 20 seconds, PHASE 5 ONLY 73 77 // Flying (Phase 2) 74 #define SPELL_THROW_GLAIVE 39635 75 #define SPELL_THROW_GLAIVE2 39849 76 #define SPELL_GLAIVE_RETURNS 39873 77 #define SPELL_FIREBALL 40598 78 #define SPELL_DARK_BARRAGE 40585 78 #define SPELL_THROW_GLAIVE 39635 // Throws a glaive on the ground 79 #define SPELL_THROW_GLAIVE2 39849 // Animation for the above spell 80 #define SPELL_GLAIVE_RETURNS 39873 // Glaive flies back to Illidan 81 #define SPELL_FIREBALL 40598 // 2.5k-3.5k damage in 10 yard radius. 2 second cast time. 82 #define SPELL_DARK_BARRAGE 40585 // 10 second channeled spell, 3k shadow damage per second. 79 83 // Demon Form 80 #define SPELL_DEMON_TRANSFORM_1 40511 81 #define SPELL_DEMON_TRANSFORM_2 40398 82 #define SPELL_DEMON_TRANSFORM_3 40510 83 #define SPELL_DEMON_FORM 40506 84 #define SPELL_SHADOW_BLAST 41078 85 #define SPELL_FLAME_BURST 41126 86 #define SPELL_FLAME_BURST_EFFECT 41131 // The actual damage. Handled by core (41126 triggers 41131)84 #define SPELL_DEMON_TRANSFORM_1 40511 // First phase of animations for transforming into Dark Illidan (fall to ground) 85 #define SPELL_DEMON_TRANSFORM_2 40398 // Second phase of animations (kneel) 86 #define SPELL_DEMON_TRANSFORM_3 40510 // Final phase of animations (stand up and roar) 87 #define SPELL_DEMON_FORM 40506 // Transforms into Demon Illidan. Has an Aura of Dread on him. 88 #define SPELL_SHADOW_BLAST 41078 // 8k - 11k Shadow Damage. Targets highest threat. Has a splash effect, damaging anyone in 20 yards of the target. 89 #define SPELL_FLAME_BURST 41126 // Hurls fire at entire raid for ~3.5k damage every 10 seconds. Resistable. (Does not work: Script effect) 90 #define SPELL_FLAME_BURST_EFFECT 41131 // The actual damage. Have each player cast it on itself (workaround) 87 91 // Other Illidan spells 88 #define SPELL_KNEEL 39656 // Before beginning encounter, this is how he appears (talking to Wilson). 89 #define SPELL_SHADOW_PRISON 40647 // Illidan casts this spell to immobilize entire raid when he summons Maiev. 90 #define SPELL_DEATH 41220 // This spell doesn't do anything except stun Illidan and set him on his knees. 91 #define SPELL_BERSERK 45078 // Damage increased by 500%, attack speed by 150% 92 93 // Non-Illidan spells 94 #define SPELL_AKAMA_DOOR_CHANNEL 41268 // Akama's channel spell on the door before the Temple Summit 95 #define SPELL_DEATHSWORN_DOOR_CHANNEL 41269 // Olum and Udalo's channel spell on the door before the Temple Summit 96 #define SPELL_AKAMA_DOOR_FAIL 41271 // Not sure where this is really used... 97 #define SPELL_HEALING_POTION 40535 // Akama uses this to heal himself to full. 98 #define SPELL_AZZINOTH_CHANNEL 39857 // Glaives cast it on Flames. Not sure if this is the right spell. 99 #define SPELL_SHADOW_DEMON_PASSIVE 41079 // Adds the "shadowform" aura to Shadow Demons. 100 #define SPELL_CONSUME_SOUL 41080 // Once the Shadow Demons reach their target, they use this to kill them 101 #define SPELL_PARALYZE 41083 // Shadow Demons cast this on their target 102 #define SPELL_PURPLE_BEAM 39123 // Purple Beam connecting Shadow Demon to their target 103 #define SPELL_CAGE_TRAP_DUMMY 40761 // Put this in DB for cage trap GO. 104 #define SPELL_EYE_BLAST_TRIGGER 40017 // This summons Demon Form every few seconds and deals ~20k damage in its radius 105 #define SPELL_EYE_BLAST 39908 // This does the blue flamey animation. 106 #define SPELL_FLAME_CRASH_EFFECT 40836 // Firey blue ring of circle that the other flame crash summons 107 #define SPELL_BLAZE_EFFECT 40610 // Green flame on the ground, triggers damage (5k) every few seconds 108 #define SPELL_BLAZE_SUMMON 40637 // Summons the Blaze creature 109 #define SPELL_DEMON_FIRE 40029 // Blue fire trail left by Eye Blast. Deals 2k per second if players stand on it. 110 #define SPELL_CAGED 40695 // Caged Trap triggers will cast this on Illidan if he is within 3 yards 111 #define SPELL_CAGE_TRAP_SUMMON 40694 // Summons a Cage Trap GO (bugged) on the ground along with a Cage Trap Disturb Trigger mob (working) 112 #define SPELL_CAGE_TRAP_BEAM 40713 // 8 Triggers on the ground in an octagon cast spells like this on Illidan 'caging him' 113 #define SPELL_FLAME_BLAST 40631 // Flames of Azzinoth use this. Frontal cone AoE 7k-9k damage. 114 #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. 115 #define SPELL_TELEPORT_VISUAL 41232 // Teleport visual for Maiev 116 #define SPELL_SHADOWFIEND_PASSIVE 41913 // Passive aura for shadowfiends 92 #define SPELL_KNEEL 39656 // Before beginning encounter, this is how he appears (talking to skully). 93 #define SPELL_SHADOW_PRISON 40647 // Illidan casts this spell to immobilize entire raid when he summons Maiev. 94 #define SPELL_DEATH 41220 // This spell doesn't do anything except stun Illidan and set him on his knees. 95 #define SPELL_BERSERK 45078 // Damage increased by 500%, attack speed by 150% 96 #define SPELL_DUAL_WIELD 42459 97 //Phase Normal spells 98 #define SPELL_FLAME_CRASH_EFFECT 40836 // Firey blue ring of circle that the other flame crash summons 99 #define SPELL_SHADOWFIEND_PASSIVE 41913 // Passive aura for shadowfiends 100 #define SPELL_SHADOW_DEMON_PASSIVE 41079 // Adds the "shadowform" aura to Shadow Demons. 101 #define SPELL_CONSUME_SOUL 41080 // Once the Shadow Demons reach their target, they use this to kill them 102 #define SPELL_PARALYZE 41083 // Shadow Demons cast this on their target 103 #define SPELL_PURPLE_BEAM 39123 // Purple Beam connecting Shadow Demon to their target 104 //Phase Flight spells 105 #define SPELL_AZZINOTH_CHANNEL 39857 // Glaives cast it on Flames. Not sure if this is the right spell. 106 #define SPELL_EYE_BLAST_TRIGGER 40017 // This summons Demon Form every few seconds and deals ~20k damage in its radius 107 #define SPELL_EYE_BLAST 39908 // This does the blue flamey animation. 108 #define SPELL_BLAZE_EFFECT 40610 // Green flame on the ground, triggers damage (5k) every few seconds 109 #define SPELL_BLAZE_SUMMON 40637 // Summons the Blaze creature 110 #define SPELL_DEMON_FIRE 40029 // Blue fire trail left by Eye Blast. Deals 2k per second if players stand on it. 111 #define SPELL_FLAME_BLAST 40631 // Flames of Azzinoth use this. Frontal cone AoE 7k-9k damage. 112 #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. 113 #define SPELL_FLAME_ENRAGE 45078 114 //Akama spells 115 #define SPELL_AKAMA_DOOR_CHANNEL 41268 // Akama's channel spell on the door before the Temple Summit 116 #define SPELL_DEATHSWORN_DOOR_CHANNEL 41269 // Olum and Udalo's channel spell on the door before the Temple Summit 117 #define SPELL_AKAMA_DOOR_FAIL 41271 // Not sure where this is really used... 118 #define SPELL_HEALING_POTION 40535 // Akama uses this to heal himself to full. 119 #define SPELL_CHAIN_LIGHTNING 40536 // 6938 to 8062 for 5 targets 120 //Maiev spells 121 #define SPELL_CAGE_TRAP_DUMMY 40761 // Put this in DB for cage trap GO. 122 #define SPELL_CAGED 40695 // Caged Trap triggers will cast this on Illidan if he is within 3 yards 123 #define SPELL_CAGE_TRAP_SUMMON 40694 // Summons a Cage Trap GO (bugged) on the ground along with a Cage Trap Disturb Trigger mob (working) 124 #define SPELL_CAGE_TRAP_BEAM 40713 // 8 Triggers on the ground in an octagon cast spells like this on Illidan 'caging him' 125 #define SPELL_TELEPORT_VISUAL 41232 // Teleport visual for Maiev 126 #define SPELL_SHADOW_STRIKE 40685 // 4375 to 5625 every 3 seconds for 12 seconds 127 #define SPELL_THROW_DAGGER 41152 // 5400 to 6600 damage, need dagger 128 #define SPELL_FAN_BLADES 39954 // bugged visual 117 129 118 130 // Other defines 119 #define CENTER_X 676.740 131 #define CENTER_X 676.740 120 132 #define CENTER_Y 305.297 121 133 #define CENTER_Z 353.192 134 135 #define FLAME_ENRAGE_DISTANCE 30 136 #define FLAME_CHARGE_DISTANCE 50 122 137 123 138 /**** Creature Summon and Recognition IDs ****/ … … 142 157 143 158 /*** Phase Names ***/ 144 enum Phase 145 { 146 PHASE_NORMAL = 1, 147 PHASE_FLIGHT = 2, 148 PHASE_NORMAL_2 = 3, 149 PHASE_DEMON = 4, 150 PHASE_NORMAL_MAIEV = 5, 151 PHASE_DEMON_SEQUENCE = 6, 159 enum PhaseIllidan 160 { 161 PHASE_NULL = 0, 162 PHASE_NORMAL = 1, 163 PHASE_FLIGHT = 2, 164 PHASE_NORMAL_2 = 3, 165 PHASE_DEMON = 4, 166 PHASE_NORMAL_MAIEV = 5, 167 PHASE_TALK_SEQUENCE = 6, 168 PHASE_FLIGHT_SEQUENCE = 7, 169 PHASE_TRANSFORM_SEQUENCE = 8, 170 };//Maiev uses the same phase 171 172 enum PhaseAkama 173 { 174 PHASE_AKAMA_NULL = 0, 175 PHASE_CHANNEL = 1, 176 PHASE_WALK = 2, 177 PHASE_TALK = 3, 178 PHASE_FIGHT_ILLIDAN = 4, 179 PHASE_FIGHT_MINIONS = 5, 180 PHASE_RETURN = 6, 181 }; 182 183 enum EventIllidan 184 { 185 EVENT_NULL = 0, 186 EVENT_BERSERK = 1, 187 //normal phase 188 EVENT_TAUNT = 2, 189 EVENT_SHEAR = 3, 190 EVENT_FLAME_CRASH = 4, 191 EVENT_PARASITIC_SHADOWFIEND = 5, 192 EVENT_PARASITE_CHECK = 6, 193 EVENT_DRAW_SOUL = 7, 194 EVENT_AGONIZING_FLAMES = 8, 195 EVENT_TRANSFORM_NORMAL = 9, 196 EVENT_ENRAGE = 10, 197 //flight phase 198 EVENT_FIREBALL = 2, 199 EVENT_DARK_BARRAGE = 3, 200 EVENT_EYE_BLAST = 4, 201 EVENT_MOVE_POINT = 5, 202 //demon phase 203 EVENT_SHADOW_BLAST = 2, 204 EVENT_FLAME_BURST = 3, 205 EVENT_SHADOWDEMON = 4, 206 EVENT_TRANSFORM_DEMON = 5, 207 //sequence phase 208 EVENT_TALK_SEQUENCE = 2, 209 EVENT_FLIGHT_SEQUENCE = 2, 210 EVENT_TRANSFORM_SEQUENCE = 2, 211 }; 212 213 enum EventMaiev 214 { 215 EVENT_MAIEV_NULL = 0, 216 EVENT_MAIEV_STEALTH = 1, 217 EVENT_MAIEV_TAUNT = 2, 218 EVENT_MAIEV_SHADOW_STRIKE = 3, 219 EVENT_MAIEV_THROW_DAGGER = 4, 220 EVENT_MAIEV_TRAP = 5, 221 }; 222 223 static EventIllidan MaxTimer[]= 224 { 225 EVENT_NULL, 226 EVENT_DRAW_SOUL, 227 EVENT_MOVE_POINT, 228 EVENT_TRANSFORM_NORMAL, 229 EVENT_TRANSFORM_DEMON, 230 EVENT_ENRAGE, 231 EVENT_TALK_SEQUENCE, 232 EVENT_FLIGHT_SEQUENCE, 233 EVENT_TRANSFORM_SEQUENCE 152 234 }; 153 235 … … 163 245 { 164 246 {11463, "Akama... your duplicity is hardly surprising. I should have slaughtered you and your malformed brethren long ago.", ILLIDAN_STORMRAGE, 8000, 0, true}, 165 {0, NULL, ILLIDAN_STORMRAGE, 5000, 396, true}, 247 {0, NULL, ILLIDAN_STORMRAGE, 5000, 396, true}, 166 248 {11389, "We've come to end your reign, Illidan. My people and all of Outland shall be free!", AKAMA, 7000, 25, true}, 167 249 {0, NULL, AKAMA, 5000, 66, true}, … … 171 253 {11466, "You are not prepared!", ILLIDAN_STORMRAGE, 3000, 406, true}, 172 254 {0, NULL, EMPTY, 1000, 0, true}, 173 {0, NULL, EMPTY, 0, 0, false}, 255 {0, NULL, EMPTY, 0, 0, false},//9 174 256 {11476, "Is this it, mortals? Is this all the fury you can muster?", ILLIDAN_STORMRAGE, 8000, 0, true}, 175 257 {11491, "Their fury pales before mine, Illidan. We have some unsettled business between us.", MAIEV_SHADOWSONG, 8000, 5, true}, 176 {11477, "Maiev... How is this even possible?", ILLIDAN_STORMRAGE, 7000, 1, true},258 {11477, "Maiev... How is this even possible?", ILLIDAN_STORMRAGE, 5000, 1, true}, 177 259 {11492, "Ah... my long hunt is finally over. Today, Justice will be done!", MAIEV_SHADOWSONG, 8000, 15, true}, 178 {11470, "Feel the hatred of ten thousand years!", ILLIDAN_STORMRAGE, 1000, 0, false}, 179 {11496, "Ahh... It is finished. You are beaten.", MAIEV_SHADOWSONG, 6000, 0, true}, 180 { // Emote dead for now. Kill him later 181 11478, "You have won... Maiev...but the huntress... is nothing...without the hunt... you... are nothing... without me..", ILLIDAN_STORMRAGE, 22000, 65, true 182 }, 260 {11470, "Feel the hatred of ten thousand years!", ILLIDAN_STORMRAGE, 1000, 0, false},//14 261 {11496, "Ahh... It is finished. You are beaten.", MAIEV_SHADOWSONG, 6000, 0, true},//15 262 {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 183 263 {11497, "He is right. I feel nothing... I am nothing... Farewell, champions.", MAIEV_SHADOWSONG, 9000, 0, true}, 184 {11498, NULL, MAIEV_SHADOWSONG, 0, true}, 264 {11498, NULL, MAIEV_SHADOWSONG, 5000, 0, true}, 265 {11498, NULL, EMPTY, 1000, 0, true},//19 Maiev disappear 185 266 {11387, "The Light will fill these dismal halls once again. I swear it.", AKAMA, 8000, 0, true}, 186 {0, NULL, EMPTY, 1000, 0, false} 267 {0, NULL, EMPTY, 1000, 0, false}//21 187 268 }; 188 269 … … 206 287 { 207 288 float x, y, z; 208 uint32 id; 289 }; 290 291 static Locations HoverPosition[]= 292 { 293 {657, 340, 355}, 294 {657, 275, 355}, 295 {705, 275, 355}, 296 {705, 340, 355} 209 297 }; 210 298 … … 212 300 { 213 301 {695.105, 305.303, 354.256}, 214 {659.338, 305.303, 354.256}, 302 {659.338, 305.303, 354.256},//the distance between two glaives is 36 215 303 {700.105, 305.303, 354.256}, 216 304 {664.338, 305.303, 354.256} … … 219 307 static Locations EyeBlast[]= 220 308 { 221 {650.697, 320.128, 353.730}, 222 {652.799, 275.091, 353.367}, 223 {701.527, 273.815, 353.230}, 224 {709.865, 325.654, 353.322} 309 {677, 350, 354},//start point, pass through glaive point 310 {677, 260, 354} 225 311 }; 226 312 227 313 static Locations AkamaWP[]= 228 314 { 229 { 770.01, 304.50, 312.29 },// Bottom of the first stairs, at the doors230 { 780.66, 304.50, 319.74 },// Top of the first stairs231 { 790.13, 319.68, 319.76 },// Bottom of the second stairs (left from the entrance)232 { 787.17, 347.38, 341.42 },// Top of the second stairs233 { 781.34, 350.31, 341.44 },// Bottom of the third stairs234 { 762.60, 361.06, 353.60 },// Top of the third stairs235 { 756.35, 360.52, 353.27 },// Before the door-thingy236 { 743.82, 342.21, 353.00 },// Somewhere further237 { 732.69, 305.13, 353.00 }, // In front of Illidan238 { 738.11, 365.44, 353.00 },// in front of the door-thingy (the other one!)239 { 792.18, 366.62, 341.42 },// Down the first flight of stairs240 { 796.84, 304.89, 319.76 },// Down the second flight of stairs241 { 782.01, 304.55, 319.76 } // Final location - back at the initial gates. This is where he will fight the minions!315 {770.01, 304.50, 312.29}, // Bottom of the first stairs, at the doors 316 {780.66, 304.50, 319.74}, // Top of the first stairs 317 {790.13, 319.68, 319.76}, // Bottom of the second stairs (left from the entrance) 318 {787.17, 347.38, 341.42}, // Top of the second stairs 319 {781.34, 350.31, 341.44}, // Bottom of the third stairs 320 {762.60, 361.06, 353.60}, // Top of the third stairs 321 {756.35, 360.52, 353.27}, // Before the door-thingy 322 {743.82, 342.21, 353.00}, // Somewhere further 323 {732.69, 305.13, 353.00}, // In front of Illidan - (8) 324 {738.11, 365.44, 353.00}, // in front of the door-thingy (the other one!) 325 {792.18, 366.62, 341.42}, // Down the first flight of stairs 326 {796.84, 304.89, 319.76}, // Down the second flight of stairs 327 {782.01, 304.55, 319.76} // Final location - back at the initial gates. This is where he will fight the minions! (12) 242 328 }; 243 329 // 755.762, 304.0747, 312.1769 -- This is where Akama should be spawned 244 330 static Locations SpiritSpawns[]= 245 331 { 246 {755.5426, 309.9156, 312.2129, SPIRIT_OF_UDALO}, 247 {755.5426, 298.7923, 312.0834, SPIRIT_OF_OLUM} 248 }; 249 250 struct WayPoints 251 { 252 WayPoints(uint32 _id, float _x, float _y, float _z) 253 { 254 id = _id; 255 x = _x; 256 y = _y; 257 z = _z; 258 } 259 uint32 id; 260 float x, y, z; 261 }; 262 263 struct Animation // For the demon transformation 332 {755.5426, 309.9156, 312.2129}, 333 {755.5426, 298.7923, 312.0834} 334 }; 335 336 struct Animation // For the demon transformation 264 337 { 265 338 uint32 aura, unaura, timer, size, displayid, phase; … … 269 342 static Animation DemonTransformation[]= 270 343 { 271 {SPELL_DEMON_TRANSFORM_1, 0, 1 300, 0, 0, 6, true},344 {SPELL_DEMON_TRANSFORM_1, 0, 1000, 0, 0, 6, true}, 272 345 {SPELL_DEMON_TRANSFORM_2, SPELL_DEMON_TRANSFORM_1, 4000, 0, 0, 6, true}, 273 { SPELL_DEMON_FORM, 0, 3000, 1073741824, 21322, 6, false},346 {0, 0, 3000, 1073741824, 21322, 6, false},//stunned, cannot cast demon form 274 347 {SPELL_DEMON_TRANSFORM_3, SPELL_DEMON_TRANSFORM_2, 3500, 0, 0, 6, false}, 275 { 0, 0, 0, 0, 0, 4, false},276 {SPELL_DEMON_TRANSFORM_1, 0, 1 500, 0, 0, 6, false},348 {SPELL_DEMON_FORM, SPELL_DEMON_TRANSFORM_3, 0, 0, 0, 4, false}, 349 {SPELL_DEMON_TRANSFORM_1, 0, 1000, 0, 0, 6, false}, 277 350 {SPELL_DEMON_TRANSFORM_2, SPELL_DEMON_TRANSFORM_1, 4000, 0, 0, 6, false}, 278 351 {0, SPELL_DEMON_FORM, 3000, 1069547520, 21135, 6, false}, 279 352 {SPELL_DEMON_TRANSFORM_3, SPELL_DEMON_TRANSFORM_2, 3500, 0, 0, 6, true}, 280 {0, 0, 0, 0, 0, 8, true} 281 }; 282 283 /**** 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 ****/ 284 struct TRINITY_DLL_DECL demonfireAI : public ScriptedAI 285 { 286 demonfireAI(Creature *c) : ScriptedAI(c) 353 {0, SPELL_DEMON_TRANSFORM_3, 0, 0, 0, 8, true} 354 }; 355 356 357 358 /************************************** Illidan's AI ***************************************/ 359 struct TRINITY_DLL_DECL boss_illidan_stormrageAI : public ScriptedAI 360 { 361 boss_illidan_stormrageAI(Creature* c) : ScriptedAI(c) 287 362 { 288 363 pInstance = ((ScriptedInstance*)c->GetInstanceData()); … … 292 367 ScriptedInstance* pInstance; 293 368 369 PhaseIllidan Phase; 370 EventIllidan Event; 371 uint32 Timer[EVENT_ENRAGE + 1]; 372 373 uint32 TalkCount; 374 uint32 TransformCount; 375 uint32 FlightCount; 376 377 uint32 HoverPoint; 378 379 uint64 AkamaGUID; 380 uint64 MaievGUID; 381 uint64 FlameGUID[2]; 382 uint64 GlaiveGUID[2]; 383 384 std::list<uint64> ParasiteTargets; // for safety, do not use Unit* 385 386 void Reset(); 387 388 void JustSummoned(Creature* summon)//, TempSummonType type) 389 { 390 if(summon->GetCreatureInfo()->Entry == FLAME_CRASH) 391 { 392 // type = TEMPSUMMON_TIMED_DESPAWN; 393 } 394 //error_log("justsummoned %d %d", summon->GetCreatureInfo()->Entry, summon->GetGUID()); 395 } 396 397 void SummonedCreatureDespawn(Creature* summon) 398 { 399 if(summon->GetCreatureInfo()->Entry == FLAME_OF_AZZINOTH) 400 { 401 for(uint8 i = 0; i < 2; i++) 402 if(summon->GetGUID() == FlameGUID[i]) 403 FlameGUID[i] = 0; 404 405 if(!FlameGUID[0] && !FlameGUID[1]) 406 { 407 m_creature->InterruptNonMeleeSpells(true); 408 EnterPhase(PHASE_FLIGHT_SEQUENCE); 409 } 410 } 411 } 412 413 void MovementInform(uint32 MovementType, uint32 Data) 414 { 415 if(FlightCount == 7) //change hover point 416 { 417 if(m_creature->getVictim()) 418 { 419 m_creature->SetInFront(m_creature->getVictim()); 420 m_creature->StopMoving(); 421 } 422 EnterPhase(PHASE_FLIGHT); 423 } 424 else 425 Timer[EVENT_FLIGHT_SEQUENCE] = 1000; 426 } 427 428 void Aggro(Unit *who) 429 { 430 DoZoneInCombat(); 431 } 432 433 void AttackStart(Unit *who) 434 { 435 if(!who || Phase >= PHASE_TALK_SEQUENCE) 436 return; 437 438 if (who->isTargetableForAttack()) 439 { 440 if(Phase == PHASE_FLIGHT || Phase == PHASE_DEMON) 441 m_creature->Attack(who, false); 442 else 443 DoStartAttackAndMovement(who); 444 445 if (!InCombat) 446 { 447 Aggro(who); 448 InCombat = true; 449 } 450 } 451 } 452 453 void MoveInLineOfSight(Unit *who) {} 454 455 void JustDied(Unit *killer) 456 { 457 m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); 458 459 if(!pInstance) 460 return; 461 462 pInstance->SetData(DATA_ILLIDANSTORMRAGEEVENT, DONE); // Completed 463 464 for(uint8 i = DATA_GAMEOBJECT_ILLIDAN_DOOR_R; i < DATA_GAMEOBJECT_ILLIDAN_DOOR_L + 1; ++i) 465 { 466 GameObject* Door = GameObject::GetGameObject((*m_creature), pInstance->GetData64(i)); 467 if(Door) 468 Door->SetUInt32Value(GAMEOBJECT_STATE, 0); // Open Doors 469 } 470 } 471 472 void KilledUnit(Unit *victim) 473 { 474 if(victim == m_creature) return; 475 476 switch(rand()%2) 477 { 478 case 0: 479 DoYell(SAY_KILL1, LANG_UNIVERSAL, victim); 480 DoPlaySoundToSet(m_creature, SOUND_KILL1); 481 break; 482 case 1: 483 DoYell(SAY_KILL2, LANG_UNIVERSAL, victim); 484 DoPlaySoundToSet(m_creature, SOUND_KILL2); 485 break; 486 } 487 } 488 489 void DamageTaken(Unit *done_by, uint32 &damage) 490 { 491 if(damage >= m_creature->GetHealth() && done_by != m_creature) 492 damage = 0; 493 if(done_by->GetGUID() == MaievGUID) 494 done_by->AddThreat(m_creature, -(3*(float)damage)/4); // do not let maiev tank him 495 } 496 497 void SpellHit(Unit *caster, const SpellEntry *spell) 498 { 499 if(spell->Id == SPELL_GLAIVE_RETURNS) // Re-equip our warblades! 500 { 501 if(!m_creature->GetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_DISPLAY)) 502 m_creature->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_DISPLAY, 45479); 503 else 504 m_creature->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_DISPLAY+1, 45481); 505 m_creature->SetByteValue(UNIT_FIELD_BYTES_2, 0, SHEATH_STATE_MELEE ); 506 } 507 } 508 509 void AddParasiteTarget(uint64 targetGUID) 510 { 511 for(std::list<uint64>::iterator tIter = ParasiteTargets.begin(); tIter != ParasiteTargets.end(); tIter++) 512 { 513 if(*tIter == targetGUID) 514 return; 515 } 516 ParasiteTargets.push_back(targetGUID); 517 518 if(Phase == PHASE_NORMAL || Phase == PHASE_NORMAL_2 || Phase == PHASE_NORMAL_MAIEV) 519 Timer[EVENT_PARASITE_CHECK] += 1000; 520 } 521 522 void DeleteFromThreatList(uint64 TargetGUID) 523 { 524 for(std::list<HostilReference*>::iterator itr = m_creature->getThreatManager().getThreatList().begin(); itr != m_creature->getThreatManager().getThreatList().end(); ++itr) 525 { 526 if((*itr)->getUnitGuid() == TargetGUID) 527 { 528 (*itr)->removeReference(); 529 break; 530 } 531 } 532 } 533 534 void Talk(uint32 count) 535 { 536 Timer[EVENT_TALK_SEQUENCE] = Conversation[count].timer; 537 538 Creature* creature = NULL; 539 if(Conversation[count].creature == ILLIDAN_STORMRAGE) 540 creature = m_creature; 541 else if(Conversation[count].creature == AKAMA) 542 creature = ((Creature*)Unit::GetUnit((*m_creature), AkamaGUID)); 543 else if(Conversation[count].creature == MAIEV_SHADOWSONG) 544 creature = ((Creature*)Unit::GetUnit((*m_creature), MaievGUID)); 545 546 if(creature) 547 { 548 if(Conversation[count].emote) 549 creature->HandleEmoteCommand(Conversation[count].emote); // Make the creature do some animation! 550 if(Conversation[count].text) 551 creature->Yell(Conversation[count].text, LANG_UNIVERSAL, 0); // Have the creature yell out some text 552 if(Conversation[count].sound) 553 DoPlaySoundToSet(creature, Conversation[count].sound); // Play some sound on the creature 554 } 555 } 556 557 void EnterPhase(PhaseIllidan NextPhase); 558 void CastEyeBlast(); 559 void SummonFlamesOfAzzinoth(); 560 void SummonMaiev(); 561 void SummonShadowDemon() 562 { 563 Creature* ShadowDemon = NULL; 564 Unit* target = NULL; 565 for(uint8 i = 0; i < 4; i++) 566 { 567 ShadowDemon = DoSpawnCreature(SHADOW_DEMON, 0,0,0,0,TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN,25000); 568 if(ShadowDemon) 569 { 570 target = SelectUnit(SELECT_TARGET_RANDOM, 0); 571 if(target && target->GetTypeId() == TYPEID_PLAYER) // only on players. 572 { 573 ShadowDemon->AddThreat(target, 5000000.0f); 574 ShadowDemon->AI()->AttackStart(target); 575 } 576 DoZoneInCombat(ShadowDemon); 577 } 578 } 579 } 580 void HandleTalkSequence(); 581 void HandleFlightSequence() 582 { 583 switch(FlightCount) 584 { 585 case 1://lift off 586 m_creature->HandleEmoteCommand(EMOTE_ONESHOT_LIFTOFF); 587 //m_creature->GetMotionMaster()->Clear(false); 588 m_creature->SetUnitMovementFlags(MOVEMENTFLAG_LEVITATING); 589 //m_creature->GetMotionMaster()->MovePoint(0, m_creature->GetPositionX(),m_creature->GetPositionY(),m_creature->GetPositionZ()); 590 m_creature->StopMoving(); 591 DoYell(SAY_TAKEOFF, LANG_UNIVERSAL, NULL); 592 DoPlaySoundToSet(m_creature, SOUND_TAKEOFF); 593 Timer[EVENT_FLIGHT_SEQUENCE] = 3000; 594 break; 595 case 2://move to center 596 //m_creature->GetMotionMaster()->Clear(false); 597 m_creature->AddUnitMovementFlag(MOVEMENTFLAG_ONTRANSPORT); 598 m_creature->GetMotionMaster()->MovePoint(0, CENTER_X + 5, CENTER_Y, CENTER_Z); //+5, for SPELL_THROW_GLAIVE bug 599 m_creature->RemoveUnitMovementFlag(MOVEMENTFLAG_ONTRANSPORT); 600 Timer[EVENT_FLIGHT_SEQUENCE] = 0; 601 break; 602 case 3://throw one glaive 603 { 604 uint8 i=1; 605 Creature* Glaive = m_creature->SummonCreature(BLADE_OF_AZZINOTH, GlaivePosition[i].x, GlaivePosition[i].y, GlaivePosition[i].z, 0, TEMPSUMMON_CORPSE_DESPAWN, 0); 606 if(Glaive) 607 { 608 GlaiveGUID[i] = Glaive->GetGUID(); 609 Glaive->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); 610 Glaive->SetUInt32Value(UNIT_FIELD_DISPLAYID, 11686); 611 Glaive->setFaction(m_creature->getFaction()); 612 DoCast(Glaive, SPELL_THROW_GLAIVE2); 613 } 614 } 615 Timer[EVENT_FLIGHT_SEQUENCE] = 700; 616 break; 617 case 4://throw another 618 m_creature->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_DISPLAY, 0); 619 m_creature->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_DISPLAY+1, 0); 620 { 621 uint8 i=0; 622 Creature* Glaive = m_creature->SummonCreature(BLADE_OF_AZZINOTH, GlaivePosition[i].x, GlaivePosition[i].y, GlaivePosition[i].z, 0, TEMPSUMMON_CORPSE_DESPAWN, 0); 623 if(Glaive) 624 { 625 GlaiveGUID[i] = Glaive->GetGUID(); 626 Glaive->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); 627 Glaive->SetUInt32Value(UNIT_FIELD_DISPLAYID, 11686); 628 Glaive->setFaction(m_creature->getFaction()); 629 DoCast(Glaive, SPELL_THROW_GLAIVE, true); 630 } 631 } 632 Timer[EVENT_FLIGHT_SEQUENCE] = 5000; 633 break; 634 case 5://summon flames 635 SummonFlamesOfAzzinoth(); 636 Timer[EVENT_FLIGHT_SEQUENCE] = 3000; 637 break; 638 case 6://fly to hover point 639 m_creature->AddUnitMovementFlag(MOVEMENTFLAG_ONTRANSPORT); 640 m_creature->GetMotionMaster()->MovePoint(0, HoverPosition[HoverPoint].x, HoverPosition[HoverPoint].y, HoverPosition[HoverPoint].z); 641 m_creature->RemoveUnitMovementFlag(MOVEMENTFLAG_ONTRANSPORT); 642 Timer[EVENT_FLIGHT_SEQUENCE] = 0; 643 break; 644 case 7://return to center 645 m_creature->AddUnitMovementFlag(MOVEMENTFLAG_ONTRANSPORT); 646 m_creature->GetMotionMaster()->MovePoint(0, CENTER_X, CENTER_Y, CENTER_Z); 647 m_creature->RemoveUnitMovementFlag(MOVEMENTFLAG_ONTRANSPORT); 648 Timer[EVENT_FLIGHT_SEQUENCE] = 0; 649 break; 650 case 8://glaive return 651 for(uint8 i = 0; i < 2; i++) 652 { 653 if(GlaiveGUID[i]) 654 { 655 Unit* Glaive = Unit::GetUnit((*m_creature), GlaiveGUID[i]); 656 if(Glaive) 657 { 658 Glaive->CastSpell(m_creature, SPELL_GLAIVE_RETURNS, false); // Make it look like the Glaive flies back up to us 659 Glaive->SetUInt32Value(UNIT_FIELD_DISPLAYID, 11686); // disappear but not die for now 660 } 661 } 662 } 663 Timer[EVENT_FLIGHT_SEQUENCE] = 2000; 664 break; 665 case 9://land 666 //m_creature->GetMotionMaster()->Clear(false); 667 m_creature->RemoveUnitMovementFlag(MOVEMENTFLAG_LEVITATING); 668 //m_creature->GetMotionMaster()->MovePoint(0, m_creature->GetPositionX(),m_creature->GetPositionY(),m_creature->GetPositionZ()); 669 m_creature->StopMoving(); 670 m_creature->HandleEmoteCommand(EMOTE_ONESHOT_LAND); 671 for(uint8 i = 0; i < 2; i++) 672 { 673 if(GlaiveGUID[i]) 674 { 675 if(GETUNIT(Glaive, GlaiveGUID[i])) 676 { 677 Glaive->SetVisibility(VISIBILITY_OFF); 678 Glaive->setDeathState(JUST_DIED); // Despawn the Glaive 679 } 680 GlaiveGUID[i] = 0; 681 } 682 } 683 Timer[EVENT_FLIGHT_SEQUENCE] = 2000; 684 break; 685 case 10://attack 686 DoResetThreat(); 687 m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE + UNIT_FLAG_NOT_SELECTABLE); 688 //m_creature->GetMotionMaster()->Clear(); 689 m_creature->SetByteValue(UNIT_FIELD_BYTES_2, 0, SHEATH_STATE_MELEE ); 690 EnterPhase(PHASE_NORMAL_2); 691 break; 692 default: 693 break; 694 } 695 FlightCount++; 696 } 697 698 void HandleTransformSequence() 699 { 700 if(DemonTransformation[TransformCount].unaura) 701 m_creature->RemoveAurasDueToSpell(DemonTransformation[TransformCount].unaura); 702 703 if(DemonTransformation[TransformCount].aura) 704 DoCast(m_creature, DemonTransformation[TransformCount].aura, true); 705 706 if(DemonTransformation[TransformCount].displayid) 707 m_creature->SetUInt32Value(UNIT_FIELD_DISPLAYID, DemonTransformation[TransformCount].displayid); // It's morphin time! 708 709 if(DemonTransformation[TransformCount].equip) 710 { 711 m_creature->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_DISPLAY, 45479); // Requip warglaives if needed 712 m_creature->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_DISPLAY+1, 45481); 713 m_creature->SetByteValue(UNIT_FIELD_BYTES_2, 0, SHEATH_STATE_MELEE ); 714 } 715 else 716 { 717 m_creature->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_DISPLAY, 0); // Unequip warglaives if needed 718 m_creature->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_DISPLAY+1, 0); 719 } 720 721 switch(TransformCount) 722 { 723 case 2: 724 DoResetThreat(); 725 break; 726 case 4: 727 EnterPhase(PHASE_DEMON); 728 break; 729 case 7: 730 DoResetThreat(); 731 break; 732 case 9: 733 if(MaievGUID) 734 EnterPhase(PHASE_NORMAL_MAIEV); // Depending on whether we summoned Maiev, we switch to either phase 5 or 3 735 else 736 EnterPhase(PHASE_NORMAL_2); 737 break; 738 default: 739 break; 740 } 741 if(Phase == PHASE_TRANSFORM_SEQUENCE) 742 Timer[EVENT_TRANSFORM_SEQUENCE] = DemonTransformation[TransformCount].timer; 743 TransformCount++; 744 } 745 746 void UpdateAI(const uint32 diff) 747 { 748 if((!m_creature->SelectHostilTarget() || !m_creature->getVictim()) && Phase < PHASE_TALK_SEQUENCE) 749 return; 750 751 Event = EVENT_NULL; 752 for(uint32 i = 1; i <= MaxTimer[Phase]; i++) 753 if(Timer[i]) 754 if(Timer[i] <= diff) 755 { 756 if(!Event) 757 Event = (EventIllidan)i; 758 } 759 else Timer[i] -= diff; 760 761 switch(Phase) 762 { 763 case PHASE_NORMAL: 764 if(HPPCT(m_creature) < 65) 765 EnterPhase(PHASE_FLIGHT_SEQUENCE); 766 break; 767 768 case PHASE_NORMAL_2: 769 if(m_creature->GetHealth()*100 / m_creature->GetMaxHealth() < 30) 770 EnterPhase(PHASE_TALK_SEQUENCE); 771 break; 772 773 case PHASE_NORMAL_MAIEV: 774 if(m_creature->GetHealth()*100 / m_creature->GetMaxHealth() < 1) 775 EnterPhase(PHASE_TALK_SEQUENCE); 776 break; 777 778 case PHASE_TALK_SEQUENCE: 779 if(Event == EVENT_TALK_SEQUENCE) 780 HandleTalkSequence(); 781 break; 782 783 case PHASE_FLIGHT_SEQUENCE: 784 if(Event == EVENT_FLIGHT_SEQUENCE) 785 HandleFlightSequence(); 786 break; 787 788 case PHASE_TRANSFORM_SEQUENCE: 789 if(Event == EVENT_TRANSFORM_SEQUENCE) 790 HandleTransformSequence(); 791 break; 792 } 793 794 if(m_creature->IsNonMeleeSpellCasted(false)) 795 return; 796 797 if(Phase == PHASE_NORMAL || Phase == PHASE_NORMAL_2 || Phase == PHASE_NORMAL_MAIEV && !m_creature->HasAura(SPELL_CAGED, 0)) 798 { 799 switch(Event) 800 { 801 //PHASE_NORMAL 802 case EVENT_BERSERK: 803 DoYell(SAY_ENRAGE, LANG_UNIVERSAL, NULL); 804 DoPlaySoundToSet(m_creature, SOUND_ENRAGE); 805 DoCast(m_creature, SPELL_BERSERK, true); 806 Timer[EVENT_BERSERK] = 5000;//The buff actually lasts forever. 807 break; 808 809 case EVENT_TAUNT: 810 { 811 uint32 random = rand()%4; 812 char* yell = RandomTaunts[random].text; 813 uint32 soundid = RandomTaunts[random].sound; 814 if(yell) 815 DoYell(yell, LANG_UNIVERSAL, NULL); 816 if(soundid) 817 DoPlaySoundToSet(m_creature, soundid); 818 } 819 Timer[EVENT_TAUNT] = 32000; 820 break; 821 822 case EVENT_SHEAR: 823 DoCast(m_creature->getVictim(), SPELL_SHEAR); 824 Timer[EVENT_SHEAR] = 25000 + (rand()%16 * 1000); 825 break; 826 827 case EVENT_FLAME_CRASH: 828 DoCast(m_creature->getVictim(), SPELL_FLAME_CRASH); 829 Timer[EVENT_FLAME_CRASH] = 35000; 830 break; 831 832 case EVENT_PARASITIC_SHADOWFIEND: 833 { 834 Unit* target = SelectUnit(SELECT_TARGET_RANDOM, 1); 835 if(!target) target = m_creature->getVictim(); 836 if(target->GetTypeId() == TYPEID_PLAYER && !target->HasAura(SPELL_PARASITIC_SHADOWFIEND, 0)) 837 { 838 target->CastSpell(target, SPELL_PARASITIC_SHADOWFIEND, true); // do not miss 839 ParasiteTargets.push_back(target->GetGUID()); 840 Timer[EVENT_PARASITE_CHECK] += 1000; // do not check immediately 841 } 842 Timer[EVENT_PARASITIC_SHADOWFIEND] = 40000; 843 } 844 break; 845 846 case EVENT_PARASITE_CHECK: 847 for(std::list<uint64>::iterator tIter = ParasiteTargets.begin(); tIter != ParasiteTargets.end();) 848 { 849 Unit* target = Unit::GetUnit((*m_creature), *tIter); 850 if(!target || !target->HasAura(SPELL_PARASITIC_SHADOWFIEND, 0)) 851 { 852 if(target && target->isAlive()) 853 target->CastSpell(target, SPELL_SUMMON_PARASITICS, true); 854 std::list<uint64>::iterator tIter2 = tIter; 855 ++tIter; 856 ParasiteTargets.erase(tIter2); 857 } 858 else 859 ++tIter; 860 } 861 if(ParasiteTargets.empty()) 862 Timer[EVENT_PARASITE_CHECK] = 0; 863 else 864 Timer[EVENT_PARASITE_CHECK] = 1000; 865 break; 866 867 case EVENT_DRAW_SOUL: 868 DoCast(m_creature->getVictim(), SPELL_DRAW_SOUL); 869 Timer[EVENT_DRAW_SOUL] = 55000; 870 break; 871 872 //PHASE_NORMAL_2 873 case EVENT_AGONIZING_FLAMES: 874 DoCast(SelectUnit(SELECT_TARGET_RANDOM,0), SPELL_AGONIZING_FLAMES); 875 Timer[EVENT_AGONIZING_FLAMES] = 0; 876 break; 877 878 case EVENT_TRANSFORM_NORMAL: 879 EnterPhase(PHASE_TRANSFORM_SEQUENCE); 880 break; 881 882 //PHASE_NORMAL_MAIEV 883 case EVENT_ENRAGE: 884 DoCast(m_creature, SPELL_ENRAGE); 885 Timer[EVENT_ENRAGE] = 0; 886 break; 887 888 default: 889 break; 890 } 891 DoMeleeAttackIfReady(); 892 } 893 894 if(Phase == PHASE_FLIGHT) 895 { 896 switch(Event) 897 { 898 case EVENT_FIREBALL: 899 DoCast(SelectUnit(SELECT_TARGET_RANDOM, 0), SPELL_FIREBALL); 900 Timer[EVENT_FIREBALL] = 3000; 901 break; 902 903 case EVENT_DARK_BARRAGE: 904 DoCast(SelectUnit(SELECT_TARGET_RANDOM, 0), SPELL_DARK_BARRAGE); 905 Timer[EVENT_DARK_BARRAGE] = 0; 906 break; 907 908 case EVENT_EYE_BLAST: 909 CastEyeBlast(); 910 Timer[EVENT_EYE_BLAST] = 0; 911 break; 912 913 case EVENT_MOVE_POINT: 914 Phase = PHASE_FLIGHT_SEQUENCE; 915 Timer[EVENT_FLIGHT_SEQUENCE] = 0;//do not start Event when changing hover point 916 for (uint8 i = 0; i <= rand()%3; i++) 917 { 918 HoverPoint++; 919 if(HoverPoint > 3) 920 HoverPoint = 0; 921 } 922 m_creature->AddUnitMovementFlag(MOVEMENTFLAG_ONTRANSPORT); 923 m_creature->GetMotionMaster()->MovePoint(0, HoverPosition[HoverPoint].x, HoverPosition[HoverPoint].y, HoverPosition[HoverPoint].z); 924 m_creature->RemoveUnitMovementFlag(MOVEMENTFLAG_ONTRANSPORT); 925 break; 926 927 default: 928 break; 929 } 930 } 931 932 if(Phase == PHASE_DEMON) 933 { 934 switch(Event) 935 { 936 case EVENT_SHADOW_BLAST: 937 m_creature->GetMotionMaster()->Clear(false); 938 if(!m_creature->IsWithinDistInMap(m_creature->getVictim(), 50)||!m_creature->IsWithinLOSInMap(m_creature->getVictim())) 939 m_creature->GetMotionMaster()->MoveChase(m_creature->getVictim(), 30); 940 else 941 m_creature->GetMotionMaster()->MoveIdle(); 942 DoCast(m_creature->getVictim(), SPELL_SHADOW_BLAST); 943 Timer[EVENT_SHADOW_BLAST] = 4000; 944 break; 945 case EVENT_SHADOWDEMON: 946 SummonShadowDemon(); 947 Timer[EVENT_SHADOWDEMON] = 0; 948 Timer[EVENT_FLAME_BURST] += 10000; 949 break; 950 case EVENT_FLAME_BURST: 951 DoCast(m_creature, SPELL_FLAME_BURST); 952 Timer[EVENT_FLAME_BURST] = 15000; 953 break; 954 case EVENT_TRANSFORM_DEMON: 955 EnterPhase(PHASE_TRANSFORM_SEQUENCE); 956 break; 957 default: 958 break; 959 } 960 } 961 } 962 }; 963 964 /********************************** End of Illidan AI ******************************************/ 965 966 //This is used to sort the players by distance in preparation for being charged by the flames. 967 struct TargetDistanceOrder : public std::binary_function<const Unit, const Unit, bool> 968 { 969 const Unit* MainTarget; 970 TargetDistanceOrder(const Unit* Target) : MainTarget(Target) {}; 971 // functor for operator ">" 972 bool operator()(const Unit* _Left, const Unit* _Right) const 973 { 974 return (MainTarget->GetDistance(_Left) > MainTarget->GetDistance(_Right)); 975 } 976 }; 977 978 struct TRINITY_DLL_DECL flame_of_azzinothAI : public ScriptedAI 979 { 980 flame_of_azzinothAI(Creature *c) : ScriptedAI(c) {Reset();} 981 982 uint32 FlameBlastTimer; 983 uint32 CheckTimer; 984 uint64 GlaiveGUID; 985 986 void Reset() 987 { 988 FlameBlastTimer = 15000; 989 CheckTimer = 5000; 990 GlaiveGUID = 0; 991 } 992 993 void Aggro(Unit *who) {} 994 995 void ChargeCheck() 996 { 997 // Get the Threat List 998 std::list<HostilReference *> m_threatlist = m_creature->getThreatManager().getThreatList(); 999 1000 if(!m_threatlist.size()) return; // He doesn't have anyone in his threatlist, useless to continue 1001 1002 std::list<Unit *> targets; 1003 std::list<HostilReference *>::iterator itr = m_threatlist.begin(); 1004 for( ; itr!= m_threatlist.end(); ++itr) //store the threat list in a different container 1005 { 1006 Unit *target = Unit::GetUnit(*m_creature, (*itr)->getUnitGuid()); 1007 if(target && target->isAlive() && target->GetTypeId() == TYPEID_PLAYER && target->GetPositionZ()>350) //only on alive players 1008 targets.push_back(target); 1009 } 1010 1011 if (!targets.size()) 1012 return; 1013 1014 //Sort the list of players 1015 targets.sort(TargetDistanceOrder(m_creature)); 1016 //Resize so we only get the furthest target 1017 targets.resize(1); 1018 1019 Unit* target = (*targets.begin()); 1020 if(target && (!m_creature->IsWithinDistInMap(target, FLAME_CHARGE_DISTANCE))) 1021 { 1022 m_creature->AttackStop(); 1023 m_creature->GetMotionMaster()->Clear(false); 1024 float x, y, z; // is it possible to fix charge? 1025 target->GetContactPoint(m_creature, x, y, z); 1026 m_creature->Relocate(x,y,z); 1027 m_creature->SendMonsterMove(x, y, z, 0, MOVEMENTFLAG_WALK_MODE, 1); 1028 //m_creature->GetMotionMaster()->MovePoint(0, m_creature->GetPositionX(), m_creature->GetPositionY(), m_creature->GetPositionZ()); 1029 m_creature->StopMoving(); 1030 //DoCast(target, SPELL_CHARGE); 1031 m_creature->AddThreat(target, 5000000.0f); 1032 DoTextEmote("sets its gaze on $N!", target); 1033 } 1034 } 1035 1036 void EnrageCheck() 1037 { 1038 if(GETUNIT(Glaive, GlaiveGUID)) 1039 { 1040 if(!m_creature->IsWithinDistInMap(Glaive, FLAME_ENRAGE_DISTANCE)) 1041 { 1042 Glaive->InterruptNonMeleeSpells(true); 1043 DoCast(m_creature, SPELL_FLAME_ENRAGE, true); 1044 DoResetThreat(); 1045 Unit* target = SelectUnit(SELECT_TARGET_RANDOM, 0); 1046 if(target && target->isAlive()) 1047 { 1048 m_creature->AddThreat(m_creature->getVictim(), 5000000.0f); 1049 AttackStart(m_creature->getVictim()); 1050 } 1051 } 1052 else if(!m_creature->HasAura(SPELL_AZZINOTH_CHANNEL, 0)) 1053 { 1054 Glaive->CastSpell(m_creature, SPELL_AZZINOTH_CHANNEL, false); 1055 m_creature->RemoveAurasDueToSpell(SPELL_FLAME_ENRAGE); 1056 } 1057 } 1058 } 1059 1060 void SetGlaiveGUID(uint64 guid){ GlaiveGUID = guid; } 1061 1062 void UpdateAI(const uint32 diff) 1063 { 1064 if(!m_creature->SelectHostilTarget() || !m_creature->getVictim()) 1065 return; 1066 1067 if(FlameBlastTimer < diff) 1068 { 1069 DoCast(m_creature->getVictim(), SPELL_BLAZE_SUMMON, true); //appear at victim 1070 DoCast(m_creature->getVictim(), SPELL_FLAME_BLAST); 1071 FlameBlastTimer = 15000; //10000 is official-like? 1072 DoZoneInCombat(); //in case someone is revived 1073 }else FlameBlastTimer -= diff; 1074 1075 if(CheckTimer < diff) 1076 { 1077 ChargeCheck(); 1078 EnrageCheck(); 1079 CheckTimer = 5000; 1080 }else CheckTimer -= diff; 1081 1082 DoMeleeAttackIfReady(); 1083 } 1084 }; 1085 1086 1087 1088 /******* Functions and vars for Akama's AI ******/ 1089 struct TRINITY_DLL_DECL npc_akama_illidanAI : public ScriptedAI 1090 { 1091 npc_akama_illidanAI(Creature* c) : ScriptedAI(c) 1092 { 1093 pInstance = ((ScriptedInstance*)c->GetInstanceData()); 1094 Reset(); 1095 } 1096 1097 ScriptedInstance* pInstance; 1098 1099 PhaseAkama Phase; 1100 bool Event; 1101 uint32 Timer; 1102 294 1103 uint64 IllidanGUID; 295 296 bool IsTrigger; 297 298 uint32 CheckTimer; 299 uint32 DemonFireTimer; 300 uint32 DespawnTimer; 1104 uint64 ChannelGUID; 1105 uint64 SpiritGUID[2]; 1106 uint64 GateGUID; 1107 uint64 DoorGUID[2]; 1108 1109 uint32 ChannelCount; 1110 uint32 WalkCount; 1111 uint32 TalkCount; 301 1112 302 1113 void Reset() 303 1114 { 304 IllidanGUID = 0;305 306 IsTrigger = false;307 308 CheckTimer = 2000;309 DemonFireTimer = 0;310 DespawnTimer = 45000;311 }312 313 void Aggro(Unit *who) {}314 void AttackStart(Unit* who) { }315 void MoveInLineOfSight(Unit *who){ }316 317 void UpdateAI(const uint32 diff)318 {319 if(IsTrigger)320 return;321 322 m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);323 324 if(CheckTimer < diff)325 {326 if(!IllidanGUID && pInstance)327 {328 IllidanGUID = pInstance->GetData64(DATA_ILLIDANSTORMRAGE);329 if(IllidanGUID)330 {331 Unit* Illidan = Unit::GetUnit((*m_creature), IllidanGUID);332 if(Illidan && !Illidan->HasUnitMovementFlag(MOVEMENTFLAG_LEVITATING))333 m_creature->setDeathState(JUST_DIED);334 }335 }336 CheckTimer = 2000;337 }else CheckTimer -= diff;338 339 if(DemonFireTimer < diff)340 {341 DoCast(m_creature, SPELL_DEMON_FIRE);342 DemonFireTimer = 30000;343 }else DemonFireTimer -= diff;344 345 if(DespawnTimer < diff)346 m_creature->setDeathState(JUST_DIED);347 else DespawnTimer -= diff;348 349 DoMeleeAttackIfReady();350 }351 };352 353 /******* Functions and vars for Akama's AI ******/354 struct TRINITY_DLL_SPEC npc_akama_illidanAI : public ScriptedAI355 {356 npc_akama_illidanAI(Creature* c) : ScriptedAI(c)357 {358 pInstance = ((ScriptedInstance*)c->GetInstanceData());359 WayPointList.clear();360 Reset();361 }362 363 /* Instance Data */364 ScriptedInstance* pInstance;365 366 /* Timers */367 uint32 ChannelTimer;368 uint32 TalkTimer;369 uint32 WalkTimer;370 uint32 SummonMinionTimer;371 372 /* GUIDs */373 uint64 IllidanGUID;374 uint64 PlayerGUID;375 uint64 SpiritGUID[2];376 uint64 ChannelGUID;377 378 bool IsTalking;379 bool StartChanneling;380 bool DoorOpen;381 bool FightMinions;382 bool IsReturningToIllidan;383 bool IsWalking;384 uint32 TalkCount;385 uint32 ChannelCount;386 387 std::list<WayPoints> WayPointList;388 std::list<WayPoints>::iterator WayPoint;389 390 void BeginEvent(uint64 PlayerGUID);391 void Aggro(Unit *who) {}392 393 void Reset()394 {395 1115 if(pInstance) 396 1116 { 397 1117 pInstance->SetData(DATA_ILLIDANSTORMRAGEEVENT, NOT_STARTED); 398 GameObject* Gate = GameObject::GetGameObject((*m_creature), pInstance->GetData64(DATA_GAMEOBJECT_ILLIDAN_GATE)); 399 if( Gate && !Gate->GetGoState() ) 400 Gate->SetGoState(1); // close door if already open (when raid wipes or something) 401 402 for(uint8 i = DATA_GAMEOBJECT_ILLIDAN_DOOR_R; i < DATA_GAMEOBJECT_ILLIDAN_DOOR_L + 1; ++i) 403 { 404 GameObject* Door = GameObject::GetGameObject((*m_creature), pInstance->GetData64(i)); 405 if(Door) 406 Door->SetGoState(0); 407 } 408 } 409 410 IllidanGUID = 0; 411 PlayerGUID = 0; 1118 1119 IllidanGUID = pInstance->GetData64(DATA_ILLIDANSTORMRAGE); 1120 GateGUID = pInstance->GetData64(DATA_GAMEOBJECT_ILLIDAN_GATE); 1121 DoorGUID[0] = pInstance->GetData64(DATA_GAMEOBJECT_ILLIDAN_DOOR_R); 1122 DoorGUID[1] = pInstance->GetData64(DATA_GAMEOBJECT_ILLIDAN_DOOR_L); 1123 1124 if(GETGO(Gate, GateGUID)) 1125 Gate->SetUInt32Value(GAMEOBJECT_STATE, 1); 1126 for(uint8 i = 0; i < 2; i++) 1127 if(GETGO(Door, DoorGUID[i])) 1128 Door->SetUInt32Value(GAMEOBJECT_STATE, 1); 1129 } 1130 else 1131 { 1132 IllidanGUID = 0; 1133 GateGUID = 0; 1134 DoorGUID[0] = 0; 1135 DoorGUID[1] = 0; 1136 } 1137 412 1138 ChannelGUID = 0; 413 for(uint8 i = 0; i < 2; ++i) SpiritGUID[i] = 0; 414 415 ChannelTimer = 0; 1139 SpiritGUID[0] = 0; 1140 SpiritGUID[1] = 0; 1141 1142 Phase = PHASE_AKAMA_NULL; 1143 Timer = 0; 1144 416 1145 ChannelCount = 0; 417 SummonMinionTimer = 2000; 418 419 WalkTimer = 0; 420 421 TalkTimer = 0; 1146 WalkCount = 0; 422 1147 TalkCount = 0; 423 1148 424 1149 KillAllElites(); 425 1150 426 IsReturningToIllidan = false; 427 FightMinions = false; 428 IsTalking = false; 429 StartChanneling = false; 430 DoorOpen = false; 431 432 m_creature->SetUInt32Value(UNIT_NPC_FLAGS, 0); // Database sometimes has strange values.. 1151 m_creature->SetUInt32Value(UNIT_NPC_FLAGS, 0); // Database sometimes has strange values.. 433 1152 m_creature->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); 434 m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE);435 m_creature->SetVisibility(VISIBILITY_ON);436 1153 } 437 1154 … … 439 1156 void EnterEvadeMode() 440 1157 { 441 InCombat = false; 442 1158 m_creature->InterruptNonMeleeSpells(true); 443 1159 m_creature->RemoveAllAuras(); 444 1160 m_creature->DeleteThreatList(); 445 1161 m_creature->CombatStop(); 1162 InCombat = false; 1163 } 1164 1165 void Aggro(Unit *who) {} 1166 1167 void MovementInform(uint32 MovementType, uint32 Data) {Timer = 1;} 1168 1169 void DamageTaken(Unit *done_by, uint32 &damage) 1170 { 1171 if(damage > m_creature->GetHealth() || done_by->GetGUID() != IllidanGUID) 1172 damage = 0; 446 1173 } 447 1174 … … 455 1182 pUnit->setDeathState(JUST_DIED); 456 1183 } 457 } 458 459 void ReturnToIllidan() 460 { 461 KillAllElites(); 462 InCombat = false; 463 FightMinions = false; 464 IsReturningToIllidan = true; 465 WayPoint = WayPointList.begin(); 466 m_creature->SetSpeed(MOVE_RUN, 2.0f); 1184 EnterEvadeMode(); 1185 } 1186 1187 void BeginTalk() 1188 { 1189 pInstance->SetData(DATA_ILLIDANSTORMRAGEEVENT, IN_PROGRESS); 1190 1191 for(uint8 i = 0; i < 2; i++) 1192 if(GETGO(Door, DoorGUID[i])) 1193 Door->SetUInt32Value(GAMEOBJECT_STATE, 1); 1194 1195 if(GETCRE(Illidan, IllidanGUID)) 1196 { 1197 Illidan->RemoveAurasDueToSpell(SPELL_KNEEL); 1198 m_creature->SetInFront(Illidan); 1199 Illidan->SetInFront(m_creature); 1200 m_creature->StopMoving(); 1201 Illidan->StopMoving(); 1202 ((boss_illidan_stormrageAI*)Illidan->AI())->AkamaGUID = m_creature->GetGUID(); 1203 ((boss_illidan_stormrageAI*)Illidan->AI())->EnterPhase(PHASE_TALK_SEQUENCE); 1204 } 1205 } 1206 1207 void BeginChannel() 1208 { 1209 float x, y, z; 1210 if(GETGO(Gate, GateGUID)) 1211 Gate->GetPosition(x, y, z); 1212 1213 if(Creature* Channel = m_creature->SummonCreature(ILLIDAN_DOOR_TRIGGER, x, y, z+5, 0, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 360000)) 1214 { 1215 ChannelGUID = Channel->GetGUID(); 1216 Channel->SetUInt32Value(UNIT_FIELD_DISPLAYID, 11686); // Invisible but spell visuals can still be seen. 1217 m_creature->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); 1218 DoCast(Channel, SPELL_AKAMA_DOOR_FAIL); 1219 } 1220 1221 for(uint8 i = 0; i < 2; ++i) 1222 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)) 1223 { 1224 Spirit->SetVisibility(VISIBILITY_OFF); 1225 SpiritGUID[i] = Spirit->GetGUID(); 1226 } 1227 } 1228 1229 void BeginWalk() 1230 { 467 1231 m_creature->RemoveUnitMovementFlag(MOVEMENTFLAG_WALK_MODE); 468 IsWalking = true; 469 } 470 471 void AddWaypoint(uint32 id, float x, float y, float z) 472 { 473 WayPoints AkamaWP(id, x, y, z); 474 WayPointList.push_back(AkamaWP); 475 } 476 477 void DamageTaken(Unit *done_by, uint32 &damage) 478 { 479 if(damage > m_creature->GetHealth() && (done_by->GetGUID() != m_creature->GetGUID())) 480 { 481 damage = 0; 482 DoCast(m_creature, SPELL_HEALING_POTION); 483 } 484 } 485 486 void BeginDoorEvent(Player* player) 487 { 488 if(!pInstance) 489 return; 490 491 outstring_log("SD2: Akama - Door event initiated by player %s", player->GetName()); 492 PlayerGUID = player->GetGUID(); 493 494 GameObject* Gate = GameObject::GetGameObject((*m_creature), pInstance->GetData64(DATA_GAMEOBJECT_ILLIDAN_GATE)); 495 if(Gate) 496 { 497 float x,y,z; 498 Gate->GetPosition(x, y, z); 499 Creature* Channel = m_creature->SummonCreature(ILLIDAN_DOOR_TRIGGER, x, y, z+5, 0, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 360000); 500 if(Channel) 501 { 502 ChannelGUID = Channel->GetGUID(); 503 // Invisible but spell visuals can still be seen. 504 Channel->SetUInt32Value(UNIT_FIELD_DISPLAYID, 11686); 505 Channel->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); 506 float PosX, PosY, PosZ; 507 m_creature->GetPosition(PosX, PosY, PosZ); 508 for(uint8 i = 0; i < 2; ++i) 1232 m_creature->SetSpeed(MOVE_RUN, 1.0f); 1233 m_creature->GetMotionMaster()->MovePoint(0, AkamaWP[WalkCount].x, AkamaWP[WalkCount].y, AkamaWP[WalkCount].z); 1234 } 1235 1236 void EnterPhase(PhaseAkama NextPhase) 1237 { 1238 if(!pInstance) return; 1239 switch(NextPhase) 1240 { 1241 case PHASE_CHANNEL: 1242 BeginChannel(); 1243 Timer = 5000; 1244 ChannelCount = 0; 1245 break; 1246 case PHASE_WALK: 1247 if(Phase == PHASE_CHANNEL) 1248 WalkCount = 0; 1249 else if(Phase == PHASE_TALK) 1250 { 1251 if(GETCRE(Illidan, IllidanGUID)) 1252 ((boss_illidan_stormrageAI*)Illidan->AI())->DeleteFromThreatList(m_creature->GetGUID()); 1253 EnterEvadeMode(); 1254 m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); 1255 WalkCount++; 1256 } 1257 BeginWalk(); 1258 Timer = 0; 1259 break; 1260 case PHASE_TALK: 1261 if(Phase == PHASE_WALK) 1262 { 1263 BeginTalk(); 1264 Timer = 0; 1265 } 1266 else if(Phase == PHASE_FIGHT_ILLIDAN) 1267 { 1268 Timer = 1; 1269 TalkCount = 0; 1270 } 1271 break; 1272 case PHASE_FIGHT_ILLIDAN: 1273 if(GETUNIT(Illidan, IllidanGUID)) 1274 { 1275 m_creature->AddThreat(Illidan, 10000000.0f); 1276 m_creature->GetMotionMaster()->MoveChase(Illidan); 1277 } 1278 Timer = 30000; //chain lightning 1279 break; 1280 case PHASE_FIGHT_MINIONS: 1281 m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); 1282 Timer = 10000 + rand()%6000;//summon minion 1283 break; 1284 case PHASE_RETURN: 1285 m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); 1286 KillAllElites(); 1287 WalkCount = 0; 1288 BeginWalk(); 1289 Timer = 1; 1290 break; 1291 default: 1292 break; 1293 } 1294 Phase = NextPhase; 1295 Event = false; 1296 } 1297 1298 void HandleTalkSequence() 1299 { 1300 switch(TalkCount) 1301 { 1302 case 0: 1303 if(GETCRE(Illidan, IllidanGUID)) 1304 { 1305 ((boss_illidan_stormrageAI*)Illidan->AI())->Timer[EVENT_TAUNT] += 30000; 1306 Illidan->Yell(SAY_AKAMA_MINION, LANG_UNIVERSAL, 0); 1307 DoPlaySoundToSet(Illidan, SOUND_AKAMA_MINION); 1308 } 1309 Timer = 8000; 1310 break; 1311 case 1: 1312 DoYell(SAY_AKAMA_LEAVE, LANG_UNIVERSAL, NULL); 1313 DoPlaySoundToSet(m_creature, SOUND_AKAMA_LEAVE); 1314 Timer = 3000; 1315 break; 1316 case 2: 1317 EnterPhase(PHASE_WALK); 1318 break; 1319 } 1320 TalkCount++; 1321 } 1322 1323 void HandleChannelSequence() 1324 { 1325 Unit* Channel, *Spirit[2]; 1326 if(ChannelCount <= 5) 1327 { 1328 Channel = Unit::GetUnit((*m_creature), ChannelGUID); 1329 Spirit[0] = Unit::GetUnit((*m_creature), SpiritGUID[0]); 1330 Spirit[1] = Unit::GetUnit((*m_creature), SpiritGUID[1]); 1331 if(!Channel || !Spirit[0] || !Spirit[1]) 1332 return; 1333 } 1334 1335 switch(ChannelCount) 1336 { 1337 case 0: // channel failed 1338 m_creature->InterruptNonMeleeSpells(true); 1339 Timer = 2000; 1340 break; 1341 case 1: // spirit appear 1342 Spirit[0]->SetVisibility(VISIBILITY_ON); 1343 Spirit[1]->SetVisibility(VISIBILITY_ON); 1344 Timer = 2000; 1345 break; 1346 case 2: // spirit help 1347 DoCast(Channel, SPELL_AKAMA_DOOR_CHANNEL); 1348 Spirit[0]->CastSpell(Channel, SPELL_DEATHSWORN_DOOR_CHANNEL,false); 1349 Spirit[1]->CastSpell(Channel, SPELL_DEATHSWORN_DOOR_CHANNEL,false); 1350 Timer = 5000; 1351 break; 1352 case 3: //open the gate 1353 m_creature->InterruptNonMeleeSpells(true); 1354 Spirit[0]->InterruptNonMeleeSpells(true); 1355 Spirit[1]->InterruptNonMeleeSpells(true); 1356 if(GETGO(Gate, GateGUID)) 1357 Gate->SetUInt32Value(GAMEOBJECT_STATE, 0); 1358 Timer = 2000; 1359 break; 1360 case 4: 1361 m_creature->HandleEmoteCommand(EMOTE_ONESHOT_SALUTE); 1362 Timer = 2000; 1363 break; 1364 case 5: 1365 DoYell(SAY_AKAMA_BEWARE, LANG_UNIVERSAL, NULL); 1366 DoPlaySoundToSet(m_creature, SOUND_AKAMA_BEWARE); 1367 Channel->setDeathState(JUST_DIED); 1368 Spirit[0]->setDeathState(JUST_DIED); 1369 Spirit[1]->setDeathState(JUST_DIED); 1370 Timer = 3000; 1371 break; 1372 case 6: 1373 EnterPhase(PHASE_WALK); 1374 break; 1375 default: 1376 break; 1377 } 1378 ChannelCount++; 1379 } 1380 1381 void HandleWalkSequence() 1382 { 1383 switch(WalkCount) 1384 { 1385 case 6: 1386 for(uint8 i = 0; i < 2; i++) 1387 if(GETGO(Door, DoorGUID[i])) 1388 Door->SetUInt32Value(GAMEOBJECT_STATE, 0); 1389 break; 1390 case 8: 1391 if(Phase == PHASE_WALK) 1392 EnterPhase(PHASE_TALK); 1393 else 1394 EnterPhase(PHASE_FIGHT_ILLIDAN); 1395 break; 1396 case 12: 1397 EnterPhase(PHASE_FIGHT_MINIONS); 1398 break; 1399 } 1400 1401 if(Phase == PHASE_WALK) 1402 { 1403 Timer = 0; 1404 WalkCount++; 1405 m_creature->GetMotionMaster()->MovePoint(WalkCount, AkamaWP[WalkCount].x, AkamaWP[WalkCount].y, AkamaWP[WalkCount].z); 1406 } 1407 } 1408 1409 void UpdateAI(const uint32 diff) 1410 { 1411 Event = false; 1412 if(Timer) 1413 { 1414 if(Timer <= diff) 1415 Event = true; 1416 else Timer -= diff; 1417 } 1418 1419 if(Event) 1420 { 1421 switch(Phase) 1422 { 1423 case PHASE_CHANNEL: 1424 HandleChannelSequence(); 1425 break; 1426 case PHASE_TALK: 1427 HandleTalkSequence(); 1428 break; 1429 case PHASE_WALK: 1430 case PHASE_RETURN: 1431 HandleWalkSequence(); 1432 break; 1433 case PHASE_FIGHT_ILLIDAN: 509 1434 { 510 Creature* Spirit = m_creature->SummonCreature(SpiritSpawns[i].id, SpiritSpawns[i].x, SpiritSpawns[i].y, SpiritSpawns[i].z, 0, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 360000); 511 if(Spirit) 1435 GETUNIT(Illidan, IllidanGUID); 1436 if(Illidan && HPPCT(Illidan) < 90) 1437 EnterPhase(PHASE_TALK); 1438 else 512 1439 { 513 Spirit->SetVisibility(VISIBILITY_OFF);514 SpiritGUID[i] = Spirit->GetGUID();1440 DoCast(m_creature->getVictim(), SPELL_CHAIN_LIGHTNING); 1441 Timer = 30000; 515 1442 } 516 } 517 StartChanneling = true; 518 m_creature->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); 519 m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); 520 DoCast(Channel, SPELL_AKAMA_DOOR_FAIL); 521 } 522 } 523 } 524 525 void MovementInform(uint32 type, uint32 id) 526 { 527 if(type != POINT_MOTION_TYPE || !IsWalking) 528 return; 529 530 if(WayPoint->id != id) 531 return; 532 533 switch(id) 534 { 535 case 6: 536 if(!IsReturningToIllidan) 537 { // open the doors that close the summit 538 for(uint32 i = DATA_GAMEOBJECT_ILLIDAN_DOOR_R; i < DATA_GAMEOBJECT_ILLIDAN_DOOR_L+1; ++i) 1443 }break; 1444 case PHASE_FIGHT_MINIONS: 1445 { 1446 float x, y, z; 1447 m_creature->GetPosition(x, y, z); 1448 Creature* Elite = m_creature->SummonCreature(ILLIDARI_ELITE, x+rand()%10, y+rand()%10, z, 0, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, 30000); 1449 //Creature* Elite = m_creature->SummonCreature(ILLIDARI_ELITE, x, y, z, 0, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, 30000); 1450 if(Elite) 539 1451 { 540 GameObject* Door = GameObject::GetGameObject((*m_creature), pInstance->GetData64(i));541 if(Door)542 Door->SetGoState(0);1452 Elite->AI()->AttackStart(m_creature); 1453 Elite->AddThreat(m_creature, 1000000.0f); 1454 AttackStart(Elite); 543 1455 } 544 } 545 case 7: 546 if(IsReturningToIllidan) 547 { 548 IsWalking = false; 549 if(IllidanGUID) 550 { 551 Unit* Illidan = Unit::GetUnit((*m_creature), IllidanGUID); 552 if(Illidan) 553 { 554 float dx = Illidan->GetPositionX() + rand()%15; 555 float dy = Illidan->GetPositionY() + rand()%15; 556 m_creature->GetMotionMaster()->MovePoint(13, dx, dy, Illidan->GetPositionZ()); 557 m_creature->SetUInt64Value(UNIT_FIELD_TARGET, IllidanGUID); 558 } 559 } 1456 Timer = 10000 + rand()%6000; 1457 GETUNIT(Illidan, IllidanGUID); 1458 if(Illidan && HPPCT(Illidan) < 10) 1459 EnterPhase(PHASE_RETURN); 560 1460 } 561 1461 break; 562 case 8: 563 m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); 564 if(!IsReturningToIllidan) 1462 default: 1463 break; 1464 } 1465 } 1466 1467 if(!m_creature->SelectHostilTarget() || !m_creature->getVictim()) 1468 return; 1469 1470 if(m_creature->GetHealth()*100 / m_creature->GetMaxHealth() < 20) 1471 DoCast(m_creature, SPELL_HEALING_POTION); 1472 1473 DoMeleeAttackIfReady(); 1474 } 1475 }; 1476 1477 1478 struct TRINITY_DLL_DECL boss_maievAI : public ScriptedAI 1479 { 1480 boss_maievAI(Creature *c) : ScriptedAI(c) { Reset(); }; 1481 1482 uint64 IllidanGUID; 1483 1484 PhaseIllidan Phase; 1485 EventMaiev Event; 1486 uint32 Timer[5]; 1487 uint32 MaxTimer; 1488 1489 void Reset() 1490 { 1491 MaxTimer = 0; 1492 Phase = PHASE_NORMAL_MAIEV; 1493 IllidanGUID = 0; 1494 Timer[EVENT_MAIEV_STEALTH] = 0; 1495 Timer[EVENT_MAIEV_TAUNT] = 22000 + rand()%21 * 1000; 1496 Timer[EVENT_MAIEV_SHADOW_STRIKE] = 30000; 1497 m_creature->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_DISPLAY, 44850); 1498 m_creature->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_DISPLAY + 1, 0); 1499 m_creature->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_DISPLAY + 2, 45738); 1500 } 1501 1502 void Aggro(Unit *who) {} 1503 void MoveInLineOfSight(Unit *who) {} 1504 void EnterEvadeMode() {} 1505 void GetIllidanGUID(uint64 guid) { IllidanGUID = guid; } 1506 1507 void DamageTaken(Unit *done_by, uint32 &damage) 1508 { 1509 if(done_by->GetGUID() != IllidanGUID ) 1510 damage = 0; 1511 else 1512 { 1513 GETUNIT(Illidan, IllidanGUID); 1514 if(Illidan && Illidan->getVictim() == m_creature) 1515 damage = m_creature->GetMaxHealth()/10; 1516 if(damage >= m_creature->GetHealth()) 1517 damage = 0; 1518 } 1519 } 1520 1521 void AttackStart(Unit *who) 1522 { 1523 if(!who || Timer[EVENT_MAIEV_STEALTH]) 1524 return; 1525 1526 if (who->isTargetableForAttack()) 1527 { 1528 if(Phase == PHASE_TALK_SEQUENCE) 1529 m_creature->Attack(who, false); 1530 else if(Phase == PHASE_DEMON || Phase == PHASE_TRANSFORM_SEQUENCE ) 1531 { 1532 GETUNIT(Illidan, IllidanGUID); 1533 if(Illidan && m_creature->IsWithinDistInMap(Illidan, 25)) 1534 BlinkToPlayer();//Do not let dread aura hurt her. 1535 m_creature->Attack(who, false); 1536 } 1537 else 1538 DoStartAttackAndMovement(who); 1539 1540 if (!InCombat) 1541 { 1542 Aggro(who); 1543 InCombat = true; 1544 } 1545 } 1546 } 1547 1548 void EnterPhase(PhaseIllidan NextPhase)//This is in fact Illidan's phase. 1549 { 1550 switch(NextPhase) 1551 { 1552 case PHASE_TALK_SEQUENCE: 1553 if(Timer[EVENT_MAIEV_STEALTH]) 1554 { 1555 m_creature->SetHealth(m_creature->GetMaxHealth()); 1556 m_creature->SetVisibility(VISIBILITY_ON); 1557 Timer[EVENT_MAIEV_STEALTH] = 0; 1558 } 1559 m_creature->InterruptNonMeleeSpells(false); 1560 m_creature->GetMotionMaster()->Clear(false); 1561 //m_creature->GetMotionMaster()->MoveIdle(); 1562 m_creature->AttackStop(); 1563 m_creature->SetUInt64Value(UNIT_FIELD_TARGET, IllidanGUID); 1564 MaxTimer = 0; 1565 break; 1566 case PHASE_TRANSFORM_SEQUENCE: 1567 MaxTimer = 4; 1568 Timer[EVENT_MAIEV_TAUNT] += 10000; 1569 Timer[EVENT_MAIEV_THROW_DAGGER] = 2000; 1570 break; 1571 case PHASE_DEMON: 1572 break; 1573 case PHASE_NORMAL_MAIEV: 1574 MaxTimer = 4; 1575 Timer[EVENT_MAIEV_TAUNT] += 10000; 1576 Timer[EVENT_MAIEV_TRAP] = 22000; 1577 break; 1578 default: 1579 break; 1580 } 1581 if(Timer[EVENT_MAIEV_STEALTH]) 1582 MaxTimer = 1; 1583 Phase = NextPhase; 1584 } 1585 1586 void BlinkTo(float x, float y, float z) 1587 { 1588 m_creature->AttackStop(); 1589 m_creature->InterruptNonMeleeSpells(false); 1590 m_creature->GetMotionMaster()->Clear(false); 1591 //m_creature->GetMotionMaster()->MoveIdle(); 1592 m_creature->Relocate(x, y, z); 1593 m_creature->SendMonsterMove(x, y, z, 0, 0, 0); 1594 DoCast(m_creature, SPELL_TELEPORT_VISUAL, true); 1595 } 1596 1597 void BlinkToPlayer() 1598 { 1599 if(GETCRE(Illidan, IllidanGUID)) 1600 { 1601 Unit* target = ((boss_illidan_stormrageAI*)Illidan->AI())->SelectUnit(SELECT_TARGET_RANDOM, 0); 1602 1603 if(!target || !m_creature->IsWithinDistInMap(target, 80) || Illidan->IsWithinDistInMap(target, 20)) 1604 { 1605 uint8 pos = rand()%4; 1606 BlinkTo(HoverPosition[pos].x, HoverPosition[pos].y, HoverPosition[pos].z); 1607 } 1608 else 1609 { 1610 float x, y, z; 1611 target->GetPosition(x, y, z); 1612 BlinkTo(x, y, z); 1613 } 1614 } 1615 } 1616 1617 void UpdateAI(const uint32 diff) 1618 { 1619 if((!m_creature->SelectHostilTarget() || !m_creature->getVictim()) && !Timer[1]) 1620 return; 1621 1622 Event = EVENT_MAIEV_NULL; 1623 for(uint8 i = 1; i <= MaxTimer; i++) 1624 if(Timer[i]) 1625 { 1626 if(Timer[i] <= diff) 1627 Event = (EventMaiev)i; 1628 else Timer[i] -= diff; 1629 } 1630 1631 switch(Event) 1632 { 1633 case EVENT_MAIEV_STEALTH: 565 1634 { 566 IsWalking = false; 567 BeginEvent(PlayerGUID); 568 } 1635 m_creature->SetHealth(m_creature->GetMaxHealth()); 1636 m_creature->SetVisibility(VISIBILITY_ON); 1637 m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); 1638 Timer[EVENT_MAIEV_STEALTH] = 0; 1639 BlinkToPlayer(); 1640 EnterPhase(Phase); 1641 }break; 1642 case EVENT_MAIEV_TAUNT: 1643 { 1644 uint32 random = rand()%4; 1645 char* text = MaievTaunts[random].text; 1646 uint32 sound = MaievTaunts[random].sound; 1647 DoYell(text, LANG_UNIVERSAL, NULL); 1648 DoPlaySoundToSet(m_creature, sound); 1649 Timer[EVENT_MAIEV_TAUNT] = 22000 + rand()%21 * 1000; 1650 }break; 1651 case EVENT_MAIEV_SHADOW_STRIKE: 1652 DoCast(m_creature->getVictim(), SPELL_SHADOW_STRIKE); 1653 Timer[EVENT_MAIEV_SHADOW_STRIKE] = 60000; 569 1654 break; 570 case 12: 571 IsWalking = false; 572 FightMinions = true; 573 m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); 574 break; 575 } 576 577 ++WayPoint; 578 WalkTimer = 200; 579 } 580 581 void DeleteFromThreatList() 582 { 583 if(!IllidanGUID) return; // If we do not have Illidan's GUID, do not proceed 584 // Create a pointer to Illidan 585 Creature* Illidan = ((Creature*)Unit::GetUnit((*m_creature), IllidanGUID)); 586 if(!Illidan) return; // No use to continue if Illidan does not exist 587 std::list<HostilReference*>::iterator itr = Illidan->getThreatManager().getThreatList().begin(); 588 for( ; itr != Illidan->getThreatManager().getThreatList().end(); ++itr) 589 { 590 // Loop through threatlist till our GUID is found in it. 591 if((*itr)->getUnitGuid() == m_creature->GetGUID()) 592 { 593 (*itr)->removeReference(); // Delete ourself from his threatlist. 594 return; // No need to continue anymore. 595 } 596 } 597 598 // Now we delete our threatlist to prevent attacking anyone for now 599 m_creature->DeleteThreatList(); 600 } 601 602 void UpdateAI(const uint32 diff) 603 { 604 if(IllidanGUID) 605 { 606 Creature* Illidan = ((Creature*)Unit::GetUnit((*m_creature), IllidanGUID)); 607 if(Illidan) 608 { 609 if(Illidan->IsInEvadeMode() && !m_creature->IsInEvadeMode()) 610 EnterEvadeMode(); 611 612 if(((Illidan->GetHealth()*100 / Illidan->GetMaxHealth()) < 85) && InCombat && !FightMinions) 1655 case EVENT_MAIEV_TRAP: 1656 if(Phase == PHASE_NORMAL_MAIEV) 613 1657 { 614 if(TalkTimer < diff) 615 { 616 switch(TalkCount) 617 { 618 case 0: 619 Illidan->Yell(SAY_AKAMA_MINION, LANG_UNIVERSAL, 0); 620 DoPlaySoundToSet(Illidan, SOUND_AKAMA_MINION); 621 TalkTimer = 8000; 622 TalkCount = 1; 623 break; 624 case 1: 625 DoYell(SAY_AKAMA_LEAVE, LANG_UNIVERSAL, NULL); 626 DoPlaySoundToSet(m_creature, SOUND_AKAMA_LEAVE); 627 TalkTimer = 3000; 628 TalkCount = 2; 629 break; 630 case 2: 631 IsTalking = true; 632 TalkTimer = 2000; 633 m_creature->RemoveAllAuras(); 634 m_creature->CombatStop(); 635 m_creature->AttackStop(); 636 m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); 637 TalkCount = 3; 638 break; 639 case 3: 640 DeleteFromThreatList(); 641 IsWalking = true; 642 WayPoint = WayPointList.begin(); 643 std::advance(WayPoint, 9); 644 m_creature->RemoveUnitMovementFlag(MOVEMENTFLAG_WALK_MODE); 645 break; 646 } 647 }else TalkTimer -= diff; 648 } 649 650 if(((Illidan->GetHealth()*100 / Illidan->GetMaxHealth()) < 4) && !IsReturningToIllidan) 651 ReturnToIllidan(); 652 } 653 }else 654 { 655 if(pInstance) 656 IllidanGUID = pInstance->GetData64(DATA_ILLIDANSTORMRAGE); 657 } 658 659 if(IsWalking && WalkTimer) 660 { 661 if(WalkTimer <= diff) 662 { 663 if(WayPoint == WayPointList.end()) 664 return; 665 m_creature->GetMotionMaster()->MovePoint(WayPoint->id, WayPoint->x, WayPoint->y,WayPoint->z); 666 WalkTimer = 0; 667 }else WalkTimer -= diff; 668 } 669 670 if(StartChanneling) 671 { 672 if(ChannelTimer < diff) 673 { 674 switch(ChannelCount) 675 { 676 case 3: 677 if(!DoorOpen) 678 { 679 m_creature->InterruptNonMeleeSpells(true); 680 for(uint8 i = 0; i < 2; ++i) 681 { 682 if(SpiritGUID[i]) 683 { 684 Unit* Spirit = Unit::GetUnit((*m_creature), SpiritGUID[i]); 685 if(Spirit) 686 Spirit->InterruptNonMeleeSpells(true); 687 } 688 } 689 GameObject* Gate = GameObject::GetGameObject((*m_creature), pInstance->GetData64(DATA_GAMEOBJECT_ILLIDAN_GATE)); 690 if(Gate) 691 Gate->SetGoState(0); 692 ChannelCount++; 693 ChannelTimer = 5000; 694 } 695 break; 696 case 4: 697 m_creature->HandleEmoteCommand(EMOTE_ONESHOT_SALUTE); 698 ChannelTimer = 2000; 699 ChannelCount++; 700 break; 701 case 5: 702 DoYell(SAY_AKAMA_BEWARE, LANG_UNIVERSAL, NULL); 703 DoPlaySoundToSet(m_creature, SOUND_AKAMA_BEWARE); 704 if(ChannelGUID) 705 { 706 Unit* ChannelTarget = Unit::GetUnit((*m_creature), ChannelGUID); 707 if(ChannelTarget) 708 ChannelTarget->setDeathState(JUST_DIED); 709 } 710 for(uint8 i = 0; i < 2; ++i) 711 { 712 if(SpiritGUID[i]) 713 { 714 Unit* Spirit = Unit::GetUnit((*m_creature), SpiritGUID[i]); 715 if(Spirit) 716 Spirit->setDeathState(JUST_DIED); 717 } 718 } 719 ChannelTimer = 6000; 720 ChannelCount++; 721 break; 722 case 6: 723 StartChanneling = false; 724 if(WayPointList.empty()) 725 { 726 error_log("SD2: Akama has no waypoints to start with!"); 727 return; 728 } 729 730 WayPoint = WayPointList.begin(); 731 m_creature->AddUnitMovementFlag(MOVEMENTFLAG_WALK_MODE); 732 m_creature->GetMotionMaster()->MovePoint(WayPoint->id, WayPoint->x, WayPoint->y, WayPoint->z); 733 IsWalking = true; 734 break; 735 default: 736 if(ChannelGUID) 737 { 738 Unit* Channel = Unit::GetUnit((*m_creature), ChannelGUID); 739 if(Channel) 740 { 741 m_creature->InterruptNonMeleeSpells(true); 742 743 for(uint8 i = 0; i < 2; ++i) 744 { 745 if(SpiritGUID[i]) 746 { 747 Unit* Spirit = Unit::GetUnit((*m_creature), SpiritGUID[i]); 748 if(Spirit) 749 { 750 Spirit->InterruptNonMeleeSpells(true); 751 if(ChannelCount%2 == 0) 752 { 753 Spirit->CastSpell(Channel, SPELL_DEATHSWORN_DOOR_CHANNEL,false); 754 DoCast(Channel, SPELL_AKAMA_DOOR_CHANNEL); 755 } 756 else 757 { 758 if(Spirit->GetVisibility() == VISIBILITY_OFF) 759 Spirit->SetVisibility(VISIBILITY_ON); 760 } 761 } 762 } 763 } 764 if(ChannelCount < 3) 765 ChannelCount++; 766 ChannelTimer = 10000; 767 } 768 break; 769 } 770 } 771 }else ChannelTimer -= diff; 772 } 773 774 if(FightMinions) 775 { 776 if(SummonMinionTimer < diff) 777 { 778 if(IllidanGUID) 779 { 780 Creature* Illidan = ((Creature*)Unit::GetUnit((*m_creature), IllidanGUID)); 781 if(!Illidan || Illidan->IsInEvadeMode()) 782 { 783 Reset(); 784 EnterEvadeMode(); 785 return; 786 } 787 } 788 789 float x,y,z; 790 m_creature->GetPosition(x,y,z); 791 Creature* Elite = m_creature->SummonCreature(ILLIDARI_ELITE, x+rand()%10, y+rand()%10, z, 0, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, 30000); 792 if(Elite) 793 { 794 Elite->AI()->AttackStart(m_creature); 795 Elite->AddThreat(m_creature, 1000000.0f); 796 AttackStart(Elite); 797 } 798 SummonMinionTimer = 10000 + rand()%6000; 799 }else SummonMinionTimer -= diff; 800 } 801 802 // If we don't have a target, or is talking, or has run away, return 803 if(!m_creature->SelectHostilTarget() || !m_creature->getVictim()) return; 804 805 DoMeleeAttackIfReady(); 806 } 807 }; 808 809 /************* Custom check used for Agonizing Flames ***************/ 810 class AgonizingFlamesTargetCheck 811 { 812 public: 813 AgonizingFlamesTargetCheck(Unit const* unit) : pUnit(unit) {} 814 bool operator() (Player* plr) 815 { 816 // Faster than square rooting 817 if(!plr->isGameMaster() && pUnit->GetDistance2d(plr) > 225) 818 return true; 819 820 return false; 821 } 822 823 private: 824 Unit const* pUnit; 825 }; 826 827 /************************************** Illidan's AI ***************************************/ 828 struct TRINITY_DLL_SPEC boss_illidan_stormrageAI : public ScriptedAI 829 { 830 boss_illidan_stormrageAI(Creature* c) : ScriptedAI(c) 831 { 832 pInstance = ((ScriptedInstance*)c->GetInstanceData()); 833 Reset(); 834 } 835 836 /** Instance Data **/ 837 ScriptedInstance* pInstance; 838 839 /** Generic **/ 840 bool IsTalking; 841 bool HasSummoned; 842 bool RefaceVictim; 843 bool InformAkama; 844 uint32 Phase; 845 uint32 GlobalTimer; 846 uint32 TalkCount; 847 uint32 DemonFormSequence; 848 849 /** GUIDs **/ 850 uint64 FlameGUID[2]; 851 uint64 GlaiveGUID[2]; 852 uint64 AkamaGUID; 853 uint64 MaievGUID; 854 855 /** Timers **/ 856 uint32 ShearTimer; 857 uint32 DrawSoulTimer; 858 uint32 FlameCrashTimer; 859 uint32 ParasiticShadowFiendTimer; 860 uint32 FireballTimer; 861 uint32 EyeBlastTimer; 862 uint32 DarkBarrageTimer; 863 uint32 SummonBladesTimer; // Animate summoning the Blades of Azzinoth in Phase 2 864 uint32 SummonFlamesTimer; // Summon Flames of Azzinoth in Phase 2 865 uint32 CheckFlamesTimer; // This is used to check the status of the Flames to see if we should begin entering Phase 3 or not. 866 uint32 RetrieveBladesTimer; // Animate retrieving the Blades of Azzinoth in Phase 2 -> 3 transition 867 uint32 LandTimer; // This is used at the end of phase 2 to signal Illidan landing after Flames are dead 868 uint32 AgonizingFlamesTimer; 869 uint32 ShadowBlastTimer; 870 uint32 FlameBurstTimer; 871 uint32 ShadowDemonTimer; 872 uint32 TalkTimer; 873 uint32 TransformTimer; 874 uint32 EnrageTimer; 875 uint32 CageTimer; 876 uint32 LayTrapTimer; 877 uint32 AnimationTimer; 878 uint32 TauntTimer; // This is used for his random yells 879 uint32 FaceVictimTimer; 880 uint32 BerserkTimer; 881 882 void Reset() 883 { 884 Phase = PHASE_NORMAL; 885 886 // Check if any flames/glaives are alive/existing. Kill if alive and set GUIDs to 0 887 for(uint8 i = 0; i < 2; i++) 888 { 889 if(FlameGUID[i]) 890 { 891 Unit* Flame = Unit::GetUnit((*m_creature), FlameGUID[i]); 892 if(Flame) 893 Flame->setDeathState(JUST_DIED); 894 FlameGUID[i] = 0; 895 } 896 897 if(GlaiveGUID[i]) 898 { 899 Unit* Glaive = Unit::GetUnit((*m_creature), GlaiveGUID[i]); 900 if(Glaive) 901 Glaive->setDeathState(JUST_DIED); 902 GlaiveGUID[i] = 0; 903 } 904 } 905 906 if(AkamaGUID) 907 { 908 Creature* Akama = ((Creature*)Unit::GetUnit((*m_creature), AkamaGUID)); 909 if(Akama) 910 { 911 if(!Akama->isAlive()) 912 Akama->Respawn(); 913 ((npc_akama_illidanAI*)Akama->AI())->Reset(); 914 ((npc_akama_illidanAI*)Akama->AI())->EnterEvadeMode(); 915 Akama->GetMotionMaster()->MoveTargetedHome(); 916 } 917 } 918 919 InformAkama = false; 920 RefaceVictim = false; 921 HasSummoned = false; 922 AkamaGUID = 0; 923 MaievGUID = 0; 924 925 FaceVictimTimer = 1000; 926 BerserkTimer = 1500000; 927 GlobalTimer = 0; 928 DemonFormSequence = 0; 929 930 /** Normal Form **/ 931 ShearTimer = 20000 + (rand()%11 * 1000); // 20 to 30 seconds 932 FlameCrashTimer = 30000; //30 seconds 933 ParasiticShadowFiendTimer = 25000; // 25 seconds 934 DrawSoulTimer = 50000; // 50 seconds 935 936 /** Phase 2 **/ 937 SummonBladesTimer = 10000; 938 SummonFlamesTimer = 20000; // Phase 2 timers may be incorrect 939 FireballTimer = 5000; 940 DarkBarrageTimer = 45000; 941 EyeBlastTimer = 30000; 942 CheckFlamesTimer = 5000; 943 RetrieveBladesTimer = 5000; 944 LandTimer = 0; 945 946 /** Phase 3+ **/ 947 AgonizingFlamesTimer = 35000; // Phase 3+ timers may be incorrect 948 ShadowBlastTimer = 3000; 949 FlameBurstTimer = 10000; 950 ShadowDemonTimer = 30000; 951 TransformTimer = 90000; 952 EnrageTimer = 40000; 953 CageTimer = 30000; 954 LayTrapTimer = CageTimer + 2000; 955 AnimationTimer = 0; 956 957 TauntTimer = 30000; // This timer may be off. 958 959 m_creature->SetUInt32Value(UNIT_FIELD_DISPLAYID, 21135); 960 m_creature->InterruptNonMeleeSpells(false); 961 m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); 962 m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); 963 // Unequip warglaives if needed 964 m_creature->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_DISPLAY, 0); 965 m_creature->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_DISPLAY+1, 0); 966 m_creature->RemoveUnitMovementFlag(MOVEMENTFLAG_LEVITATING); 967 968 IsTalking = false; 969 970 TalkCount = 0; 971 TalkTimer = 0; 972 973 if(pInstance) 974 pInstance->SetData(DATA_ILLIDANSTORMRAGEEVENT, NOT_STARTED); 975 } 976 977 void Aggro(Unit *who) { DoZoneInCombat(); } 978 979 void AttackStart(Unit *who) 980 { 981 if(!who || IsTalking || Phase == 2 || Phase == 4 || Phase == 6 || m_creature->HasAura(SPELL_KNEEL, 0)) 982 return; 983 984 if (who->isTargetableForAttack() && who!= m_creature) 985 { 986 //Begin melee attack if we are within range 987 DoStartAttackAndMovement(who); 988 } 989 } 990 991 void MoveInLineOfSight(Unit *who) 992 { 993 if (!who || m_creature->getVictim() || IsTalking || m_creature->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE)) 994 return; 995 996 if (who->isTargetableForAttack() && who->isInAccessablePlaceFor(m_creature) && m_creature->IsHostileTo(who)) 997 { 998 if (!m_creature->canFly() && m_creature->GetDistanceZ(who) > CREATURE_Z_ATTACK_RANGE) 999 return; 1000 1001 float attackRadius = m_creature->GetAttackDistance(who); 1002 if (m_creature->IsWithinDistInMap(who, attackRadius) && m_creature->IsWithinLOSInMap(who)) 1003 { 1004 if(who->HasStealthAura()) 1005 who->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH); 1006 1007 DoStartAttackAndMovement(who); 1008 } 1009 } 1010 } 1011 1012 void JustDied(Unit *killer) 1013 { 1014 IsTalking = false; 1015 TalkCount = 0; 1016 TalkTimer = 0; 1017 1018 m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); 1019 1020 if(!pInstance) 1021 return; 1022 // Completed 1023 pInstance->SetData(DATA_ILLIDANSTORMRAGEEVENT, DONE); 1024 1025 for(uint8 i = DATA_GAMEOBJECT_ILLIDAN_DOOR_R; i < DATA_GAMEOBJECT_ILLIDAN_DOOR_L + 1; ++i) 1026 { 1027 GameObject* Door = GameObject::GetGameObject((*m_creature), pInstance->GetData64(i)); 1028 if(Door) 1029 Door->SetGoState(0); // Open Doors 1030 } 1031 1032 } 1033 1034 void KilledUnit(Unit *victim) 1035 { 1036 if(victim == m_creature) return; 1037 1038 switch(rand()%2) 1039 { 1040 case 0: 1041 DoYell(SAY_KILL1, LANG_UNIVERSAL, victim); 1042 DoPlaySoundToSet(m_creature, SOUND_KILL1); 1043 break; 1044 case 1: 1045 DoYell(SAY_KILL2, LANG_UNIVERSAL, victim); 1046 DoPlaySoundToSet(m_creature, SOUND_KILL2); 1047 break; 1048 } 1049 } 1050 1051 void DamageTaken(Unit *done_by, uint32 &damage) 1052 { 1053 if(damage > m_creature->GetHealth()) // Don't let ourselves be slain before we do our death speech 1054 { 1055 damage = 0; 1056 m_creature->SetHealth(m_creature->GetMaxHealth()/100); 1057 } 1058 } 1059 1060 void Cast(Unit* victim, uint32 Spell, bool triggered = false) 1061 { 1062 if(!victim) 1063 return; 1064 1065 RefaceVictim = true; 1066 m_creature->SetUInt64Value(UNIT_FIELD_TARGET, victim->GetGUID()); 1067 m_creature->CastSpell(victim, Spell, triggered); 1068 } 1069 1070 /** This will handle the cast of eye blast **/ 1071 void CastEyeBlast() 1072 { 1073 m_creature->InterruptNonMeleeSpells(false); 1074 1075 DarkBarrageTimer += 10000; 1076 1077 DoYell(SAY_EYE_BLAST, LANG_UNIVERSAL, NULL); 1078 DoPlaySoundToSet(m_creature, SOUND_EYE_BLAST); 1079 1080 uint32 initial = rand()%4; 1081 uint32 final = 0; 1082 if(initial < 3) 1083 final = initial+1; 1084 1085 float initial_X = EyeBlast[initial].x; 1086 float initial_Y = EyeBlast[initial].y; 1087 float initial_Z = EyeBlast[initial].z; 1088 1089 float final_X = EyeBlast[final].x; 1090 float final_Y = EyeBlast[final].y; 1091 float final_Z = EyeBlast[final].z; 1092 1093 for(uint8 i = 0; i < 2; ++i) 1094 { 1095 Creature* Trigger = NULL; 1096 Trigger = m_creature->SummonCreature(DEMON_FIRE, initial_X, initial_Y, initial_Z, 0, TEMPSUMMON_TIMED_DESPAWN, 20000); 1097 if(Trigger) 1098 { 1099 ((demonfireAI*)Trigger->AI())->IsTrigger = true; 1100 Trigger->GetMotionMaster()->MovePoint(0, final_X, final_Y, final_Z); 1101 1102 if(!i) 1103 Trigger->CastSpell(Trigger, SPELL_EYE_BLAST_TRIGGER, true); 1104 else 1105 { 1106 Trigger->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); 1107 m_creature->SetUInt64Value(UNIT_FIELD_TARGET, Trigger->GetGUID()); 1108 DoCast(Trigger, SPELL_EYE_BLAST); 1109 } 1110 } 1111 } 1112 } 1113 1114 // 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). 1115 void CastAgonizingFlames() 1116 { 1117 // We'll use grid searching for this, using a custom searcher that selects a player that is at a distance >15 yards 1118 Player* target = NULL; 1119 1120 CellPair pair(Trinity::ComputeCellPair(m_creature->GetPositionX(), m_creature->GetPositionY())); 1121 Cell cell(pair); 1122 cell.data.Part.reserved = ALL_DISTRICT; 1123 cell.SetNoCreate(); 1124 1125 AgonizingFlamesTargetCheck check(m_creature); 1126 Trinity::PlayerSearcher<AgonizingFlamesTargetCheck> searcher(target, check); 1127 TypeContainerVisitor 1128 <Trinity::PlayerSearcher<AgonizingFlamesTargetCheck>, GridTypeMapContainer> visitor(searcher); 1129 1130 CellLock<GridReadGuard> cell_lock(cell, pair); 1131 cell_lock->Visit(cell_lock, visitor, *(m_creature->GetMap())); 1132 1133 if(target) 1134 DoCast(target, SPELL_AGONIZING_FLAMES); 1135 else 1136 DoCast(m_creature->getVictim(), SPELL_AGONIZING_FLAMES); 1137 } 1138 1139 void Talk(uint32 count) 1140 { 1141 if(!m_creature->isAlive()) return; 1142 uint32 sound = Conversation[count].sound; 1143 char* text = NULL; 1144 if(Conversation[count].text) 1145 text = Conversation[count].text; 1146 TalkTimer = Conversation[count].timer; 1147 uint32 emote = Conversation[count].emote; 1148 IsTalking = Conversation[count].Talk; 1149 Creature* creature = NULL; 1150 uint64 GUID = 0; 1151 if(Conversation[count].creature == ILLIDAN_STORMRAGE) 1152 creature = m_creature; 1153 else if(Conversation[count].creature == AKAMA) 1154 { 1155 if(!AkamaGUID) 1156 { 1157 if(pInstance) 1158 { 1159 AkamaGUID = pInstance->GetData64(DATA_AKAMA); 1160 if(!AkamaGUID) 1161 return; 1162 GUID = AkamaGUID; 1163 } 1164 } 1165 else GUID = AkamaGUID; 1166 } 1167 else if(Conversation[count].creature == MAIEV_SHADOWSONG) 1168 { 1169 if(!MaievGUID) 1170 return; 1171 GUID = MaievGUID; 1172 } 1173 else if(Conversation[count].creature == EMPTY) // This is just for special cases without speech/sounds/emotes. 1174 return; 1175 1176 if(GUID) // Now we check if we actually specified a GUID, if so: 1177 // we grab a pointer to that creature 1178 creature = ((Creature*)Unit::GetUnit((*m_creature), GUID)); 1179 1180 if(creature) 1181 { 1182 creature->HandleEmoteCommand(emote); // Make the creature do some animation! 1183 if(text) 1184 creature->Yell(text, LANG_UNIVERSAL, 0); // Have the creature yell out some text 1185 if(sound) 1186 DoPlaySoundToSet(creature, sound); // Play some sound on the creature 1187 } 1188 } 1189 1190 void Move(float X, float Y, float Z, Creature* _Creature) 1191 { 1192 _Creature->GetMotionMaster()->MovePoint(0, X, Y, Z); 1193 } 1194 1195 void HandleDemonTransformAnimation(uint32 count) 1196 { 1197 uint32 unaura = DemonTransformation[count].unaura; 1198 uint32 aura = DemonTransformation[count].aura; 1199 uint32 displayid = DemonTransformation[count].displayid; 1200 AnimationTimer = DemonTransformation[count].timer; 1201 uint32 size = DemonTransformation[count].size; 1202 1203 m_creature->InterruptNonMeleeSpells(false); 1204 1205 if(DemonTransformation[count].phase != 8) 1206 { 1207 m_creature->GetMotionMaster()->Clear(); 1208 m_creature->GetMotionMaster()->MoveIdle(); 1209 } 1210 1211 if(unaura) 1212 m_creature->RemoveAurasDueToSpell(unaura); 1213 1214 if(aura) 1215 DoCast(m_creature, aura, true); 1216 1217 if(displayid) 1218 // It's morphin time! 1219 m_creature->SetUInt32Value(UNIT_FIELD_DISPLAYID, displayid); 1220 /*if(size) 1221 m_creature->SetUInt32Value(OBJECT_FIELD_SCALE_X, size); // Let us grow! (or shrink)*/ 1222 1223 if(DemonTransformation[count].equip) 1224 { 1225 // Requip warglaives if needed 1226 m_creature->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_DISPLAY, 45479); 1227 m_creature->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_DISPLAY+1, 45481); 1228 } 1229 else 1230 { 1231 // Unequip warglaives if needed 1232 m_creature->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_DISPLAY, 0); 1233 m_creature->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_DISPLAY+1, 0); 1234 } 1235 1236 if(DemonTransformation[count].phase != 8) 1237 Phase = DemonTransformation[count].phase; // Set phase properly 1238 else 1239 { 1240 // Refollow and attack our old victim 1241 m_creature->GetMotionMaster()->MoveChase(m_creature->getVictim()); 1242 if(MaievGUID) Phase = PHASE_NORMAL_MAIEV; // Depending on whether we summoned Maiev, we switch to either phase 5 or 3 1243 else Phase = PHASE_NORMAL_2; 1244 } 1245 1246 if(count == 7) 1247 { 1248 DoResetThreat(); 1249 m_creature->RemoveAurasDueToSpell( SPELL_DEMON_FORM ); 1250 } 1251 else if(count == 4) 1252 { 1253 DoResetThreat(); 1254 if(!m_creature->HasAura(SPELL_DEMON_FORM, 0)) 1255 DoCast(m_creature, SPELL_DEMON_FORM, true); 1256 } 1257 } 1258 1259 /** To reduce the amount of code in UpdateAI, we can seperate them into different functions and simply call them from UpdateAI **/ 1260 void EnterPhase2() 1261 { 1262 DoYell(SAY_TAKEOFF, LANG_UNIVERSAL, NULL); 1263 DoPlaySoundToSet(m_creature, SOUND_TAKEOFF); 1264 1265 SummonBladesTimer = 10000; // Summon Glaives when this decrements 1266 SummonFlamesTimer = 20000; // Summon Flames when this decrements 1267 GlobalTimer += 20000; 1268 LandTimer = 0; 1269 Phase = PHASE_FLIGHT; 1270 m_creature->RemoveAllAuras(); 1271 m_creature->SetUInt64Value(UNIT_FIELD_TARGET, 0); 1272 // So players don't shoot us down 1273 m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); 1274 // Animate our take off! 1275 m_creature->HandleEmoteCommand(EMOTE_ONESHOT_LIFTOFF); 1276 // We now hover! 1277 m_creature->AddUnitMovementFlag(MOVEMENTFLAG_LEVITATING); 1278 m_creature->GetMotionMaster()->MovePoint(0, CENTER_X, CENTER_Y, CENTER_Z); 1279 for(uint8 i = 0; i < 2; ++i) 1280 { 1281 Creature* Glaive = m_creature->SummonCreature(BLADE_OF_AZZINOTH, GlaivePosition[i].x, GlaivePosition[i].y, GlaivePosition[i].z, 0, TEMPSUMMON_CORPSE_DESPAWN, 0); 1282 if(Glaive) 1283 { 1284 GlaiveGUID[i] = Glaive->GetGUID(); // We need this to remove them later on 1285 Glaive->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); 1286 Glaive->SetVisibility(VISIBILITY_OFF); 1287 Glaive->setFaction(m_creature->getFaction()); 1288 } 1289 } 1290 } 1291 1292 void SummonBladesOfAzzinoth() 1293 { 1294 m_creature->GetMotionMaster()->Clear(false); 1295 1296 LandTimer = 0; 1297 RetrieveBladesTimer = 0; 1298 1299 DoCast(m_creature, SPELL_THROW_GLAIVE2); // Make it look like we're throwing the glaives on the ground 1300 // We no longer wear the glaives! 1301 m_creature->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_DISPLAY, 0); 1302 // since they are now channeling the flames (or will be) 1303 m_creature->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_DISPLAY+1, 0); 1304 for(uint8 i = 0; i < 2; ++i) 1305 { 1306 Creature* Glaive = NULL; 1307 Glaive = ((Creature*)Unit::GetUnit((*m_creature), GlaiveGUID[i])); 1308 if(Glaive) 1309 { 1310 DoCast(Glaive, SPELL_THROW_GLAIVE, true); 1311 Glaive->SetVisibility(VISIBILITY_ON); 1312 } 1313 } 1314 } 1315 1316 void SummonFlamesOfAzzinoth() 1317 { 1318 DoYell(SAY_SUMMONFLAMES, LANG_UNIVERSAL, NULL); 1319 DoPlaySoundToSet(m_creature, SOUND_SUMMONFLAMES); 1320 1321 for(uint8 i = 0; i < 2; ++i) 1322 { 1323 Creature* Flame = NULL; 1324 Creature* Glaive = NULL; 1325 Glaive = ((Creature*)Unit::GetUnit((*m_creature), GlaiveGUID[i])); 1326 if(Glaive) 1327 { 1328 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); 1329 if(Flame) 1330 { 1331 // Just in case the database has it as a different faction 1332 Flame->setFaction(m_creature->getFaction()); 1333 // Attack our target! 1334 Flame->AI()->AttackStart(m_creature->getVictim()); 1335 FlameGUID[i] = Flame->GetGUID(); // Record GUID in order to check if they're dead later on to move to the next phase 1336 // Glaives do some random Beam type channel on it. 1337 Glaive->CastSpell(Flame, SPELL_AZZINOTH_CHANNEL, true); 1338 if(m_creature->getVictim()) 1339 Flame->AI()->AttackStart(m_creature->getVictim()); 1658 BlinkToPlayer(); 1659 DoCast(m_creature, SPELL_CAGE_TRAP_SUMMON); 1660 Timer[EVENT_MAIEV_TRAP] = 22000; 1340 1661 } 1341 1662 else 1342 1663 { 1343 DoTextEmote("is unable to summon a Flame of Azzinoth.", NULL); 1344 error_log("SD2 ERROR: Illidan Stormrage AI: Unable to summon Flame of Azzinoth (entry: 22997), please check your database"); 1345 EnterEvadeMode(); 1664 if(!m_creature->IsWithinDistInMap(m_creature->getVictim(), 40)) 1665 m_creature->GetMotionMaster()->MoveChase(m_creature->getVictim(), 30); 1666 DoCast(m_creature->getVictim(), SPELL_THROW_DAGGER); 1667 Timer[EVENT_MAIEV_THROW_DAGGER] = 2000; 1346 1668 } 1347 } 1348 else 1349 { 1350 DoTextEmote("is unable to summon a Blade of Azzinoth.", NULL); 1351 error_log("SD2 ERROR: Illidan Stormrage AI: Unable to summon Blade of Azzinoth (entry: 22996), please check your database"); 1352 } 1353 } 1354 DoResetThreat(); // And now reset our threatlist 1355 HasSummoned = true; 1356 } 1357 1358 void SummonMaiev() 1359 { 1360 TauntTimer += 4000; 1361 GlobalTimer += 4000; 1362 1363 m_creature->InterruptNonMeleeSpells(false); // Interrupt any of our spells 1364 Creature* Maiev = NULL; // Summon Maiev near Illidan 1365 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); 1366 if(Maiev) 1367 { 1368 m_creature->GetMotionMaster()->Clear(false); // Stop moving, it's rude to walk and talk! 1369 m_creature->GetMotionMaster()->MoveIdle(); 1370 // Just in case someone is unaffected by Shadow Prison 1371 m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); 1372 DoCast(m_creature, SPELL_SHADOW_PRISON, true); 1373 TalkCount = 10; 1374 IsTalking = true; // We are now talking/ 1375 Maiev->SetVisibility(VISIBILITY_OFF); // Leave her invisible until she has to talk 1376 Maiev->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); 1377 MaievGUID = Maiev->GetGUID(); 1378 } 1379 else // If Maiev cannot be summoned, reset the encounter and post some errors to the console. 1380 { 1381 EnterEvadeMode(); 1382 DoTextEmote("is unable to summon Maiev Shadowsong and enter Phase 4. Resetting Encounter.", NULL); 1383 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)"); 1384 } 1385 } 1386 1387 void InitializeDeath() 1388 { 1389 m_creature->RemoveAllAuras(); 1390 DoCast(m_creature, SPELL_DEATH); // Animate his kneeling + stun him 1391 // Don't let the players interrupt our talk! 1392 m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); 1393 m_creature->GetMotionMaster()->Clear(false); // No moving! 1394 m_creature->GetMotionMaster()->MoveIdle(); 1395 if(MaievGUID) 1396 { 1397 Creature* Maiev = ((Creature*)Unit::GetUnit((*m_creature), MaievGUID)); 1398 if(Maiev) 1399 { 1400 Maiev->CombatStop(); // Maiev shouldn't do anything either. No point in her attacking us =] 1401 Maiev->GetMotionMaster()->Clear(false); // Stop her from moving as well 1402 Maiev->GetMotionMaster()->MoveIdle(); 1403 float distance = 10.0f; 1404 float dx = m_creature->GetPositionX() + (distance*cos(m_creature->GetOrientation())); 1405 float dy = m_creature->GetPositionY() + (distance*sin(m_creature->GetOrientation())); 1406 Maiev->Relocate(dx,dy,Maiev->GetPositionZ()); 1407 Maiev->SendMonsterMove(dx,dy,Maiev->GetPositionZ(), 0, 0, 0); 1408 Maiev->CastSpell(Maiev, SPELL_TELEPORT_VISUAL, true); 1409 Maiev->SetUInt64Value(UNIT_FIELD_TARGET, m_creature->GetGUID()); 1410 } 1411 } 1412 IsTalking = true; 1413 TalkCount++; 1414 } 1415 1416 void UpdateAI(const uint32 diff) 1417 { 1418 /*** This section will handle the conversations ***/ 1419 if(IsTalking) // Somewhat more efficient using a function rather than a long switch 1420 { 1421 if(TalkTimer < diff) 1422 { 1423 switch(TalkCount) // This is only for specialized cases 1424 { 1425 case 0: 1426 // Time to stand up! 1427 m_creature->RemoveAurasDueToSpell( SPELL_KNEEL ); 1428 break; 1429 case 8: 1430 // Equip our warglaives! 1431 m_creature->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_DISPLAY, 45479); 1432 m_creature->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_DISPLAY+1, 45481); 1433 m_creature->setFaction(14); // Hostile if we weren't before 1434 break; 1435 case 9: 1436 if(AkamaGUID) 1437 { 1438 Creature* Akama = ((Creature*)Unit::GetUnit((*m_creature), AkamaGUID)); 1439 if(Akama) 1440 { 1441 Akama->GetMotionMaster()->Clear(false); 1442 // Akama runs to us! 1443 Akama->GetMotionMaster()->MoveChase(m_creature); 1444 m_creature->GetMotionMaster()->Clear(false); 1445 // We run to Akama! 1446 m_creature->GetMotionMaster()->MoveChase(Akama); 1447 Akama->AddThreat(m_creature, 1000000.0f); 1448 AttackStart(Akama); // Start attacking Akama 1449 ((npc_akama_illidanAI*)Akama->AI())->IsTalking = false; 1450 // Akama starts attacking us 1451 ((npc_akama_illidanAI*)Akama->AI())->AttackStart(m_creature); 1452 } 1453 } 1454 // We are now attackable! 1455 m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); 1456 break; 1457 case 11: 1458 if(MaievGUID) 1459 { 1460 Unit* Maiev = Unit::GetUnit((*m_creature), MaievGUID); 1461 if(Maiev) 1462 { 1463 // Maiev is now visible 1464 Maiev->SetVisibility(VISIBILITY_ON); 1465 // onoz she looks like she teleported! 1466 Maiev->CastSpell(Maiev, SPELL_TELEPORT_VISUAL, true); 1467 // Have her face us 1468 Maiev->SetUInt64Value(UNIT_FIELD_TARGET, m_creature->GetGUID()); 1469 // Face her, so it's not rude =P 1470 m_creature->SetUInt64Value(UNIT_FIELD_TARGET, Maiev->GetGUID()); 1471 } 1472 } 1473 break; 1474 case 14: 1475 if(MaievGUID) 1476 { 1477 Creature* Maiev = ((Creature*)Unit::GetUnit((*m_creature), MaievGUID)); 1478 if(Maiev) 1479 { 1480 Maiev->GetMotionMaster()->Clear(false); 1481 Maiev->GetMotionMaster()->MoveChase(m_creature); 1482 // Have Maiev add a lot of threat on us so that players don't pull her off if they damage her via AOE 1483 Maiev->AddThreat(m_creature, 10000000.0f); 1484 // Force Maiev to attack us. 1485 Maiev->AI()->AttackStart(m_creature); 1486 Maiev->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); 1487 } 1488 } 1489 m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); 1490 m_creature->GetMotionMaster()->MoveChase(m_creature->getVictim()); 1491 IsTalking = false; 1492 FaceVictimTimer = 2000; 1493 RefaceVictim = true; 1494 break; 1495 case 20: // Kill ourself. 1496 if(MaievGUID) 1497 { 1498 Creature* Maiev = ((Creature*)Unit::GetUnit((*m_creature), MaievGUID)); 1499 if(Maiev) // Make Maiev leave 1500 { 1501 Maiev->CastSpell(Maiev, SPELL_TELEPORT_VISUAL, true); 1502 Maiev->setDeathState(JUST_DIED); 1503 } 1504 } 1505 IsTalking = false; 1506 if(m_creature->getVictim()) 1507 m_creature->getVictim()->DealDamage(m_creature, m_creature->GetHealth(), NULL, DIRECT_DAMAGE,SPELL_SCHOOL_MASK_NORMAL, NULL, false); 1508 else 1509 // Now we kill ourself 1510 m_creature->DealDamage(m_creature, m_creature->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); 1511 break; 1512 } 1513 Talk(TalkCount); // This function does most of the talking 1514 TalkCount++; 1515 }else TalkTimer -= diff; 1516 } 1517 1518 // If we don't have a target, return. 1519 if(!m_creature->SelectHostilTarget() || !m_creature->getVictim() || IsTalking) 1520 return; 1521 1522 // If we are 'caged', then we shouldn't do anything such as cast spells or transform into Demon Form. 1523 if(m_creature->HasAura(SPELL_CAGED, 0)) 1524 { 1525 EnrageTimer = 40000; // Just so that he doesn't immediately enrage after he stops being caged. 1526 CageTimer = 30000; 1527 return; 1528 } 1529 1530 // Berserk Timer - flat 25 minutes 1531 if(!m_creature->HasAura(SPELL_BERSERK, 0) && Phase != PHASE_DEMON_SEQUENCE) 1532 if(BerserkTimer < diff) 1533 { 1534 DoYell(SAY_ENRAGE, LANG_UNIVERSAL, NULL); 1535 DoPlaySoundToSet(m_creature, SOUND_ENRAGE); 1536 DoCast(m_creature, SPELL_BERSERK, true); 1537 }else BerserkTimer -= diff; 1538 1539 if(RefaceVictim) 1540 if(FaceVictimTimer < diff) 1541 { 1542 m_creature->SetUInt64Value(UNIT_FIELD_TARGET, m_creature->getVictim()->GetGUID()); 1543 FaceVictimTimer = 1000; 1544 RefaceVictim = false; 1545 }else FaceVictimTimer -= diff; 1546 1547 /** Signal to change to phase 2 **/ 1548 if(((m_creature->GetHealth()*100 / m_creature->GetMaxHealth()) < 65) && (Phase == PHASE_NORMAL)) 1549 EnterPhase2(); 1550 1551 /** Signal to summon Maiev **/ 1552 if(((m_creature->GetHealth()*100 / m_creature->GetMaxHealth()) < 30) && !MaievGUID && 1553 ((Phase != PHASE_DEMON) || (Phase != PHASE_DEMON_SEQUENCE))) 1554 SummonMaiev(); 1555 1556 /** Time for the death speech **/ 1557 if((m_creature->GetHealth()*100 / m_creature->GetMaxHealth() < 1) && (!IsTalking) && 1558 ((Phase != PHASE_DEMON) || (Phase != PHASE_DEMON_SEQUENCE))) 1559 InitializeDeath(); 1560 1561 /***** Spells for Phase 1, 3 and 5 (Normal Form) ******/ 1562 if(Phase == PHASE_NORMAL || Phase == PHASE_NORMAL_2 || Phase == PHASE_NORMAL_MAIEV) 1563 { 1564 if(TauntTimer < diff) // His random taunt/yell timer. 1565 { 1566 uint32 random = rand()%4; 1567 char* yell = RandomTaunts[random].text; 1568 uint32 soundid = RandomTaunts[random].sound; 1569 if(yell) 1570 DoYell(yell, LANG_UNIVERSAL, NULL); 1571 if(soundid) 1572 DoPlaySoundToSet(m_creature, soundid); 1573 TauntTimer = 32000; 1574 }else TauntTimer -= diff; 1575 1576 if(GlobalTimer < diff) // Global Timer so that spells do not overlap. 1577 { 1578 if(ShearTimer < diff) 1579 { 1580 DoCast(m_creature->getVictim(), SPELL_SHEAR); 1581 ShearTimer = 25000 + (rand()%16 * 1000); 1582 GlobalTimer += 2000; 1583 }else ShearTimer -= diff; 1584 1585 if(FlameCrashTimer < diff) 1586 { 1587 // It spawns multiple flames sometimes. Therefore, we'll do this manually. 1588 //DoCast(m_creature->getVictim(), SPELL_FLAME_CRASH); 1589 DoSpawnCreature(FLAME_CRASH, 0, 0, 0, 0, TEMPSUMMON_TIMED_DESPAWN, 40000); 1590 FlameCrashTimer = 35000; 1591 GlobalTimer += 2000; 1592 }else FlameCrashTimer -= diff; 1593 1594 if(ParasiticShadowFiendTimer < diff) 1595 { 1596 Unit* target = NULL; 1597 target = SelectUnit(SELECT_TARGET_RANDOM,1); 1598 if(target && target->isAlive() && !target->HasAura(SPELL_PARASITIC_SHADOWFIEND, 0)) 1599 { 1600 Cast(target, SPELL_PARASITIC_SHADOWFIEND); 1601 ParasiticShadowFiendTimer = 40000; 1602 } 1603 }else ParasiticShadowFiendTimer -= diff; 1604 1605 if(DrawSoulTimer < diff) 1606 { 1607 DoCast(m_creature->getVictim(), SPELL_DRAW_SOUL); 1608 DrawSoulTimer = 55000; 1609 GlobalTimer += 3000; 1610 }else DrawSoulTimer -= diff; 1611 }else GlobalTimer -= diff; 1612 1613 if(!IsTalking) 1669 break; 1670 default: 1671 break; 1672 } 1673 1674 if(m_creature->GetHealth()*100 / m_creature->GetMaxHealth() < 50) 1675 { 1676 m_creature->SetVisibility(VISIBILITY_OFF); 1677 m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); 1678 if(GETCRE(Illidan, IllidanGUID)) 1679 ((boss_illidan_stormrageAI*)Illidan->AI())->DeleteFromThreatList(m_creature->GetGUID()); 1680 m_creature->AttackStop(); 1681 Timer[EVENT_MAIEV_STEALTH] = 60000; //reappear after 1 minute 1682 MaxTimer = 1; 1683 } 1684 1685 if(Phase == PHASE_NORMAL_MAIEV) 1614 1686 DoMeleeAttackIfReady(); 1615 } 1616 1617 /*** Phase 2 ***/ 1618 if(Phase == PHASE_FLIGHT) 1619 { 1620 // Check if we have summoned or not. 1621 if(!HasSummoned) 1622 { 1623 if(SummonBladesTimer) 1624 if(SummonBladesTimer <= diff) 1625 { 1626 SummonBladesOfAzzinoth(); 1627 SummonBladesTimer = 0; 1628 }else SummonBladesTimer -= diff; 1629 1630 if(SummonFlamesTimer < diff) 1631 { 1632 SummonFlamesOfAzzinoth(); 1633 }else SummonFlamesTimer -= diff; 1634 } 1635 1636 if(!m_creature->GetMotionMaster()->empty() && (m_creature->GetMotionMaster()->GetCurrentMovementGeneratorType() != POINT_MOTION_TYPE)) 1637 m_creature->GetMotionMaster()->Clear(false); 1638 1639 if(HasSummoned) 1640 { 1641 if(CheckFlamesTimer) 1642 if(CheckFlamesTimer <= diff) 1643 { 1644 // Check if flames are dead or non-existant. If so, set GUID to 0. 1645 for(uint8 i = 0; i < 2; i++) 1646 { 1647 if(FlameGUID[i]) 1648 { 1649 Unit* Flame = NULL; 1650 Flame = Unit::GetUnit((*m_creature), FlameGUID[i]); 1651 1652 // If the flame dies, or somehow the pointer becomes invalid, reset GUID to 0. 1653 if(!Flame || !Flame->isAlive()) 1654 FlameGUID[i] = 0; 1655 } 1656 } 1657 CheckFlamesTimer = 500; 1658 }else CheckFlamesTimer -= diff; 1659 1660 // If both flames are dead/non-existant, kill glaives and change to phase 3. 1661 if(!FlameGUID[0] && !FlameGUID[1] && CheckFlamesTimer) 1662 { 1663 RetrieveBladesTimer = 5000; // Prepare for re-equipin! 1664 CheckFlamesTimer = 0; 1665 } 1666 1667 if(RetrieveBladesTimer) 1668 if(RetrieveBladesTimer <= diff) // Time to get back our glaives! 1669 { 1670 // Interrupt any spells we might be doing *cough* DArk Barrage *cough* 1671 m_creature->InterruptNonMeleeSpells(false); 1672 for(uint8 i = 0; i < 2; i++) 1673 { 1674 if(GlaiveGUID[i]) 1675 { 1676 Unit* Glaive = NULL; 1677 Glaive = Unit::GetUnit((*m_creature), GlaiveGUID[i]); 1678 if(Glaive) 1679 { 1680 // Make it look like the Glaive flies back up to us 1681 Glaive->CastSpell(m_creature, SPELL_GLAIVE_RETURNS, true); 1682 // Despawn the Glaive 1683 Glaive->setDeathState(JUST_DIED); 1684 } 1685 GlaiveGUID[i] = 0; 1686 } 1687 } 1688 // Re-equip our warblades! 1689 m_creature->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_DISPLAY, 45479); 1690 m_creature->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_DISPLAY+1, 45481); 1691 LandTimer = 5000; // Prepare for landin'! 1692 RetrieveBladesTimer = 0; 1693 }else RetrieveBladesTimer -= diff; 1694 1695 if(LandTimer) 1696 { 1697 if(LandTimer <= diff) // Time to land! 1698 { 1699 DoResetThreat(); 1700 // anndddd touchdown! 1701 m_creature->HandleEmoteCommand(EMOTE_ONESHOT_LAND); 1702 m_creature->RemoveUnitMovementFlag(MOVEMENTFLAG_ONTRANSPORT + MOVEMENTFLAG_LEVITATING); 1703 Phase = PHASE_NORMAL_2; 1704 // We should let the raid fight us =) 1705 m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); 1706 m_creature->SetUInt64Value(UNIT_FIELD_TARGET, m_creature->getVictim()->GetGUID()); 1707 // Chase our victim! 1708 m_creature->GetMotionMaster()->MoveChase(m_creature->getVictim()); 1709 }else LandTimer -= diff; 1710 return; // Do not continue past this point if LandTimer is not 0 and we are in phase 2. 1711 } 1712 } 1713 1714 if(GlobalTimer < diff) 1715 { 1716 if(FireballTimer < diff) 1717 { 1718 Cast(SelectUnit(SELECT_TARGET_RANDOM, 0), SPELL_FIREBALL); 1719 FireballTimer = 5000; 1720 }else FireballTimer -= diff; 1721 1722 if(DarkBarrageTimer < diff) 1723 { 1724 m_creature->InterruptNonMeleeSpells(false); 1725 DoCast(SelectUnit(SELECT_TARGET_RANDOM, 0), SPELL_DARK_BARRAGE); 1726 DarkBarrageTimer = 35000; 1727 GlobalTimer += 9000; 1728 }else DarkBarrageTimer -= diff; 1729 1730 if(EyeBlastTimer < diff) 1731 { 1732 CastEyeBlast(); 1733 EyeBlastTimer = 30000; 1734 }else EyeBlastTimer -= diff; 1735 }else GlobalTimer -= diff; 1736 } 1737 1738 /** Phase 3,5 spells only**/ 1739 if(Phase == PHASE_NORMAL_2 || Phase == PHASE_NORMAL_MAIEV) 1740 { 1741 if(GlobalTimer < diff) 1742 { 1743 if(AgonizingFlamesTimer < diff) 1744 { 1745 CastAgonizingFlames(); 1746 AgonizingFlamesTimer = 60000; 1747 }else AgonizingFlamesTimer -= diff; 1748 }else GlobalTimer -= diff; 1749 1750 if(TransformTimer < diff) 1751 { 1752 uint32 CurHealth = m_creature->GetHealth()*100 / m_creature->GetMaxHealth(); 1753 // Prevent Illidan from morphing if less than 32% or 5%, as this may cause issues with the phase transition or death speech 1754 if((CurHealth < 32 && !MaievGUID) || (CurHealth < 5)) 1755 return; 1756 1757 Phase = PHASE_DEMON_SEQUENCE; // Transform sequence 1758 DemonFormSequence = 0; 1759 AnimationTimer = 0; 1760 DoYell(SAY_MORPH, LANG_UNIVERSAL, NULL); 1761 DoPlaySoundToSet(m_creature, SOUND_MORPH); 1762 TransformTimer = 60000; 1763 FlameBurstTimer = 10000; 1764 ShadowDemonTimer = 30000; 1765 m_creature->GetMotionMaster()->Clear(false);// Stop moving 1766 }else TransformTimer -= diff; 1767 } 1768 1769 /** Phase 4 spells only (Demon Form) **/ 1770 if(Phase == PHASE_DEMON) 1771 { 1772 // Stop moving if we are by clearing movement generators. 1773 if(!m_creature->GetMotionMaster()->empty()) 1774 m_creature->GetMotionMaster()->Clear(false); 1775 1776 if(TransformTimer < diff) 1777 { 1778 Phase = PHASE_DEMON_SEQUENCE; 1779 DemonFormSequence = 5; 1780 AnimationTimer = 100; 1781 TransformTimer = 60000; 1782 }else TransformTimer -= diff; 1783 1784 if(ShadowDemonTimer < diff) 1785 { 1786 m_creature->InterruptNonMeleeSpells(false); 1787 Creature* ShadowDemon = NULL; 1788 for(uint8 i = 0; i < 4; i++) 1789 { 1790 Unit* target = NULL; 1791 target = SelectUnit(SELECT_TARGET_RANDOM,0); 1792 // only on players. 1793 if(target && target->GetTypeId() == TYPEID_PLAYER) 1794 { 1795 ShadowDemon = DoSpawnCreature(SHADOW_DEMON, 0,0,0,0,TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN,25000); 1796 if(ShadowDemon) 1797 { 1798 ShadowDemon->AddThreat(target, 5000000.0f); 1799 ShadowDemon->AI()->AttackStart(target); 1800 DoZoneInCombat(ShadowDemon); 1801 } 1802 } 1803 } 1804 ShadowDemonTimer = 60000; 1805 }else ShadowDemonTimer -= diff; 1806 1807 if(GlobalTimer < diff) 1808 { 1809 if(ShadowBlastTimer < diff) 1810 { 1811 Unit* target = SelectUnit(SELECT_TARGET_TOPAGGRO, 0); 1812 if(target && target->isAlive()) 1813 { 1814 m_creature->SetUInt64Value(UNIT_FIELD_TARGET, target->GetGUID()); 1815 DoCast(target, SPELL_SHADOW_BLAST); 1816 ShadowBlastTimer = 4000; 1817 GlobalTimer += 1500; 1818 } 1819 if(!m_creature->HasAura(SPELL_DEMON_FORM, 0)) 1820 DoCast(m_creature, SPELL_DEMON_FORM, true); 1821 }else ShadowBlastTimer -= diff; 1822 1823 if(FlameBurstTimer < diff) 1824 { 1825 DoCast(m_creature, SPELL_FLAME_BURST); 1826 FlameBurstTimer = 15000; 1827 }else FlameBurstTimer -= diff; 1828 }else GlobalTimer -= diff; 1829 } 1830 1831 /** Phase 5 timers. Enrage spell **/ 1832 if(Phase == PHASE_NORMAL_MAIEV) 1833 { 1834 if(EnrageTimer < diff) 1835 { 1836 DoCast(m_creature, SPELL_ENRAGE); 1837 EnrageTimer = 40000; 1838 CageTimer = 30000; 1839 TransformTimer += 10000; 1840 }else EnrageTimer -= diff; 1841 1842 // We'll handle Cage Trap in Illidan's script for simplicity's sake 1843 if(CageTimer < diff) 1844 { 1845 if(MaievGUID) 1846 { 1847 Unit* Maiev = Unit::GetUnit((*m_creature), MaievGUID); 1848 Unit* target = SelectUnit(SELECT_TARGET_RANDOM, 0); 1849 if(!Maiev || !target || (target->GetTypeId() != TYPEID_PLAYER)) 1850 return; 1851 float X, Y, Z; 1852 target->GetPosition(X, Y, Z); 1853 Maiev->Relocate(X, Y, Z, Maiev->GetOrientation()); 1854 // Make it look like she 'teleported' 1855 Maiev->CastSpell(Maiev, SPELL_TELEPORT_VISUAL, true); 1856 // summon the trap! 1857 Maiev->CastSpell(Maiev, SPELL_CAGE_TRAP_SUMMON, false); 1858 } 1859 CageTimer = 15000; 1860 }else CageTimer -= diff; 1861 } 1862 1863 if(Phase == PHASE_DEMON_SEQUENCE) // Demonic Transformation 1864 { 1865 if(AnimationTimer < diff) 1866 { 1867 HandleDemonTransformAnimation(DemonFormSequence); 1868 DemonFormSequence++; 1869 }else AnimationTimer -= diff; 1870 } 1871 } 1872 }; 1873 1874 /*********************** End of Illidan AI ******************************************/ 1875 1876 void npc_akama_illidanAI::BeginEvent(uint64 PlayerGUID) 1877 { 1878 debug_log("SD2: Akama - Illidan Introduction started. Illidan event properly begun."); 1879 if(pInstance) 1880 { 1881 IllidanGUID = pInstance->GetData64(DATA_ILLIDANSTORMRAGE); 1882 pInstance->SetData(DATA_ILLIDANSTORMRAGEEVENT, IN_PROGRESS); 1883 } 1884 1885 if(pInstance) 1886 for(uint8 i = DATA_GAMEOBJECT_ILLIDAN_DOOR_R; i < DATA_GAMEOBJECT_ILLIDAN_DOOR_L+1; ++i) 1887 { 1888 GameObject* Door = GameObject::GetGameObject((*m_creature), pInstance->GetData64(i)); 1889 if(Door) 1890 Door->SetGoState(1); 1891 } 1892 1893 if(IllidanGUID) 1894 { 1895 m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); 1896 Creature* Illidan = ((Creature*)Unit::GetUnit((*m_creature), IllidanGUID)); 1897 if(Illidan) 1898 { 1899 Illidan->RemoveAurasDueToSpell(SPELL_KNEEL); // Time for Illidan to stand up. 1900 // First line of Akama-Illidan convo 1901 ((boss_illidan_stormrageAI*)Illidan->AI())->TalkCount = 0; 1902 // Begin Talking 1903 ((boss_illidan_stormrageAI*)Illidan->AI())->IsTalking = true; 1904 ((boss_illidan_stormrageAI*)Illidan->AI())->AkamaGUID = m_creature->GetGUID(); 1905 m_creature->SetUInt64Value(UNIT_FIELD_TARGET, Illidan->GetGUID()); 1906 Illidan->SetUInt64Value(UNIT_FIELD_TARGET, m_creature->GetGUID()); 1907 IsTalking = true; // Prevent Akama from starting to attack him 1908 // Prevent players from talking again 1909 m_creature->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); 1910 m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); 1911 Illidan->GetMotionMaster()->Clear(false); 1912 Illidan->GetMotionMaster()->MoveIdle(); 1913 m_creature->GetMotionMaster()->Clear(false); 1914 m_creature->GetMotionMaster()->MoveIdle(); 1915 1916 if(PlayerGUID) 1917 { 1918 Unit* player = Unit::GetUnit((*m_creature), PlayerGUID); 1919 if(player) 1920 Illidan->AddThreat(player, 100.0f); 1921 } 1922 } 1923 } 1924 } 1687 } 1688 }; 1689 1925 1690 1926 1691 bool GossipSelect_npc_akama_at_illidan(Player *player, Creature *_Creature, uint32 sender, uint32 action) 1927 1692 { 1928 if(action == GOSSIP_ACTION_INFO_DEF) // Time to begin the event1693 if(action == GOSSIP_ACTION_INFO_DEF) // Time to begin the Event 1929 1694 { 1930 1695 player->CLOSE_GOSSIP_MENU(); 1931 ((npc_akama_illidanAI*)_Creature->AI())-> BeginDoorEvent(player);1696 ((npc_akama_illidanAI*)_Creature->AI())->EnterPhase(PHASE_CHANNEL); 1932 1697 } 1933 1698 return true; … … 1942 1707 } 1943 1708 1944 struct TRINITY_DLL_SPEC boss_maievAI : public ScriptedAI 1945 { 1946 boss_maievAI(Creature *c) : ScriptedAI(c) 1947 { 1948 pInstance = ((ScriptedInstance*)c->GetInstanceData()); 1949 Reset(); 1950 }; 1951 1952 uint32 TauntTimer; 1709 struct TRINITY_DLL_DECL cage_trap_triggerAI : public ScriptedAI 1710 { 1711 cage_trap_triggerAI(Creature *c) : ScriptedAI(c) {Reset();} 1712 1953 1713 uint64 IllidanGUID; 1954 1955 ScriptedInstance* pInstance;1956 1957 void Reset()1958 {1959 TauntTimer = 12000;1960 IllidanGUID = 0;1961 }1962 1963 void Aggro(Unit *who) {}1964 1965 void UpdateAI(const uint32 diff)1966 {1967 if(!IllidanGUID)1968 {1969 if(pInstance)1970 IllidanGUID = pInstance->GetData64(DATA_ILLIDANSTORMRAGE);1971 }else1972 {1973 Creature* Illidan = NULL;1974 Illidan = ((Creature*)Unit::GetUnit((*m_creature), IllidanGUID));1975 if(!Illidan || !Illidan->isAlive() || Illidan->IsInEvadeMode())1976 {1977 m_creature->SetVisibility(VISIBILITY_OFF);1978 m_creature->DealDamage(m_creature, m_creature->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false);1979 }1980 else if(Illidan && ((Illidan->GetHealth()*100 / Illidan->GetMaxHealth()) < 2))1981 return;1982 }1983 1984 // Return if we don't have a target1985 if(!m_creature->SelectHostilTarget() || !m_creature->getVictim())1986 return;1987 1988 if(TauntTimer < diff)1989 {1990 uint32 random = rand()%4;1991 char* text = MaievTaunts[random].text;1992 uint32 sound = MaievTaunts[random].sound;1993 DoYell(text, LANG_UNIVERSAL, NULL);1994 DoPlaySoundToSet(m_creature, sound);1995 TauntTimer = 22000 + rand()%21 * 1000;1996 }else TauntTimer -= diff;1997 1998 DoMeleeAttackIfReady();1999 }2000 };2001 2002 struct TRINITY_DLL_DECL cage_trap_triggerAI : public ScriptedAI2003 {2004 cage_trap_triggerAI(Creature *c) : ScriptedAI(c) {Reset();}2005 2006 uint64 IllidanGUID;2007 uint64 CageTrapGUID;2008 2009 1714 uint32 DespawnTimer; 2010 1715 … … 2015 1720 { 2016 1721 IllidanGUID = 0; 2017 CageTrapGUID = 0;2018 1722 2019 1723 Active = false; … … 2034 1738 if(who && (who->GetTypeId() != TYPEID_PLAYER)) 2035 1739 { 2036 if(who->GetEntry() == ILLIDAN_STORMRAGE) 2037 { 2038 if(!IllidanGUID && m_creature->IsWithinDistInMap(who, 3) && !who->HasAura(SPELL_CAGED, 0))1740 if(who->GetEntry() == ILLIDAN_STORMRAGE) // Check if who is Illidan 1741 { 1742 if(!IllidanGUID && m_creature->IsWithinDistInMap(who, 3) && (!who->HasAura(SPELL_CAGED, 0))) 2039 1743 { 2040 1744 IllidanGUID = who->GetGUID(); … … 2042 1746 DespawnTimer = 5000; 2043 1747 if(who->HasAura(SPELL_ENRAGE, 0)) 2044 // Dispel his enrage 2045 who->RemoveAurasDueToSpell(SPELL_ENRAGE); 2046 2047 if(GameObject* CageTrap = GameObject::GetGameObject(*m_creature, CageTrapGUID)) 2048 CageTrap->SetLootState(GO_JUST_DEACTIVATED); 1748 who->RemoveAurasDueToSpell(SPELL_ENRAGE); // Dispel his enrage 1749 //if(GameObject* CageTrap = GameObject::GetGameObject(*m_creature, CageTrapGUID)) 1750 // CageTrap->SetLootState(GO_JUST_DEACTIVATED); 2049 1751 } 2050 1752 } … … 2057 1759 if(DespawnTimer < diff) 2058 1760 m_creature->DealDamage(m_creature, m_creature->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); 2059 else DespawnTimer -= diff;2060 2061 //if(IllidanGUID && !SummonedBeams)2062 //{2063 // if(Unit* Illidan = Unit::GetUnit(*m_creature, IllidanGUID)2064 // {2065 // //TODO: Find proper spells and properly apply 'caged' Illidan effect2066 // }2067 //}1761 else DespawnTimer -= diff; 1762 1763 //if(IllidanGUID && !SummonedBeams) 1764 //{ 1765 // if(Unit* Illidan = Unit::GetUnit(*m_creature, IllidanGUID) 1766 // { 1767 // //TODO: Find proper spells and properly apply 'caged' Illidan effect 1768 // } 1769 //} 2068 1770 } 2069 1771 }; … … 2090 1792 cell_lock->Visit(cell_lock, cSearcher, *(plr->GetMap())); 2091 1793 2092 if(!trigger)2093 {2094 plr->GetSession()->SendNotification("SD2: Summon failed. This trap is now useless.", LANG_UNIVERSAL, 0);2095 error_log("SD2: Cage Trap- Unable to find trigger. This Cage Trap is now useless");2096 return false;2097 }2098 2099 1794 ((cage_trap_triggerAI*)trigger->AI())->Active = true; 2100 go->Set GoState(0);1795 go->SetUInt32Value(GAMEOBJECT_STATE, 0); 2101 1796 return true; 2102 1797 } 2103 1798 2104 //This is used to sort the players by distance in preparation for being charged by the flames. 2105 struct TargetDistanceOrder : public std::binary_function<const Unit, const Unit, bool> 2106 { 2107 const Unit* MainTarget; 2108 TargetDistanceOrder(const Unit* Target) : MainTarget(Target) {}; 2109 // functor for operator ">" 2110 bool operator()(const Unit* _Left, const Unit* _Right) const 2111 { 2112 return (MainTarget->GetDistance(_Left) > MainTarget->GetDistance(_Right)); 2113 } 2114 }; 2115 2116 struct TRINITY_DLL_DECL flame_of_azzinothAI : public ScriptedAI 2117 { 2118 flame_of_azzinothAI(Creature *c) : ScriptedAI(c) {Reset();} 2119 2120 uint32 FlameBlastTimer; 2121 uint32 SummonBlazeTimer; 2122 uint32 ChargeTimer; 1799 struct TRINITY_DLL_DECL shadow_demonAI : public ScriptedAI 1800 { 1801 shadow_demonAI(Creature *c) : ScriptedAI(c) {Reset();} 1802 1803 uint64 TargetGUID; 1804 1805 void Aggro(Unit *who) {} 2123 1806 2124 1807 void Reset() 2125 1808 { 2126 FlameBlastTimer = 15000 + rand()%15000; 2127 SummonBlazeTimer = 10000 + rand()%20000; 2128 ChargeTimer = 5000; 2129 } 2130 2131 void Aggro(Unit *who) {} 2132 2133 void Charge() 2134 { 2135 // Get the Threat List 2136 std::list<HostilReference*>& m_threatlist = m_creature->getThreatManager().getThreatList(); 2137 2138 if(!m_threatlist.size()) return; // He doesn't have anyone in his threatlist, useless to continue 2139 2140 std::list<Unit*> targets; 2141 std::list<HostilReference *>::iterator itr = m_threatlist.begin(); 2142 for( ; itr!= m_threatlist.end(); ++itr) //store the threat list in a different container 2143 { 2144 Unit *target = Unit::GetUnit(*m_creature, (*itr)->getUnitGuid()); 2145 //only on alive players 2146 if(target && target->isAlive() && target->GetTypeId() == TYPEID_PLAYER ) 2147 targets.push_back( target); 2148 } 2149 2150 //Sort the list of players 2151 targets.sort(TargetDistanceOrder(m_creature)); 2152 //Resize so we only get the furthest target 2153 targets.resize(1); 2154 2155 Unit* target = (*targets.begin()); 2156 if(target && (!m_creature->IsWithinDistInMap(target, 40))) 2157 { 2158 DoCast(m_creature, SPELL_ENRAGE, true); 2159 DoCast(target, SPELL_CHARGE); 2160 } 1809 TargetGUID = 0; 1810 DoCast(m_creature, SPELL_SHADOW_DEMON_PASSIVE, true); 1811 } 1812 1813 void JustDied(Unit *killer) 1814 { 1815 Unit* target = Unit::GetUnit((*m_creature), TargetGUID); 1816 if(target) 1817 target->RemoveAurasDueToSpell(SPELL_PARALYZE); 2161 1818 } 2162 1819 2163 1820 void UpdateAI(const uint32 diff) 2164 1821 { 2165 // Return if we don't have a target2166 if(!m_creature->SelectHostilTarget() || !m_creature->getVictim())2167 return;2168 2169 if(FlameBlastTimer < diff)2170 {2171 DoCast(m_creature->getVictim(), SPELL_FLAME_BLAST);2172 FlameBlastTimer = 30000;2173 }else FlameBlastTimer -= diff;2174 2175 if(SummonBlazeTimer < diff)2176 {2177 DoCast(m_creature, SPELL_BLAZE_SUMMON);2178 SummonBlazeTimer = 30000 + rand()%20000;2179 }else SummonBlazeTimer -= diff;2180 2181 if(ChargeTimer < diff)2182 {2183 Charge();2184 ChargeTimer = 5000;2185 }else ChargeTimer -= diff;2186 2187 DoMeleeAttackIfReady();2188 }2189 };2190 2191 struct TRINITY_DLL_DECL shadow_demonAI : public ScriptedAI2192 {2193 shadow_demonAI(Creature *c) : ScriptedAI(c) {Reset();}2194 2195 uint64 TargetGUID;2196 2197 void Reset() { TargetGUID = 0; }2198 2199 void Aggro(Unit *who) {}2200 2201 void JustDied(Unit *killer)2202 {2203 if(TargetGUID)2204 {2205 Unit* target = Unit::GetUnit((*m_creature), TargetGUID);2206 if(target)2207 target->RemoveAurasDueToSpell(SPELL_PARALYZE);2208 }2209 }2210 2211 void UpdateAI(const uint32 diff)2212 {2213 1822 if(!m_creature->SelectHostilTarget() || !m_creature->getVictim()) return; 2214 1823 2215 // Only cast the below on players. 2216 if(m_creature->getVictim()->GetTypeId() != TYPEID_PLAYER) return; 1824 if(m_creature->getVictim()->GetTypeId() != TYPEID_PLAYER) return; // Only cast the below on players. 2217 1825 2218 1826 if(!m_creature->getVictim()->HasAura(SPELL_PARALYZE, 0)) … … 2220 1828 TargetGUID = m_creature->getVictim()->GetGUID(); 2221 1829 m_creature->AddThreat(m_creature->getVictim(), 10000000.0f); 2222 DoCast(m_creature, SPELL_SHADOW_DEMON_PASSIVE, true);2223 1830 DoCast(m_creature->getVictim(), SPELL_PURPLE_BEAM, true); 2224 1831 DoCast(m_creature->getVictim(), SPELL_PARALYZE, true); … … 2230 1837 }; 2231 1838 2232 struct TRINITY_DLL_DECL flamecrashAI : public ScriptedAI 2233 { 2234 flamecrashAI(Creature *c) : ScriptedAI(c) {Reset();} 2235 2236 uint32 FlameCrashTimer; 1839 // Shadowfiends interact with Illidan, setting more targets in Illidan's hashmap 1840 struct TRINITY_DLL_DECL mob_parasitic_shadowfiendAI : public ScriptedAI 1841 { 1842 mob_parasitic_shadowfiendAI(Creature* c) : ScriptedAI(c) 1843 { 1844 pInstance = ((ScriptedInstance*)c->GetInstanceData()); 1845 Reset(); 1846 } 1847 1848 ScriptedInstance* pInstance; 1849 uint64 IllidanGUID; 1850 uint32 CheckTimer; 1851 1852 void Reset() 1853 { 1854 if(pInstance) 1855 IllidanGUID = pInstance->GetData64(DATA_ILLIDANSTORMRAGE); 1856 else 1857 IllidanGUID = 0; 1858 1859 CheckTimer = 5000; 1860 DoCast(m_creature, SPELL_SHADOWFIEND_PASSIVE, true); 1861 } 1862 1863 void Aggro(Unit* who) {} 1864 void MoveInLineOfSight(Unit *who){} 1865 1866 void DoMeleeAttackIfReady() 1867 { 1868 if( m_creature->isAttackReady() && m_creature->IsWithinDistInMap(m_creature->getVictim(), ATTACK_DISTANCE)) 1869 { 1870 if(!m_creature->getVictim()->HasAura(SPELL_PARASITIC_SHADOWFIEND, 0)) 1871 { 1872 m_creature->getVictim()->CastSpell(m_creature->getVictim(), SPELL_PARASITIC_SHADOWFIEND, true); //do not stack 1873 if(GETCRE(Illidan, IllidanGUID)) 1874 ((boss_illidan_stormrageAI*)Illidan->AI())->AddParasiteTarget(m_creature->getVictim()->GetGUID()); 1875 } 1876 m_creature->AttackerStateUpdate(m_creature->getVictim()); 1877 m_creature->resetAttackTimer(); 1878 } 1879 } 1880 1881 void UpdateAI(const uint32 diff) 1882 { 1883 if(!m_creature->getVictim()) 1884 { 1885 if(GETCRE(Illidan, IllidanGUID)) 1886 { 1887 if(Illidan->getVictim() && !Illidan->getVictim()->HasAura(SPELL_PARASITIC_SHADOWFIEND, 0)) 1888 AttackStart(Illidan->getVictim()); 1889 else 1890 AttackStart(((boss_illidan_stormrageAI*)Illidan->AI())->SelectUnit(SELECT_TARGET_RANDOM, 1)); 1891 } 1892 } 1893 else 1894 DoMeleeAttackIfReady(); 1895 1896 if(CheckTimer < diff) 1897 { 1898 GETUNIT(Illidan, IllidanGUID); 1899 if(!Illidan || ((Creature*)Illidan)->IsInEvadeMode()) 1900 { 1901 m_creature->SetVisibility(VISIBILITY_OFF); 1902 m_creature->setDeathState(JUST_DIED); 1903 return; 1904 }else CheckTimer = 5000; 1905 }else CheckTimer -= diff; 1906 } 1907 }; 1908 1909 struct TRINITY_DLL_DECL demonfireAI : public ScriptedAI 1910 { 1911 demonfireAI(Creature *c) : ScriptedAI(c) 1912 { 1913 pInstance = ((ScriptedInstance*)c->GetInstanceData()); 1914 Reset(); 1915 } 1916 1917 ScriptedInstance* pInstance; 1918 uint64 IllidanGUID; 1919 bool IsTrigger; 1920 bool DemonFire; 1921 uint32 CheckTimer; 2237 1922 uint32 DespawnTimer; 2238 1923 2239 1924 void Reset() 2240 1925 { 2241 FlameCrashTimer = 3000 +rand()%5000; 2242 DespawnTimer = 60000; 2243 } 2244 2245 void Aggro(Unit *who){ return; } 2246 2247 void AttackStart(Unit *who) { } 2248 2249 void MoveInLineOfSight(Unit *who){ } 1926 if(pInstance) 1927 IllidanGUID = pInstance->GetData64(DATA_ILLIDANSTORMRAGE); 1928 else 1929 IllidanGUID = 0; 1930 1931 IsTrigger = false; 1932 DemonFire = false; 1933 1934 CheckTimer = 5000; 1935 DespawnTimer = 78000; //spell duration, core bug, cannot despawn self 1936 } 1937 1938 void Aggro(Unit *who) {} 1939 void AttackStart(Unit* who) {} 1940 void MoveInLineOfSight(Unit *who){} 2250 1941 2251 1942 void UpdateAI(const uint32 diff) 2252 1943 { 2253 if(FlameCrashTimer < diff) 2254 { 2255 DoCast(m_creature, SPELL_FLAME_CRASH_EFFECT); 2256 FlameCrashTimer = 15000; 2257 }else FlameCrashTimer -= diff; 1944 if(IsTrigger) 1945 return; 1946 1947 if(!DemonFire) 1948 DoCast(m_creature, SPELL_DEMON_FIRE); //duration 60s 1949 1950 if(CheckTimer < diff) 1951 { 1952 GETUNIT(Illidan, IllidanGUID); 1953 if(!Illidan || !Illidan->HasUnitMovementFlag(MOVEMENTFLAG_LEVITATING)) 1954 { 1955 m_creature->SetVisibility(VISIBILITY_OFF); 1956 m_creature->setDeathState(JUST_DIED); 1957 return; 1958 }else CheckTimer = 5000; 1959 }else CheckTimer -= diff; 2258 1960 2259 1961 if(DespawnTimer < diff) 2260 1962 { 2261 m_creature->SetVisibility(VISIBILITY_OFF); // So that players don't see the sparkly effect when we die.2262 m_creature-> DealDamage(m_creature, m_creature->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false);1963 m_creature->SetVisibility(VISIBILITY_OFF); 1964 m_creature->setDeathState(JUST_DIED); 2263 1965 }else DespawnTimer -= diff; 2264 }2265 };2266 2267 // Shadowfiends interact with Illidan, setting more targets in Illidan's hashmap2268 struct TRINITY_DLL_SPEC mob_parasitic_shadowfiendAI : public ScriptedAI2269 {2270 mob_parasitic_shadowfiendAI(Creature* c) : ScriptedAI(c)2271 {2272 Reset();2273 }2274 2275 void Reset() {}2276 2277 void Aggro(Unit* who) {}2278 2279 void DoMeleeAttackIfReady()2280 {2281 //If we are within range melee the target2282 if( m_creature->IsWithinDistInMap(m_creature->getVictim(), ATTACK_DISTANCE))2283 {2284 //Make sure our attack is ready and we aren't currently casting2285 if( m_creature->isAttackReady() && !m_creature->IsNonMeleeSpellCasted(false))2286 {2287 if(!m_creature->getVictim()->HasAura(SPELL_PARASITIC_SHADOWFIEND, 0))2288 DoCast(m_creature->getVictim(), SPELL_PARASITIC_SHADOWFIEND, true);2289 m_creature->AttackerStateUpdate(m_creature->getVictim());2290 m_creature->resetAttackTimer();2291 }2292 }2293 1966 } 2294 1967 }; … … 2303 1976 void Reset() 2304 1977 { 2305 BlazeTimer = 2000;2306 DespawnTimer = 15000;2307 }2308 2309 void Aggro(Unit *who){ } 2310 1978 BlazeTimer = 3000; 1979 DespawnTimer = 60000; // Spell duration = 1 min 1980 //((TemporarySummon*)m_creature)->Summon(TEMPSUMMON_TIMED_DESPAWN, 0, false); 1981 } 1982 1983 void Aggro(Unit *who) {} 2311 1984 void AttackStart(Unit* who) { } 2312 2313 1985 void MoveInLineOfSight(Unit *who){ } 2314 1986 2315 1987 void UpdateAI(const uint32 diff) 2316 1988 { 2317 if(BlazeTimer < diff) 2318 { 2319 DoCast(m_creature, SPELL_BLAZE_EFFECT); 2320 BlazeTimer = 15000; 2321 }else BlazeTimer -= diff; 1989 if(BlazeTimer) 1990 if(BlazeTimer <= diff) 1991 { 1992 DoCast(m_creature, SPELL_BLAZE_EFFECT);//duration 60s 1993 BlazeTimer = 0; 1994 }else BlazeTimer -= diff; 2322 1995 2323 1996 if(DespawnTimer < diff) 2324 1997 { 2325 1998 m_creature->SetVisibility(VISIBILITY_OFF); 2326 m_creature-> DealDamage(m_creature, m_creature->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false);1999 m_creature->setDeathState(JUST_DIED); 2327 2000 }else DespawnTimer -= diff; 2328 2001 } 2329 2002 }; 2330 2003 2004 struct TRINITY_DLL_DECL flamecrashAI : public ScriptedAI 2005 { 2006 flamecrashAI(Creature *c) : ScriptedAI(c) {Reset();} 2007 2008 uint32 DespawnTimer; 2009 2010 void Reset() 2011 { 2012 DoCast(m_creature, SPELL_FLAME_CRASH_EFFECT);//duration inf 2013 DespawnTimer = 120000; // summon spell duration 2014 } 2015 2016 void Aggro(Unit *who) {} 2017 void AttackStart(Unit *who) { } 2018 void MoveInLineOfSight(Unit *who){ } 2019 2020 void UpdateAI(const uint32 diff) 2021 { 2022 if(DespawnTimer < diff) 2023 { 2024 m_creature->SetVisibility(VISIBILITY_OFF); 2025 m_creature->setDeathState(JUST_DIED); 2026 }else DespawnTimer -= diff; 2027 } 2028 }; 2029 2331 2030 struct TRINITY_DLL_DECL blade_of_azzinothAI : public ScriptedAI 2332 2031 { 2333 blade_of_azzinothAI(Creature* c) : ScriptedAI(c) { Reset(); } 2334 2032 blade_of_azzinothAI(Creature* c) : ScriptedAI(c) {} 2335 2033 void Reset() {} 2336 // Do-Nothing-But-Stand-There 2337 void Aggro(Unit* who) { } 2034 void Aggro(Unit *who) {} 2338 2035 void AttackStart(Unit* who) { } 2339 2036 void MoveInLineOfSight(Unit* who) { } 2340 2037 2341 }; 2038 void SpellHit(Unit *caster, const SpellEntry *spell) 2039 { 2040 if(spell->Id == SPELL_THROW_GLAIVE2 || spell->Id == SPELL_THROW_GLAIVE) 2041 m_creature->SetUInt32Value(UNIT_FIELD_DISPLAYID, 21431);//appear when hit by Illidan's glaive 2042 } 2043 }; 2044 2045 void boss_illidan_stormrageAI::Reset() 2046 { 2047 if(pInstance) 2048 pInstance->SetData(DATA_ILLIDANSTORMRAGEEVENT, NOT_STARTED); 2049 2050 for(uint8 i = 0; i < 2; i++) 2051 { 2052 if(FlameGUID[i]) 2053 { 2054 if(GETUNIT(Flame, FlameGUID[i])) 2055 Flame->setDeathState(JUST_DIED); 2056 FlameGUID[i] = 0; 2057 } 2058 2059 if(GlaiveGUID[i]) 2060 { 2061 if(GETUNIT(Glaive, GlaiveGUID[i])) 2062 Glaive->setDeathState(JUST_DIED); 2063 GlaiveGUID[i] = 0; 2064 } 2065 } 2066 2067 if(AkamaGUID) 2068 { 2069 if(GETCRE(Akama, AkamaGUID)) 2070 { 2071 if(!Akama->isAlive()) 2072 Akama->Respawn(); 2073 else 2074 { 2075 ((npc_akama_illidanAI*)Akama->AI())->EnterEvadeMode(); 2076 Akama->GetMotionMaster()->MoveTargetedHome(); 2077 ((npc_akama_illidanAI*)Akama->AI())->Reset(); 2078 } 2079 } 2080 AkamaGUID = 0; 2081 } 2082 2083 if(MaievGUID) 2084 { 2085 GETUNIT(Maiev, MaievGUID); 2086 if(Maiev && Maiev->isAlive()) 2087 { 2088 Maiev->CastSpell(Maiev, SPELL_TELEPORT_VISUAL, true); 2089 Maiev->setDeathState(JUST_DIED); 2090 } 2091 MaievGUID = 0; 2092 } 2093 2094 Phase = PHASE_NULL; 2095 Event = EVENT_NULL; 2096 Timer[EVENT_BERSERK] = 1500000; 2097 2098 HoverPoint = 0; 2099 TalkCount = 0; 2100 FlightCount = 0; 2101 TransformCount = 0; 2102 2103 ParasiteTargets.clear(); 2104 2105 m_creature->SetUInt32Value(UNIT_FIELD_DISPLAYID, 21135); 2106 m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); 2107 m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); 2108 m_creature->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_DISPLAY, 0); 2109 m_creature->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_DISPLAY+1, 0); 2110 m_creature->RemoveUnitMovementFlag(MOVEMENTFLAG_LEVITATING); 2111 2112 DoCast(m_creature, SPELL_DUAL_WIELD, true); 2113 } 2114 2115 void boss_illidan_stormrageAI::HandleTalkSequence() 2116 { 2117 switch(TalkCount) 2118 { 2119 case 0: 2120 m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); 2121 break; 2122 case 8: 2123 m_creature->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_DISPLAY, 45479); // Equip our warglaives! 2124 m_creature->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_DISPLAY+1, 45481); 2125 m_creature->SetByteValue(UNIT_FIELD_BYTES_2, 0, SHEATH_STATE_MELEE ); 2126 m_creature->RemoveUnitMovementFlag(MOVEMENTFLAG_WALK_MODE); 2127 break; 2128 case 9: 2129 if(GETCRE(Akama, AkamaGUID)) 2130 { 2131 m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE + UNIT_FLAG_NOT_SELECTABLE); 2132 m_creature->AddThreat(Akama, 100.0f); 2133 ((npc_akama_illidanAI*)Akama->AI())->EnterPhase(PHASE_FIGHT_ILLIDAN); 2134 EnterPhase(PHASE_NORMAL); 2135 } 2136 break; 2137 case 10: 2138 SummonMaiev(); 2139 break; 2140 case 11: 2141 if(GETUNIT(Maiev, MaievGUID)) 2142 { 2143 Maiev->SetVisibility(VISIBILITY_ON); // Maiev is now visible 2144 Maiev->CastSpell(Maiev, SPELL_TELEPORT_VISUAL, true); // onoz she looks like she teleported! 2145 Maiev->SetInFront(m_creature); // Have her face us 2146 m_creature->SetInFront(Maiev); // Face her, so it's not rude =P 2147 Maiev->StopMoving(); 2148 m_creature->StopMoving(); 2149 }break; 2150 case 14: 2151 if(GETCRE(Maiev, MaievGUID)) 2152 { 2153 m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE + UNIT_FLAG_NOT_SELECTABLE); 2154 Maiev->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE + UNIT_FLAG_NOT_SELECTABLE); 2155 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 2156 Maiev->AI()->AttackStart(m_creature); // Force Maiev to attack us. 2157 EnterPhase(PHASE_NORMAL_MAIEV); 2158 }break; 2159 case 15: 2160 DoCast(m_creature, SPELL_DEATH); // Animate his kneeling + stun him 2161 break; 2162 case 17: 2163 if(GETUNIT(Akama, AkamaGUID)) 2164 { 2165 if(!m_creature->IsWithinDistInMap(Akama, 15)) 2166 { 2167 float x, y, z; 2168 m_creature->GetPosition(x, y, z); 2169 x += 10; y += 10; 2170 Akama->GetMotionMaster()->Clear(false); 2171 //Akama->GetMotionMaster()->MoveIdle(); 2172 Akama->Relocate(x, y, z); 2173 Akama->SendMonsterMove(x, y, z, 0, 0, 0);//Illidan must not die until Akama arrives. 2174 Akama->GetMotionMaster()->MoveChase(m_creature); 2175 } 2176 } 2177 break; 2178 case 19: // Make Maiev leave 2179 if(GETUNIT(Maiev, MaievGUID)) 2180 { 2181 Maiev->CastSpell(Maiev, SPELL_TELEPORT_VISUAL, true); 2182 Maiev->setDeathState(JUST_DIED); 2183 m_creature->SetUInt32Value(UNIT_FIELD_BYTES_1,PLAYER_STATE_DEAD); 2184 } 2185 break; 2186 case 21: // Kill ourself. 2187 m_creature->DealDamage(m_creature, m_creature->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); 2188 break; 2189 default: 2190 break; 2191 } 2192 if(Phase == PHASE_TALK_SEQUENCE) 2193 Talk(TalkCount); // This function does most of the talking 2194 TalkCount++; 2195 } 2196 2197 2198 void boss_illidan_stormrageAI::CastEyeBlast() 2199 { 2200 m_creature->InterruptNonMeleeSpells(false); 2201 2202 DoYell(SAY_EYE_BLAST, LANG_UNIVERSAL, NULL); 2203 DoPlaySoundToSet(m_creature, SOUND_EYE_BLAST); 2204 2205 float distx, disty, dist[2]; 2206 for(uint8 i = 0; i < 2; ++i) 2207 { 2208 distx = EyeBlast[i].x - HoverPosition[HoverPoint].x; 2209 disty = EyeBlast[i].y - HoverPosition[HoverPoint].y; 2210 dist[i] = distx * distx + disty * disty; 2211 } 2212 Locations initial = EyeBlast[dist[0] < dist[1] ? 0 : 1]; 2213 for(uint8 i = 0; i < 2; ++i) 2214 { 2215 distx = GlaivePosition[i].x - HoverPosition[HoverPoint].x; 2216 disty = GlaivePosition[i].y - HoverPosition[HoverPoint].y; 2217 dist[i] = distx * distx + disty * disty; 2218 } 2219 Locations final = GlaivePosition[dist[0] < dist[1] ? 0 : 1]; 2220 2221 final.x = 2 * final.x - initial.x; 2222 final.y = 2 * final.y - initial.y; 2223 2224 for(uint8 i = 0; i < 2; ++i)//core bug, two buff do not coexist 2225 { 2226 Creature* Trigger = NULL; 2227 Trigger = m_creature->SummonCreature(DEMON_FIRE, initial.x, initial.y, initial.z, 0, TEMPSUMMON_TIMED_DESPAWN, 13000); 2228 if(Trigger) 2229 { 2230 ((demonfireAI*)Trigger->AI())->IsTrigger = true; 2231 Trigger->SetSpeed(MOVE_WALK, 3); 2232 Trigger->SetUnitMovementFlags(MOVEMENTFLAG_WALK_MODE); 2233 Trigger->GetMotionMaster()->MovePoint(0, final.x, final.y, final.z); 2234 2235 if(!i) 2236 Trigger->CastSpell(Trigger, SPELL_EYE_BLAST_TRIGGER, true); 2237 else 2238 { 2239 Trigger->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); 2240 m_creature->SetUInt64Value(UNIT_FIELD_TARGET, Trigger->GetGUID()); 2241 DoCast(Trigger, SPELL_EYE_BLAST); 2242 } 2243 } 2244 } 2245 } 2246 2247 void boss_illidan_stormrageAI::SummonFlamesOfAzzinoth() 2248 { 2249 DoYell(SAY_SUMMONFLAMES, LANG_UNIVERSAL, NULL); 2250 DoPlaySoundToSet(m_creature, SOUND_SUMMONFLAMES); 2251 2252 for(uint8 i = 0; i < 2; ++i) 2253 { 2254 if(GETUNIT(Glaive, GlaiveGUID[i])) 2255 { 2256 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); 2257 if(Flame) 2258 { 2259 Flame->setFaction(m_creature->getFaction()); // Just in case the database has it as a different faction 2260 Flame->SetMeleeDamageSchool(SPELL_SCHOOL_FIRE); 2261 Flame->AI()->AttackStart(m_creature->getVictim()); // Attack our target! 2262 FlameGUID[i] = Flame->GetGUID(); // Record GUID in order to check if they're dead later on to move to the next phase 2263 ((flame_of_azzinothAI*)Flame->AI())->SetGlaiveGUID(GlaiveGUID[i]); 2264 DoZoneInCombat(Flame); 2265 Glaive->CastSpell(Flame, SPELL_AZZINOTH_CHANNEL, false); // Glaives do some random Beam type channel on it. 2266 } 2267 } 2268 } 2269 } 2270 2271 void boss_illidan_stormrageAI::SummonMaiev() 2272 { 2273 DoCast(m_creature, SPELL_SHADOW_PRISON, true); 2274 Creature* Maiev = m_creature->SummonCreature(MAIEV_SHADOWSONG, m_creature->GetPositionX() + 10, m_creature->GetPositionY() + 5, m_creature->GetPositionZ(), 0, TEMPSUMMON_CORPSE_DESPAWN, 0); 2275 if(Maiev) 2276 { 2277 Maiev->SetVisibility(VISIBILITY_OFF); // Leave her invisible until she has to talk 2278 Maiev->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); 2279 MaievGUID = Maiev->GetGUID(); 2280 ((boss_maievAI*)Maiev->AI())->GetIllidanGUID(m_creature->GetGUID()); 2281 ((boss_maievAI*)Maiev->AI())->EnterPhase(PHASE_TALK_SEQUENCE); 2282 } 2283 else // If Maiev cannot be summoned, reset the encounter and post some errors to the console. 2284 { 2285 EnterEvadeMode(); 2286 DoTextEmote("is unable to summon Maiev Shadowsong and enter Phase 4. Resetting Encounter.", NULL); 2287 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)"); 2288 } 2289 } 2290 2291 2292 void boss_illidan_stormrageAI::EnterPhase(PhaseIllidan NextPhase) 2293 { 2294 DoZoneInCombat(); 2295 switch(NextPhase) 2296 { 2297 case PHASE_NORMAL: 2298 case PHASE_NORMAL_2: 2299 case PHASE_NORMAL_MAIEV: 2300 AttackStart(m_creature->getVictim()); 2301 Timer[EVENT_TAUNT] = 32000; 2302 Timer[EVENT_SHEAR] = 10000 + rand()%15 * 1000; 2303 Timer[EVENT_FLAME_CRASH] = 20000; 2304 Timer[EVENT_PARASITIC_SHADOWFIEND] = 25000; 2305 Timer[EVENT_PARASITE_CHECK] = 0; 2306 Timer[EVENT_DRAW_SOUL] = 30000; 2307 if(NextPhase == PHASE_NORMAL) 2308 break; 2309 Timer[EVENT_AGONIZING_FLAMES] = 35000; 2310 Timer[EVENT_TRANSFORM_NORMAL] = 60000; 2311 if(NextPhase == PHASE_NORMAL_2) 2312 break; 2313 Timer[EVENT_ENRAGE] = 30000 + rand()%10 * 1000; 2314 break; 2315 case PHASE_FLIGHT: 2316 Timer[EVENT_FIREBALL] = 1000; 2317 if(!(rand()%4)) 2318 Timer[EVENT_DARK_BARRAGE] = 10000; 2319 Timer[EVENT_EYE_BLAST] = 10000 + rand()%15 * 1000; 2320 Timer[EVENT_MOVE_POINT] = 20000 + rand()%20 * 1000; 2321 break; 2322 case PHASE_DEMON: 2323 Timer[EVENT_SHADOW_BLAST] = 1000; 2324 Timer[EVENT_FLAME_BURST] = 10000; 2325 Timer[EVENT_SHADOWDEMON] = 30000; 2326 Timer[EVENT_TRANSFORM_DEMON] = 60000; 2327 AttackStart(m_creature->getVictim()); 2328 break; 2329 case PHASE_TALK_SEQUENCE: 2330 Timer[EVENT_TALK_SEQUENCE] = 100; 2331 m_creature->RemoveAllAuras(); 2332 m_creature->InterruptNonMeleeSpells(false); 2333 m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE + UNIT_FLAG_NOT_SELECTABLE); 2334 m_creature->GetMotionMaster()->Clear(false); 2335 //m_creature->GetMotionMaster()->MoveIdle(); 2336 m_creature->AttackStop(); 2337 break; 2338 case PHASE_FLIGHT_SEQUENCE: 2339 if(Phase == PHASE_FLIGHT) //land 2340 Timer[EVENT_FLIGHT_SEQUENCE] = 2000; 2341 else //lift off 2342 { 2343 FlightCount = 1; 2344 Timer[EVENT_FLIGHT_SEQUENCE] = 1; 2345 m_creature->RemoveAllAuras(); 2346 m_creature->InterruptNonMeleeSpells(false); 2347 m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE + UNIT_FLAG_NOT_SELECTABLE); 2348 m_creature->GetMotionMaster()->Clear(false); 2349 //m_creature->GetMotionMaster()->MoveIdle(); 2350 m_creature->AttackStop(); 2351 } 2352 break; 2353 case PHASE_TRANSFORM_SEQUENCE: 2354 if(Phase == PHASE_DEMON) 2355 Timer[EVENT_TRANSFORM_SEQUENCE] = 500; 2356 else 2357 { 2358 TransformCount = 0; 2359 Timer[EVENT_TRANSFORM_SEQUENCE] = 500; 2360 DoYell(SAY_MORPH, LANG_UNIVERSAL, NULL); 2361 DoPlaySoundToSet(m_creature, SOUND_MORPH); 2362 } 2363 m_creature->GetMotionMaster()->Clear(); 2364 //m_creature->GetMotionMaster()->MoveIdle(); 2365 m_creature->AttackStop(); 2366 break; 2367 default: 2368 break; 2369 } 2370 if(MaievGUID) 2371 { 2372 GETCRE(Maiev, MaievGUID); 2373 if(Maiev && Maiev->isAlive()) 2374 ((boss_maievAI*)Maiev->AI())->EnterPhase(NextPhase); 2375 } 2376 Phase = NextPhase; 2377 Event = EVENT_NULL; 2378 } 2342 2379 2343 2380 CreatureAI* GetAI_boss_illidan_stormrage(Creature *_Creature) … … 2348 2385 CreatureAI* GetAI_npc_akama_at_illidan(Creature *_Creature) 2349 2386 { 2350 npc_akama_illidanAI* Akama_AI = new npc_akama_illidanAI(_Creature); 2351 2352 for(uint8 i = 0; i < 13; ++i) 2353 Akama_AI->AddWaypoint(i, AkamaWP[i].x, AkamaWP[i].y, AkamaWP[i].z); 2354 2355 return ((CreatureAI*)Akama_AI); 2387 return new npc_akama_illidanAI(_Creature); 2356 2388 } 2357 2389 -
trunk/src/bindings/scripts/scripts/zone/black_temple/boss_mother_shahraz.cpp
r48 r57 33 33 #define SPELL_SILENCING_SHRIEK 40823 34 34 #define SPELL_ENRAGE 23537 35 #define SPELL_SABER_LASH 4 326735 #define SPELL_SABER_LASH 40810//43267 36 36 #define SPELL_SABER_LASH_IMM 43690 37 37 #define SPELL_TELEPORT_VISUAL 40869 … … 116 116 uint32 FatalAttractionExplodeTimer; 117 117 uint32 ShriekTimer; 118 uint32 SaberTimer; 118 119 uint32 RandomYellTimer; 119 120 uint32 EnrageTimer; … … 130 131 TargetGUID[i] = 0; 131 132 132 BeamTimer = 60000;// Timers may be incorrect133 BeamTimer = 20000; // Timers may be incorrect 133 134 BeamCount = 0; 134 135 CurrentBeam = 0; // 0 - Sinister, 1 - Vile, 2 - Wicked, 3 - Sinful … … 137 138 FatalAttractionExplodeTimer = 70000; 138 139 ShriekTimer = 30000; 140 SaberTimer = 35000; 139 141 RandomYellTimer = 70000 + rand()%41 * 1000; 140 142 EnrageTimer = 600000; … … 302 304 { 303 305 DoCast(m_creature->getVictim(), SPELL_SILENCING_SHRIEK); 304 ShriekTimer = 30000;306 ShriekTimer = 25000+rand()%10 * 1000; 305 307 }else ShriekTimer -= diff; 308 309 if(SaberTimer < diff) 310 { 311 DoCast(m_creature->getVictim(), SPELL_SABER_LASH); 312 SaberTimer = 25000+rand()%10 * 1000; 313 }else SaberTimer -= diff; 306 314 307 315 //Enrage -
trunk/src/bindings/scripts/scripts/zone/black_temple/boss_reliquary_of_souls.cpp
r48 r57 1 1 /* Copyright (C) 2006 - 2008 ScriptDev2 <https://scriptdev2.svn.sourceforge.net/> 2 3 4 5 6 7 8 9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the10 11 12 13 14 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307USA15 2 * This program is free software; you can redistribute it and/or modify 3 * it under the terms of the GNU General Public License as published by 4 * the Free Software Foundation; either version 2 of the License, or 5 * (at your option) any later version. 6 * 7 * This program is distributed in the hope that it will be useful, 8 * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 * GNU General Public License for more details. 11 * 12 * You should have received a copy of the GNU General Public License 13 * along with this program; if not, write to the Free Software 14 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 15 */ 16 16 17 17 /* ScriptData 18 18 SDName: Boss_Reliquary_of_Souls 19 19 SD%Complete: 90 20 SDComment: Persistent Area Auras for each Essence (Aura of Suffering, Aura of Desire, Aura of Anger) requires core support.20 SDComment: 21 21 SDCategory: Black Temple 22 22 EndScriptData */ … … 24 24 #include "precompiled.h" 25 25 #include "def_black_temple.h" 26 #include "Spell.h" 26 27 27 28 //Sound'n'speech … … 35 36 #define SUFF_SAY_SLAY2 "I didn't ask for this!" 36 37 #define SUFF_SOUND_SLAY2 11418 37 #define SUFF_SAY_ SLAY3"The pain is only beginning!"38 #define SUFF_SOUND_ SLAY31141938 #define SUFF_SAY_ENRAGE "The pain is only beginning!" 39 #define SUFF_SOUND_ENRAGE 11419 39 40 #define SUFF_SAY_RECAP "I don't want to go back!" 40 41 #define SUFF_SOUND_RECAP 11420 … … 61 62 #define ANGER_SAY_FREED "Beware... I live." 62 63 #define ANGER_SOUND_FREED 11399 63 #define ANGER_SAY_ FREED2"So... foolish."64 #define ANGER_SOUND_ FREED21140064 #define ANGER_SAY_SCREAM "So... foolish." 65 #define ANGER_SOUND_SCREAM 11400 65 66 #define ANGER_SOUND_SLAY1 11401 66 67 #define ANGER_SAY_SLAY2 "Enough. No more." … … 75 76 //Spells 76 77 #define AURA_OF_SUFFERING 41292 77 #define AURA_OF_SUFFERING_ARMOR 42017 78 #define ESSENCE_OF_SUFFERING_PASSIVE 41296 78 #define AURA_OF_SUFFERING_ARMOR 42017 // linked aura, need core support 79 #define ESSENCE_OF_SUFFERING_PASSIVE 41296 // periodic trigger 41294 80 #define ESSENCE_OF_SUFFERING_PASSIVE2 41623 81 #define SPELL_FIXATE_TARGET 41294 // dummy, select target 82 #define SPELL_FIXATE_TAUNT 41295 // force taunt 79 83 #define SPELL_ENRAGE 41305 80 84 #define SPELL_SOUL_DRAIN 41303 81 #define SPELL_FIXATE 4129582 85 83 86 #define AURA_OF_DESIRE 41350 87 #define AURA_OF_DESIRE_DAMAGE 41352 84 88 #define SPELL_RUNE_SHIELD 41431 85 89 #define SPELL_DEADEN 41410 … … 87 91 88 92 #define AURA_OF_ANGER 41337 89 #define SPELL_SELF_SEETHE 41364 93 #define SPELL_SELF_SEETHE 41364 // force cast 41520 90 94 #define SPELL_ENEMY_SEETHE 41520 91 95 #define SPELL_SOUL_SCREAM 41545 92 #define SPELL_SPITE 41377 96 #define SPELL_SPITE_TARGET 41376 // cast 41377 after 6 sec 97 #define SPELL_SPITE_DAMAGE 41377 93 98 94 99 #define ENSLAVED_SOUL_PASSIVE 41535 95 100 #define SPELL_SOUL_RELEASE 41542 96 #define SPELL_RESTORE_MANA 3284897 #define SPELL_RESTORE_HEALTH 2532998 101 99 102 #define CREATURE_ENSLAVED_SOUL 23469 103 #define NUMBER_ENSLAVED_SOUL 8 100 104 101 105 struct Position … … 120 124 uint64 ReliquaryGUID; 121 125 122 void Reset() 123 { 124 ReliquaryGUID = 0; 125 } 126 127 void Aggro(Unit* who) {} 128 129 void DamageTaken(Unit *done_by, uint32 &damage) 130 { 131 if(damage >= m_creature->GetHealth()) 132 { 133 if(done_by->GetTypeId() == TYPEID_PLAYER) 134 { 135 done_by->CastSpell(done_by, SPELL_RESTORE_HEALTH, true); 136 if(done_by->GetMaxPower(POWER_MANA) > 0) 137 { 138 if((done_by->GetPower(POWER_MANA) / done_by->GetMaxPower(POWER_MANA)) < 70) 139 { 140 uint32 mana = done_by->GetPower(POWER_MANA) + (uint32)(done_by->GetMaxPower(POWER_MANA)*0.3); 141 done_by->SetPower(POWER_MANA, mana); 142 }else done_by->SetPower(POWER_MANA, done_by->GetMaxPower(POWER_MANA)); 143 } 144 } 145 DoCast(done_by, SPELL_SOUL_RELEASE); 146 } 126 void Reset() {ReliquaryGUID = 0;} 127 128 void Aggro(Unit* who) 129 { 130 m_creature->CastSpell(m_creature, ENSLAVED_SOUL_PASSIVE, true); 131 DoZoneInCombat(); 147 132 } 148 133 … … 152 137 struct TRINITY_DLL_DECL boss_reliquary_of_soulsAI : public ScriptedAI 153 138 { 154 boss_reliquary_of_soulsAI(Creature *c) : ScriptedAI(c) 139 boss_reliquary_of_soulsAI(Creature *c) : ScriptedAI(c) 155 140 { 156 141 pInstance = ((ScriptedInstance*)c->GetInstanceData()); 142 EssenceGUID = 0; 157 143 Reset(); 158 144 } … … 160 146 ScriptedInstance* pInstance; 161 147 162 uint64 SufferingGUID; 163 uint64 DesireGUID; 164 uint64 AngerGUID; 165 148 uint64 EssenceGUID; 149 150 uint32 Phase; 151 uint32 Counter; 152 uint32 Timer; 153 154 uint32 SoulCount; 166 155 uint32 SoulDeathCount; 167 // 0 = Out of Combat, 1 = Not started, 2 = Suffering, 3 = Souls, 4 = Desire, 5 = Souls, 6 = Anger168 uint32 Phase;169 uint32 SummonEssenceTimer;170 uint32 DespawnEssenceTimer;171 uint32 SoulCount;172 uint32 SummonSoulTimer;173 uint32 AnimationTimer;174 175 bool IsDead;176 bool EndingPhase;177 156 178 157 void Reset() … … 181 160 pInstance->SetData(DATA_RELIQUARYOFSOULSEVENT, NOT_STARTED); 182 161 183 DespawnEssences(); 184 185 SufferingGUID = 0; 186 DesireGUID = 0; 187 AngerGUID = 0; 188 189 SoulDeathCount = 0; 162 if(EssenceGUID) 163 { 164 if(Unit* Essence = Unit::GetUnit(*m_creature, EssenceGUID)) 165 { 166 Essence->SetVisibility(VISIBILITY_OFF); 167 Essence->setDeathState(DEAD); 168 } 169 EssenceGUID = 0; 170 } 171 190 172 Phase = 0; 191 SummonEssenceTimer = 8000; 192 DespawnEssenceTimer = 2000; 193 SoulCount = 0; 194 SummonSoulTimer = 1000; 195 AnimationTimer = 8000; 196 197 IsDead = false; 198 EndingPhase = false; 199 200 m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); 173 201 174 m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); 202 175 m_creature->SetUInt32Value(UNIT_NPC_EMOTESTATE,0); 203 m_creature->GetMotionMaster()->Clear(false); 204 } 205 206 void Aggro(Unit* who) { } 207 208 void AttackStart(Unit* who) { } 176 } 177 178 void Aggro(Unit* who) 179 { 180 m_creature->AddThreat(who, 10000.0f); 181 DoZoneInCombat(); 182 if(pInstance) 183 pInstance->SetData(DATA_RELIQUARYOFSOULSEVENT, IN_PROGRESS); 184 185 Phase = 1; 186 Counter = 0; 187 Timer = 0; 188 } 209 189 210 190 void MoveInLineOfSight(Unit *who) 211 191 { 212 if (who->isTargetableForAttack() && who->isInAccessablePlaceFor(m_creature) && m_creature->IsHostileTo(who)) 213 { 192 if( !m_creature->getVictim() && who->isTargetableForAttack() && ( m_creature->IsHostileTo( who )) && who->isInAccessablePlaceFor(m_creature) ) 193 { 194 if (m_creature->GetDistanceZ(who) > CREATURE_Z_ATTACK_RANGE) 195 return; 196 214 197 float attackRadius = m_creature->GetAttackDistance(who); 215 if (m_creature->IsWithinDistInMap(who, attackRadius) && m_creature->GetDistanceZ(who) <= CREATURE_Z_ATTACK_RANGE && m_creature->IsWithinLOSInMap(who))198 if( m_creature->IsWithinDistInMap(who, attackRadius) && m_creature->IsWithinLOSInMap(who) ) 216 199 { 217 if(who->HasStealthAura()) 218 who->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH); 219 220 if(!InCombat) 200 who->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH); 201 202 if (!InCombat) 221 203 { 222 if(pInstance) 223 pInstance->SetData(DATA_RELIQUARYOFSOULSEVENT, IN_PROGRESS); 224 225 Phase = 1; 226 // I R ANNNGRRRY! 227 m_creature->SetUInt32Value(UNIT_NPC_EMOTESTATE,375); 228 SummonEssenceTimer = 8000; 229 AnimationTimer = 5100; 230 m_creature->AddThreat(who, 1.0f); 231 204 Aggro(who); 232 205 InCombat = true; 233 206 } … … 236 209 } 237 210 238 void SummonSoul() 211 void AttackStart(Unit*) {} 212 213 bool SummonSoul() 239 214 { 240 215 uint32 random = rand()%6; 241 216 float x = Coords[random].x; 242 217 float y = Coords[random].y; 243 Creature* Soul = m_creature->SummonCreature(CREATURE_ENSLAVED_SOUL, x, y, m_creature->GetPositionZ(), m_creature->GetOrientation(), TEMPSUMMON_ TIMED_OR_CORPSE_DESPAWN, 45000);244 Unit* target = SelectUnit(SELECT_TARGET_RANDOM, 0);245 if (target && Soul)218 Creature* Soul = m_creature->SummonCreature(CREATURE_ENSLAVED_SOUL, x, y, m_creature->GetPositionZ(), m_creature->GetOrientation(), TEMPSUMMON_CORPSE_DESPAWN, 0); 219 if(!Soul) return false; 220 if(Unit* target = SelectUnit(SELECT_TARGET_RANDOM, 0)) 246 221 { 247 222 ((npc_enslaved_soulAI*)Soul->AI())->ReliquaryGUID = m_creature->GetGUID(); 248 Soul->CastSpell(Soul, ENSLAVED_SOUL_PASSIVE, true); 249 Soul->AddThreat(target, 1.0f); 250 SoulCount++; 251 } 252 } 253 254 void MergeThreatList(Creature* target) 255 { 256 if(!target) return; 257 258 std::list<HostilReference*>& m_threatlist = target->getThreatManager().getThreatList(); 259 std::list<HostilReference*>::iterator itr = m_threatlist.begin(); 260 for( ; itr != m_threatlist.end(); itr++) 261 { 262 Unit* pUnit = Unit::GetUnit((*m_creature), (*itr)->getUnitGuid()); 263 if(pUnit) 264 { 265 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. 266 m_creature->getThreatManager().modifyThreatPercent(pUnit, -100); 267 float threat = target->getThreatManager().getThreat(pUnit); 268 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). 269 } 270 } 271 } 272 273 void DespawnEssences() 274 { 275 // Despawn Essences 276 Unit* Essence = NULL; 277 if(SufferingGUID) 278 Essence = ((Creature*)Unit::GetUnit((*m_creature), SufferingGUID)); 279 else if(DesireGUID) 280 Essence = ((Creature*)Unit::GetUnit((*m_creature), DesireGUID)); 281 else if(AngerGUID) 282 Essence = ((Creature*)Unit::GetUnit((*m_creature), AngerGUID)); 283 if(Essence && Essence->isAlive()) 284 Essence->setDeathState(JUST_DIED); 223 Soul->AI()->AttackStart(target); 224 }else EnterEvadeMode(); 225 return true; 285 226 } 286 227 … … 298 239 return; 299 240 300 // Reset if event is begun and we don't have a threatlist301 if(Phase && m_creature->getThreatManager().getThreatList().empty())241 if(m_creature->getThreatManager().getThreatList().empty()) // Reset if event is begun and we don't have a threatlist 242 { 302 243 EnterEvadeMode(); 303 304 if(Phase == 1) 305 { 306 if(AnimationTimer < diff) 244 return; 245 } 246 247 Creature* Essence; 248 if(EssenceGUID) 249 { 250 Essence = (Creature*)Unit::GetUnit(*m_creature, EssenceGUID); 251 if(!Essence) 307 252 { 308 // Release the cube 309 m_creature->SetUInt32Value(UNIT_NPC_EMOTESTATE,374); 310 AnimationTimer = 8300; 311 }else AnimationTimer -= diff; 312 313 if(SummonEssenceTimer < diff) 253 EnterEvadeMode(); 254 return; 255 } 256 } 257 258 if(Timer < diff) 259 { 260 switch(Counter) 314 261 { 315 // Ribs: open 316 m_creature->SetUInt32Value(UNIT_NPC_EMOTESTATE,373); 317 Creature* EssenceSuffering = NULL; 318 EssenceSuffering = m_creature->SummonCreature(23418, m_creature->GetPositionX(), m_creature->GetPositionY(), m_creature->GetPositionZ(), 1.57, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 10000); 319 320 if(EssenceSuffering) 262 case 0: 263 m_creature->SetUInt32Value(UNIT_NPC_EMOTESTATE,375); // I R ANNNGRRRY! 264 Timer = 3000; 265 break; 266 case 1: 267 Timer = 2800; 268 m_creature->SetUInt32Value(UNIT_NPC_EMOTESTATE,374); // Release the cube 269 break; 270 case 2: 271 Timer = 5000; 272 if(Creature* Summon = DoSpawnCreature(23417+Phase, 0, 0, 0, 0, TEMPSUMMON_DEAD_DESPAWN, 0)) 321 273 { 322 EssenceSuffering->Yell(SUFF_SAY_FREED, LANG_UNIVERSAL, 0); 323 DoPlaySoundToSet(m_creature, SUFF_SOUND_FREED); 324 Unit* target = SelectUnit(SELECT_TARGET_TOPAGGRO, 0); 325 if(target) 274 m_creature->SetUInt32Value(UNIT_NPC_EMOTESTATE,373); // Ribs: open 275 Summon->AI()->AttackStart(SelectUnit(SELECT_TARGET_TOPAGGRO, 0)); 276 EssenceGUID = Summon->GetGUID(); 277 }else EnterEvadeMode(); 278 break; 279 case 3: 280 Timer = 1000; 281 if(Phase == 3) 282 { 283 if(!Essence->isAlive()) 284 m_creature->CastSpell(m_creature, 7, true); 285 else return; 286 } 287 else 288 { 289 if(Essence->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE)) 326 290 { 327 EssenceSuffering->AddThreat(target, 1.0f); 328 EssenceSuffering->AI()->AttackStart(target); 329 } 330 SufferingGUID = EssenceSuffering->GetGUID(); 291 Essence->AI()->EnterEvadeMode(); 292 Essence->GetMotionMaster()->MoveFollow(m_creature, 0, 0); 293 }else return; 331 294 } 332 333 EndingPhase = false; 334 Phase = 2; 335 }else SummonEssenceTimer -= diff; 336 } 337 338 if(Phase == 2) 339 { 340 if(SufferingGUID) 341 { 342 Creature* EssenceSuffering = NULL; 343 EssenceSuffering = ((Creature*)Unit::GetUnit((*m_creature), SufferingGUID)); 344 345 if(!EssenceSuffering || (!EssenceSuffering->isAlive())) 346 EnterEvadeMode(); 347 348 if(!EndingPhase) 295 break; 296 case 4: 297 Timer = 1500; 298 if(Essence->IsWithinDistInMap(m_creature, 10)) 299 Essence->SetUInt32Value(UNIT_NPC_EMOTESTATE, 374); //rotate and disappear 300 else 301 return; 302 break; 303 case 5: 304 if(Phase == 1) 349 305 { 350 if(EssenceSuffering) 351 { 352 if(EssenceSuffering->GetHealth() < (EssenceSuffering->GetMaxHealth()*0.1)) 353 { 354 MergeThreatList(EssenceSuffering); 355 EssenceSuffering->RemoveAllAuras(); 356 EssenceSuffering->DeleteThreatList(); 357 EssenceSuffering->GetMotionMaster()->MoveFollow(m_creature,0.0f,0.0f); 358 EssenceSuffering->Yell(SUFF_SAY_RECAP,LANG_UNIVERSAL,0); 359 DoPlaySoundToSet(m_creature, SUFF_SOUND_RECAP); 360 EssenceSuffering->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); 361 DespawnEssenceTimer = 4000; 362 AnimationTimer = 2200; 363 EndingPhase = true; 364 } 365 } 306 Essence->Yell(SUFF_SAY_AFTER,LANG_UNIVERSAL,0); 307 DoPlaySoundToSet(Essence, SUFF_SOUND_AFTER); 366 308 } 367 368 if((EndingPhase) && (EssenceSuffering) && (EssenceSuffering->isAlive())) 309 else 369 310 { 370 if(AnimationTimer < diff) 371 { 372 // Return 373 EssenceSuffering->SetUInt32Value(UNIT_NPC_EMOTESTATE,374); 374 AnimationTimer = 10000; 375 }else AnimationTimer -= diff; 376 377 if(DespawnEssenceTimer < diff) 378 { 379 EssenceSuffering->DeleteThreatList(); 380 EssenceSuffering->Yell(SUFF_SAY_AFTER,LANG_UNIVERSAL,0); 381 DoPlaySoundToSet(m_creature, SUFF_SOUND_AFTER); 382 EssenceSuffering->SetUInt32Value(UNIT_FIELD_DISPLAYID, 11686); 383 EssenceSuffering->setFaction(35); 384 m_creature->SetUInt32Value(UNIT_NPC_EMOTESTATE,0); 385 SummonEssenceTimer = 20000; //60000; 386 AnimationTimer = 18200; //58100; 387 SoulDeathCount = 0; 388 SoulCount = 0; 389 SummonSoulTimer = 1000; 390 EndingPhase = false; 391 Phase = 3; 392 SufferingGUID = 0; 393 }else DespawnEssenceTimer -= diff; 311 Essence->Yell(DESI_SAY_AFTER,LANG_UNIVERSAL,0); 312 DoPlaySoundToSet(Essence, DESI_SOUND_AFTER); 394 313 } 395 } 396 } 397 398 if(Phase == 3) 399 { 400 if(SoulCount < 36) 401 { 402 if(SummonSoulTimer < diff) 314 Essence->SetVisibility(VISIBILITY_OFF); 315 Essence->setDeathState(DEAD); 316 m_creature->SetUInt32Value(UNIT_NPC_EMOTESTATE,0); 317 EssenceGUID = 0; 318 SoulCount = 0; 319 SoulDeathCount = 0; 320 Timer = 3000; 321 break; 322 case 6: 323 if(SoulCount < NUMBER_ENSLAVED_SOUL) 403 324 { 404 SummonSoul(); 405 SummonSoulTimer = 500; 406 }else SummonSoulTimer -= diff; 407 } 408 409 if(SoulDeathCount >= SoulCount) 410 { 411 if(AnimationTimer < diff) 325 if(SummonSoul()) 326 SoulCount++; 327 Timer = 500; 328 return; 329 }break; 330 case 7: 331 if(SoulDeathCount >= SoulCount) 412 332 { 413 // Release the cube 414 m_creature->SetUInt32Value(UNIT_NPC_EMOTESTATE,374); 415 AnimationTimer = 10000; 416 }else AnimationTimer -= diff; 417 418 if(SummonEssenceTimer < diff) 419 { 420 // Ribs: open 421 m_creature->SetUInt32Value(UNIT_NPC_EMOTESTATE,373); 422 Creature* EssenceDesire = NULL; 423 EssenceDesire = m_creature->SummonCreature(23419, m_creature->GetPositionX(), m_creature->GetPositionY(), m_creature->GetPositionZ(), 1.57, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 10000); 424 425 if(EssenceDesire) 426 { 427 EssenceDesire->Yell(DESI_SAY_FREED, LANG_UNIVERSAL, NULL); 428 DoPlaySoundToSet(m_creature, DESI_SOUND_FREED); 429 Unit* target = NULL; 430 target = SelectUnit(SELECT_TARGET_RANDOM, 0); 431 if(target) 432 { 433 EssenceDesire->AddThreat(target, 1.0f); 434 EssenceDesire->AI()->AttackStart(target); 435 } 436 DesireGUID = EssenceDesire->GetGUID(); 437 SoulDeathCount = 0; 438 } 439 440 Phase = 4; 441 }else SummonEssenceTimer -= diff; 442 } 443 } 444 445 if(Phase == 4) 446 { 447 if(DesireGUID) 448 { 449 Creature* EssenceDesire = NULL; 450 EssenceDesire = ((Creature*)Unit::GetUnit((*m_creature), DesireGUID)); 451 452 if(!EssenceDesire || !EssenceDesire->isAlive()) 453 EnterEvadeMode(); 454 455 if(!EndingPhase && EssenceDesire) 456 { 457 if(EssenceDesire->GetHealth() < (EssenceDesire->GetMaxHealth()*0.1)) 458 { 459 MergeThreatList(EssenceDesire); 460 EssenceDesire->GetMotionMaster()->MoveFollow(m_creature,0.0f,0.0f); 461 EssenceDesire->RemoveAllAuras(); 462 EssenceDesire->DeleteThreatList(); 463 EssenceDesire->Yell(DESI_SAY_RECAP,LANG_UNIVERSAL,0); 464 DoPlaySoundToSet(m_creature, DESI_SOUND_RECAP); 465 EssenceDesire->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); 466 DespawnEssenceTimer = 4000; 467 AnimationTimer = 2200; 468 EndingPhase = true; 469 } 333 Counter = 1; 334 Phase++; 335 Timer = 5000; 470 336 } 471 472 if(EndingPhase && EssenceDesire) 473 { 474 if(EssenceDesire->isAlive()) 475 { 476 if(AnimationTimer < diff) 477 { 478 // Return 479 EssenceDesire->SetUInt32Value(UNIT_NPC_EMOTESTATE,374); 480 AnimationTimer = 10000; 481 }else AnimationTimer -= diff; 482 483 if(DespawnEssenceTimer < diff) 484 { 485 EssenceDesire->DeleteThreatList(); 486 EssenceDesire->setFaction(35); 487 EssenceDesire->Yell(DESI_SAY_AFTER, LANG_UNIVERSAL, 0); 488 DoPlaySoundToSet(m_creature, DESI_SOUND_AFTER); 489 EssenceDesire->SetUInt32Value(UNIT_FIELD_DISPLAYID, 11686); 490 m_creature->SetUInt32Value(UNIT_NPC_EMOTESTATE,0); 491 SummonEssenceTimer = 20000; 492 AnimationTimer = 18200; 493 SoulDeathCount = 0; 494 SoulCount = 0; 495 SummonSoulTimer = 1000; 496 EndingPhase = false; 497 Phase = 5; 498 DesireGUID = 0; 499 }else DespawnEssenceTimer -= diff; 500 } 501 } 502 } 503 } 504 505 if(Phase == 5) 506 { 507 if(SoulCount < 36) 508 { 509 if(SummonSoulTimer < diff) 510 { 511 SummonSoul(); 512 SummonSoulTimer = 500; 513 }else SummonSoulTimer -= diff; 514 } 515 516 if(SoulDeathCount >= SoulCount) 517 { 518 if(AnimationTimer < diff) 519 { 520 // Release the cube 521 m_creature->SetUInt32Value(UNIT_NPC_EMOTESTATE,374); 522 AnimationTimer = 10000; 523 }else AnimationTimer -= diff; 524 525 if(SummonEssenceTimer < diff) 526 { 527 // Ribs: open 528 m_creature->SetUInt32Value(UNIT_NPC_EMOTESTATE,373); 529 Creature* EssenceAnger = NULL; 530 EssenceAnger = m_creature->SummonCreature(23420, m_creature->GetPositionX(), m_creature->GetPositionY(), m_creature->GetPositionZ(), 1.57, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, 45000); 531 532 if(EssenceAnger) 533 { 534 Unit* target = SelectUnit(SELECT_TARGET_TOPAGGRO, 0); 535 if(target) 536 { 537 EssenceAnger->AddThreat(target, 1.0f); 538 EssenceAnger->AI()->AttackStart(target); 539 } 540 AngerGUID = EssenceAnger->GetGUID(); 541 DoPlaySoundToSet(m_creature, ANGER_SOUND_FREED); 542 EssenceAnger->Yell(ANGER_SAY_FREED, LANG_UNIVERSAL, 0); 543 SoulDeathCount = 0; 544 } 545 546 Phase = 6; 547 }else SummonEssenceTimer -= diff; 548 } 549 } 550 551 if(Phase == 6) 552 { 553 if(AngerGUID) 554 { 555 Creature* EssenceAnger = NULL; 556 EssenceAnger = ((Creature*)Unit::GetUnit((*m_creature), AngerGUID)); 557 558 if(!EssenceAnger) 559 EnterEvadeMode(); 560 561 if(m_creature->isAlive() && EssenceAnger) 562 { 563 if(!EssenceAnger->isAlive()) 564 { 565 AngerGUID = 0; 566 m_creature->DealDamage(m_creature, m_creature->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); 567 } 568 } 569 } 570 } 337 return; 338 default: 339 break; 340 } 341 Counter++; 342 }else Timer -= diff; 571 343 } 572 344 }; … … 594 366 uint32 EnrageTimer; 595 367 uint32 SoulDrainTimer; 368 uint32 AuraTimer; 596 369 597 370 void Reset() … … 600 373 601 374 AggroYellTimer = 5000; 602 FixateTimer = 5000;375 FixateTimer = 8000; 603 376 EnrageTimer = 30000; 604 SoulDrainTimer = 150000; 377 SoulDrainTimer = 45000; 378 AuraTimer = 5000; 605 379 } 606 380 607 381 void DamageTaken(Unit *done_by, uint32 &damage) 608 382 { 609 if( (damage >= m_creature->GetHealth()) && (done_by != m_creature))383 if(damage >= m_creature->GetHealth()) 610 384 { 611 385 damage = 0; 612 // 10% of total health, signalling time to return 613 m_creature->SetHealth(m_creature->GetMaxHealth()/10); 614 if(StatAuraGUID) 615 { 616 Unit* pUnit = Unit::GetUnit((*m_creature), StatAuraGUID); 617 if(pUnit) 618 pUnit->RemoveAurasDueToSpell(AURA_OF_SUFFERING_ARMOR); 619 } 386 m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); 387 m_creature->Yell(SUFF_SAY_RECAP,LANG_UNIVERSAL,0); 388 DoPlaySoundToSet(m_creature, SUFF_SOUND_RECAP); 620 389 } 621 390 } … … 623 392 void Aggro(Unit *who) 624 393 { 394 m_creature->Yell(SUFF_SAY_FREED, LANG_UNIVERSAL, 0); 395 DoPlaySoundToSet(m_creature, SUFF_SOUND_FREED); 625 396 DoZoneInCombat(); 626 DoCast(who, AURA_OF_SUFFERING, true); 627 DoCast(m_creature, ESSENCE_OF_SUFFERING_PASSIVE, true); 397 m_creature->CastSpell(m_creature, AURA_OF_SUFFERING, true); // linked aura need core support 398 m_creature->CastSpell(m_creature, ESSENCE_OF_SUFFERING_PASSIVE, true); 399 m_creature->CastSpell(m_creature, ESSENCE_OF_SUFFERING_PASSIVE2, true); 628 400 } 629 401 630 402 void KilledUnit(Unit *victim) 631 403 { 632 switch(rand()%3) 633 { 634 case 0: 635 DoYell(SUFF_SAY_SLAY1,LANG_UNIVERSAL,NULL); 636 DoPlaySoundToSet(m_creature, SUFF_SOUND_SLAY1); 637 break; 638 case 1: 639 DoYell(SUFF_SAY_SLAY2,LANG_UNIVERSAL,NULL); 640 DoPlaySoundToSet(m_creature, SUFF_SOUND_SLAY2); 641 break; 642 case 2: 643 DoYell(SUFF_SAY_SLAY3,LANG_UNIVERSAL,NULL); 644 DoPlaySoundToSet(m_creature, SUFF_SOUND_SLAY3); 645 break; 646 } 647 } 648 649 void JustDied(Unit* killer) 650 { 404 switch(rand()%2) 405 { 406 case 0: 407 DoYell(SUFF_SAY_SLAY1,LANG_UNIVERSAL,NULL); 408 DoPlaySoundToSet(m_creature, SUFF_SOUND_SLAY1); 409 break; 410 case 1: 411 DoYell(SUFF_SAY_SLAY2,LANG_UNIVERSAL,NULL); 412 DoPlaySoundToSet(m_creature, SUFF_SOUND_SLAY2); 413 break; 414 } 651 415 } 652 416 … … 655 419 std::list<HostilReference*>& m_threatlist = m_creature->getThreatManager().getThreatList(); 656 420 if(m_threatlist.empty()) 657 return; 421 return; // No point continuing if empty threatlist. 658 422 std::list<Unit*> targets; 659 423 std::list<HostilReference*>::iterator itr = m_threatlist.begin(); … … 661 425 { 662 426 Unit* pUnit = Unit::GetUnit((*m_creature), (*itr)->getUnitGuid()); 663 // Only alive players 664 if(pUnit && pUnit->isAlive() && (pUnit->GetTypeId() == TYPEID_PLAYER)) 427 if(pUnit && pUnit->isAlive() && (pUnit->GetTypeId() == TYPEID_PLAYER)) // Only alive players 665 428 targets.push_back(pUnit); 666 429 } 667 430 if(targets.empty()) 668 return; // No targets added for some reason. No point continuing. 669 targets.sort(TargetDistanceOrder(m_creature)); // Sort players by distance. 670 targets.resize(1); // Only need closest target. 671 Unit* target = targets.front(); // Get the first target. 672 // Add threat equivalent to threat on victim. 673 m_creature->AddThreat(target, m_creature->getThreatManager().getThreat(m_creature->getVictim())); 674 DoCast(target, SPELL_FIXATE); 431 return; // No targets added for some reason. No point continuing. 432 targets.sort(TargetDistanceOrder(m_creature)); // Sort players by distance. 433 targets.resize(1); // Only need closest target. 434 Unit* target = targets.front(); // Get the first target. 435 target->CastSpell(m_creature, SPELL_FIXATE_TAUNT, true); 675 436 } 676 437 … … 678 439 { 679 440 //Return since we have no target 680 if (!m_creature->SelectHostilTarget() ||!m_creature->getVictim())441 if (!m_creature->SelectHostilTarget() && !m_creature->getVictim()) 681 442 return; 682 683 if(m_creature->GetHealth() <= (m_creature->GetMaxHealth()*0.1))684 {685 if(StatAuraGUID)686 {687 Unit* pUnit = NULL;688 pUnit = Unit::GetUnit((*m_creature), StatAuraGUID);689 if(pUnit)690 pUnit->RemoveAurasDueToSpell(AURA_OF_SUFFERING_ARMOR);691 }692 }693 694 if(m_creature->GetHealth() <= (m_creature->GetMaxHealth()*0.1))695 {696 if(m_creature->getVictim())697 m_creature->DeleteThreatList(); // Delete our threatlist if below 10% as we should no longer attack.698 return;699 }700 701 // Prevent overlapping yells702 if(AggroYellTimer)703 if(AggroYellTimer < diff)704 {705 DoYell(SUFF_SAY_AGGRO, LANG_UNIVERSAL, NULL);706 DoPlaySoundToSet(m_creature, SUFF_SOUND_AGGRO);707 AggroYellTimer = 0;708 }else AggroYellTimer -= diff;709 443 710 444 //Supposed to be cast on nearest target … … 713 447 CastFixate(); 714 448 FixateTimer = 5000; 449 if(!(rand()%16)) 450 { 451 DoYell(SUFF_SAY_AGGRO,LANG_UNIVERSAL,NULL); 452 DoPlaySoundToSet(m_creature, SUFF_SOUND_AGGRO); 453 } 715 454 }else FixateTimer -= diff; 716 455 … … 719 458 DoCast(m_creature, SPELL_ENRAGE); 720 459 EnrageTimer = 60000; 460 DoYell(SUFF_SAY_ENRAGE,LANG_UNIVERSAL,NULL); 461 DoPlaySoundToSet(m_creature, SUFF_SOUND_ENRAGE); 721 462 }else EnrageTimer -= diff; 722 463 723 464 if(SoulDrainTimer < diff) 724 465 { 725 Unit* target = NULL; 726 target = SelectUnit(SELECT_TARGET_RANDOM, 0); 727 728 if(target) 729 DoCast(target, SPELL_SOUL_DRAIN); 466 DoCast(m_creature, SPELL_SOUL_DRAIN); 730 467 SoulDrainTimer = 60000; 731 468 }else SoulDrainTimer -= diff; … … 734 471 } 735 472 }; 473 736 474 struct TRINITY_DLL_DECL boss_essence_of_desireAI : public ScriptedAI 737 475 { 738 476 boss_essence_of_desireAI(Creature *c) : ScriptedAI(c) {Reset();} 739 477 740 uint32 AggroYellTimer;741 478 uint32 RuneShieldTimer; 742 479 uint32 DeadenTimer; … … 745 482 void Reset() 746 483 { 747 AggroYellTimer = 5000;748 484 RuneShieldTimer = 60000; 749 DeadenTimer = 15000; 750 SoulShockTimer = 40000; 485 DeadenTimer = 30000; 486 SoulShockTimer = 5000; 487 m_creature->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_MOD_CONFUSE, true); 751 488 } 752 489 753 490 void DamageTaken(Unit *done_by, uint32 &damage) 754 491 { 755 if((damage >= m_creature->GetHealth()) && (done_by != m_creature)) 492 if(done_by == m_creature) 493 return; 494 495 if(damage >= m_creature->GetHealth()) 756 496 { 757 497 damage = 0; 758 // 10% of total health, signalling time to return 759 m_creature->SetHealth(m_creature->GetMaxHealth()/10); 498 m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); 499 m_creature->Yell(DESI_SAY_RECAP,LANG_UNIVERSAL,0); 500 DoPlaySoundToSet(m_creature, DESI_SOUND_RECAP); 760 501 } 761 502 else 762 503 { 763 if(done_by && (done_by->GetTypeId() == TYPEID_PLAYER) && done_by->isAlive()) 764 done_by->DealDamage(done_by, damage/2, NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); 765 } 766 } 767 768 void Aggro(Unit *who) { DoZoneInCombat(); } 504 int32 bp0 = damage / 2; 505 m_creature->CastCustomSpell(done_by, AURA_OF_DESIRE_DAMAGE, &bp0, NULL, NULL, true); 506 } 507 } 508 509 void SpellHit(Unit *caster, const SpellEntry *spell) 510 { 511 if(m_creature->m_currentSpells[CURRENT_GENERIC_SPELL]) 512 for(uint8 i = 0; i < 3; ++i) 513 if(spell->Effect[i] == SPELL_EFFECT_INTERRUPT_CAST) 514 if(m_creature->m_currentSpells[CURRENT_GENERIC_SPELL]->m_spellInfo->Id == SPELL_SOUL_SHOCK 515 || m_creature->m_currentSpells[CURRENT_GENERIC_SPELL]->m_spellInfo->Id == SPELL_DEADEN) 516 m_creature->InterruptSpell(CURRENT_GENERIC_SPELL, false); 517 } 518 519 void Aggro(Unit *who) 520 { 521 m_creature->Yell(DESI_SAY_FREED, LANG_UNIVERSAL, 0); 522 DoPlaySoundToSet(m_creature, DESI_SOUND_FREED); 523 DoZoneInCombat(); 524 DoCast(m_creature, AURA_OF_DESIRE, true); 525 } 769 526 770 527 void KilledUnit(Unit *victim) … … 772 529 switch(rand()%3) 773 530 { 774 775 776 777 778 779 780 781 782 783 784 785 786 } 787 } 788 789 void MoveInLineOfSight(Unit *who)790 { 791 if (! who ||m_creature->getVictim())531 case 0: 532 DoYell(DESI_SAY_SLAY1,LANG_UNIVERSAL,NULL); 533 DoPlaySoundToSet(m_creature, DESI_SOUND_SLAY1); 534 break; 535 case 1: 536 DoYell(DESI_SAY_SLAY2,LANG_UNIVERSAL,NULL); 537 DoPlaySoundToSet(m_creature, DESI_SOUND_SLAY2); 538 break; 539 case 2: 540 DoYell(DESI_SAY_SLAY3,LANG_UNIVERSAL,NULL); 541 DoPlaySoundToSet(m_creature, DESI_SOUND_SLAY3); 542 break; 543 } 544 } 545 546 void UpdateAI(const uint32 diff) 547 { 548 if (!m_creature->SelectHostilTarget() && !m_creature->getVictim()) 792 549 return; 793 550 794 if (who->isTargetableForAttack() && who->isInAccessablePlaceFor(m_creature) && m_creature->IsHostileTo(who))795 {796 float attackRadius = m_creature->GetAttackDistance(who);797 if (m_creature->IsWithinDistInMap(who, attackRadius) && m_creature->GetDistanceZ(who) <= CREATURE_Z_ATTACK_RANGE && m_creature->IsWithinLOSInMap(who))798 {799 if(who->HasStealthAura())800 who->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH);801 802 //Begin melee attack if we are within range803 DoStartAttackAndMovement(who);804 805 if (!InCombat)806 {807 DoCast(who, AURA_OF_DESIRE);808 }809 }810 }811 }812 813 void UpdateAI(const uint32 diff)814 {815 //Return since we have no target816 if (!m_creature->SelectHostilTarget() || !m_creature->getVictim())817 return;818 819 if(m_creature->GetHealth() <= (m_creature->GetMaxHealth()*0.1))820 {821 if(m_creature->getVictim())822 m_creature->DeleteThreatList(); // Delete our threatlist if below 10% as we should no longer attack.823 return;824 }825 826 551 if(RuneShieldTimer < diff) 827 552 { 828 DoCast(m_creature, SPELL_RUNE_SHIELD); 553 m_creature->InterruptNonMeleeSpells(false); 554 m_creature->CastSpell(m_creature, SPELL_RUNE_SHIELD, true); 555 SoulShockTimer += 2000; 556 DeadenTimer += 2000; 829 557 RuneShieldTimer = 60000; 830 558 }else RuneShieldTimer -= diff; 831 559 560 if(SoulShockTimer < diff) 561 { 562 DoCast(m_creature->getVictim(), SPELL_SOUL_SHOCK); 563 SoulShockTimer = 5000; 564 }else SoulShockTimer -= diff; 565 832 566 if(DeadenTimer < diff) 833 567 { 568 m_creature->InterruptNonMeleeSpells(false); 834 569 DoCast(m_creature->getVictim(), SPELL_DEADEN); 835 DeadenTimer = 30000 + rand()%30001; 836 }else DeadenTimer -= diff; 837 838 if(SoulShockTimer < diff) 839 { 840 DoCast(m_creature->getVictim(), SPELL_SOUL_SHOCK); 841 SoulShockTimer = 40000; 842 if(rand()%2 == 0) 570 DeadenTimer = 25000 + rand()%10000; 571 if(!(rand()%2)) 843 572 { 844 573 DoYell(DESI_SAY_SPEC,LANG_UNIVERSAL,NULL); 845 574 DoPlaySoundToSet(m_creature, DESI_SOUND_SPEC); 846 575 } 847 848 }else SoulShockTimer -= diff; 576 }else DeadenTimer -= diff; 849 577 850 578 DoMeleeAttackIfReady(); … … 858 586 uint64 AggroTargetGUID; 859 587 860 uint32 AggroYellTimer;861 588 uint32 CheckTankTimer; 862 589 uint32 SoulScreamTimer; 863 590 uint32 SpiteTimer; 864 591 592 std::list<uint64> SpiteTargetGUID; 593 865 594 bool CheckedAggro; 866 595 … … 869 598 AggroTargetGUID = 0; 870 599 871 AggroYellTimer = 5000;872 600 CheckTankTimer = 5000; 873 601 SoulScreamTimer = 10000; 874 602 SpiteTimer = 30000; 875 603 604 SpiteTargetGUID.clear(); 605 876 606 CheckedAggro = false; 877 607 } … … 879 609 void Aggro(Unit *who) 880 610 { 611 m_creature->Yell(ANGER_SAY_FREED, LANG_UNIVERSAL, 0); 612 DoPlaySoundToSet(m_creature, ANGER_SOUND_FREED); 881 613 DoZoneInCombat(); 882 DoCast(m_creature->getVictim(), AURA_OF_ANGER, true); 883 } 884 885 void MoveInLineOfSight(Unit *who) 886 { 887 if (!who || m_creature->getVictim()) 888 return; 889 890 if (who->isTargetableForAttack() && who->isInAccessablePlaceFor(m_creature) && m_creature->IsHostileTo(who)) 891 { 892 float attackRadius = m_creature->GetAttackDistance(who); 893 if (m_creature->IsWithinDistInMap(who, attackRadius) && m_creature->GetDistanceZ(who) <= CREATURE_Z_ATTACK_RANGE && m_creature->IsWithinLOSInMap(who)) 894 { 895 if(who->HasStealthAura()) 896 who->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH); 897 898 //Begin melee attack if we are within range 899 DoStartAttackAndMovement(who); 900 901 if (!InCombat) 902 { 903 DoCast(who, AURA_OF_ANGER); 904 } 905 } 906 } 614 DoCast(m_creature, AURA_OF_ANGER, true); 907 615 } 908 616 … … 917 625 switch(rand()%2) 918 626 { 919 case 0: 920 DoPlaySoundToSet(m_creature, ANGER_SOUND_SLAY1); 921 break; 922 case 1: 923 DoYell(ANGER_SAY_SLAY2,LANG_UNIVERSAL,NULL); 924 DoPlaySoundToSet(m_creature, ANGER_SOUND_SLAY2); 925 break; 926 } 627 case 0: 628 DoPlaySoundToSet(m_creature, ANGER_SOUND_SLAY1); 629 break; 630 case 1: 631 DoYell(ANGER_SAY_SLAY2,LANG_UNIVERSAL,NULL); 632 DoPlaySoundToSet(m_creature, ANGER_SOUND_SLAY2); 633 break; 634 } 635 } 636 637 void SelectSpiteTarget(uint32 num, float max_range = 999) 638 { 639 if(!num) return; 640 641 CellPair p(Trinity::ComputeCellPair(m_creature->GetPositionX(), m_creature->GetPositionY())); 642 Cell cell(p); 643 cell.data.Part.reserved = ALL_DISTRICT; 644 cell.SetNoCreate(); 645 646 std::list<Unit *> tempUnitMap; 647 648 { 649 Trinity::AnyAoETargetUnitInObjectRangeCheck u_check(m_creature, m_creature, max_range); 650 Trinity::UnitListSearcher<Trinity::AnyAoETargetUnitInObjectRangeCheck> searcher(tempUnitMap, u_check); 651 652 TypeContainerVisitor<Trinity::UnitListSearcher<Trinity::AnyAoETargetUnitInObjectRangeCheck>, WorldTypeMapContainer > world_unit_searcher(searcher); 653 TypeContainerVisitor<Trinity::UnitListSearcher<Trinity::AnyAoETargetUnitInObjectRangeCheck>, GridTypeMapContainer > grid_unit_searcher(searcher); 654 655 CellLock<GridReadGuard> cell_lock(cell, p); 656 cell_lock->Visit(cell_lock, world_unit_searcher, *(m_creature->GetMap())); 657 cell_lock->Visit(cell_lock, grid_unit_searcher, *(m_creature->GetMap())); 658 } 659 660 std::list<Unit*>::iterator itr; 661 while(tempUnitMap.size() && SpiteTargetGUID.size() < num) 662 { 663 itr = tempUnitMap.begin(); 664 advance(itr, rand()%tempUnitMap.size()); 665 SpiteTargetGUID.push_back((*itr)->GetGUID()); 666 tempUnitMap.erase(itr); 667 } 668 669 for(itr = tempUnitMap.begin(); itr != tempUnitMap.end(); ++itr) 670 (*itr)->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); 671 m_creature->CastSpell(m_creature, SPELL_SPITE_TARGET, true); // must true 672 for(itr = tempUnitMap.begin(); itr != tempUnitMap.end(); ++itr) 673 (*itr)->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); 927 674 } 928 675 … … 930 677 { 931 678 //Return since we have no target 932 if (!m_creature->SelectHostilTarget() ||!m_creature->getVictim())679 if (!m_creature->SelectHostilTarget() && !m_creature->getVictim()) 933 680 return; 934 681 … … 939 686 } 940 687 941 if(AggroYellTimer)942 if(AggroYellTimer < diff)943 {944 DoYell(ANGER_SAY_FREED2,LANG_UNIVERSAL,NULL);945 DoPlaySoundToSet(m_creature, ANGER_SOUND_FREED2);946 AggroYellTimer = 0;947 }else AggroYellTimer -= diff;948 949 688 if(CheckTankTimer < diff) 950 689 { 951 690 if(m_creature->getVictim()->GetGUID() != AggroTargetGUID) 952 { 691 { 953 692 DoYell(ANGER_SAY_BEFORE,LANG_UNIVERSAL,NULL); 954 693 DoPlaySoundToSet(m_creature, ANGER_SOUND_BEFORE); 955 DoCast(m_creature, SPELL_SELF_SEETHE); 956 DoCast(m_creature->getVictim(), SPELL_ENEMY_SEETHE, true); 694 DoCast(m_creature, SPELL_SELF_SEETHE, true); 957 695 AggroTargetGUID = m_creature->getVictim()->GetGUID(); 958 696 } … … 964 702 DoCast(m_creature->getVictim(), SPELL_SOUL_SCREAM); 965 703 SoulScreamTimer = 10000; 704 if(!(rand()%3)) 705 { 706 DoYell(ANGER_SAY_SCREAM,LANG_UNIVERSAL,NULL); 707 DoPlaySoundToSet(m_creature, ANGER_SOUND_SCREAM); 708 } 966 709 }else SoulScreamTimer -= diff; 967 710 968 711 if(SpiteTimer < diff) 969 712 { 970 for(uint8 i = 0; i < 4; i++)713 if(!SpiteTargetGUID.empty()) 971 714 { 972 Unit* target = NULL; 973 target = SelectUnit(SELECT_TARGET_RANDOM, 0); 974 975 if(target) 976 DoCast(target, SPELL_SPITE); 977 978 } 979 980 SpiteTimer = 30000; 981 DoYell(ANGER_SAY_SPEC,LANG_UNIVERSAL,NULL); 982 DoPlaySoundToSet(m_creature, ANGER_SOUND_SPEC); 715 for (std::list<uint64>::iterator itr = SpiteTargetGUID.begin(); itr != SpiteTargetGUID.end(); ++itr) 716 { 717 if(Unit* target = Unit::GetUnit(*m_creature, *itr)) 718 { 719 target->RemoveAurasDueToSpell(SPELL_SPITE_TARGET); 720 m_creature->CastSpell(target, SPELL_SPITE_DAMAGE, true); 721 } 722 } 723 SpiteTargetGUID.clear(); 724 SpiteTimer = 24000; 725 } 726 else 727 { 728 SelectSpiteTarget(3); 729 SpiteTimer = 6000; 730 DoYell(ANGER_SAY_SPEC,LANG_UNIVERSAL,NULL); 731 DoPlaySoundToSet(m_creature, ANGER_SOUND_SPEC); 732 } 983 733 }else SpiteTimer -= diff; 984 734 … … 995 745 ((boss_reliquary_of_soulsAI*)Reliquary->AI())->SoulDeathCount++; 996 746 } 747 DoCast(m_creature, SPELL_SOUL_RELEASE, true); 997 748 } 998 749 -
trunk/src/bindings/scripts/scripts/zone/black_temple/boss_supremus.cpp
r48 r57 117 117 FireballTimer = 500; 118 118 GeyserTimer = 0; 119 m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_DISABLE_MOVE); 120 m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); 119 121 } 120 122 … … 122 124 void AttackStart(Unit* who) {} 123 125 void MoveInLineOfSight(Unit* who) {} 124 void SetSupremusGUID(uint64 guid) { SupremusGUID = guid; }125 126 126 127 void UpdateAI(const uint32 diff) 127 128 { 128 if(CheckTimer < diff)129 {130 if(SupremusGUID)131 {132 Unit* Supremus = NULL;133 Supremus = Unit::GetUnit((*m_creature), SupremusGUID);134 if(Supremus && (!Supremus->isAlive()))135 m_creature->DealDamage(m_creature, m_creature->GetHealth(), 0, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false);136 }137 CheckTimer = 2000;138 }else CheckTimer -= diff;139 140 129 if(GeyserTimer < diff) 141 130 { … … 143 132 GeyserTimer = 18000; 144 133 }else GeyserTimer -= diff; 134 135 if(FireballTimer < diff) 136 { 137 DoCast(m_creature, SPELL_VOLCANIC_FIREBALL, true); 138 FireballTimer = 1000; 139 }else FireballTimer -= diff; 145 140 } 146 141 }; … … 272 267 if(BerserkTimer < diff) 273 268 DoCast(m_creature, SPELL_BERSERK); 274 else BerserkTimer -= diff;269 else BerserkTimer -= diff; 275 270 276 271 if(SummonFlameTimer < diff) … … 333 328 if(target) 334 329 { 335 Creature* Volcano = NULL; 336 Volcano = SummonCreature(CREATURE_VOLCANO, target); 337 338 if(Volcano) 339 { 340 DoCast(target, SPELL_VOLCANIC_ERUPTION); 341 ((npc_volcanoAI*)Volcano->AI())->SetSupremusGUID(m_creature->GetGUID()); 342 } 343 330 DoCast(target, SPELL_VOLCANIC_ERUPTION); 344 331 DoTextEmote("roars and the ground begins to crack open!", NULL); 345 332 SummonVolcanoTimer = 10000; … … 356 343 PhaseSwitchTimer = 60000; 357 344 m_creature->SetSpeed(MOVE_RUN, 1.0f); 345 DoZoneInCombat(); 358 346 } 359 347 else … … 365 353 PhaseSwitchTimer = 60000; 366 354 m_creature->SetSpeed(MOVE_RUN, 0.9f); 355 DoZoneInCombat(); 367 356 } 368 357 }else PhaseSwitchTimer -= diff; -
trunk/src/bindings/scripts/scripts/zone/black_temple/boss_warlord_najentus.cpp
r48 r57 17 17 /* ScriptData 18 18 SDName: Boss_Warlord_Najentus 19 SD%Complete: 9 020 SDComment: Using a creature workaround instead of a GO for Impaling Spine.19 SD%Complete: 95 20 SDComment: 21 21 SDCategory: Black Temple 22 22 EndScriptData */ … … 59 59 60 60 //Spells 61 #define SPELL_CRASHINGWAVE 4010062 61 #define SPELL_NEEDLE_SPINE 39835 63 62 #define SPELL_NEEDLE_AOE 39968 64 63 #define SPELL_TIDAL_BURST 39878 65 #define SPELL_TIDAL_SHIELD 39872 // Not going to use this since Hurl Spine doesn't dispel it.64 #define SPELL_TIDAL_SHIELD 39872 66 65 #define SPELL_IMPALING_SPINE 39837 67 66 #define SPELL_CREATE_NAJENTUS_SPINE 39956 68 67 #define SPELL_HURL_SPINE 39948 69 #define SPELL_SHIELD_VISUAL 3713670 68 #define SPELL_BERSERK 45078 71 69 72 #define DISPLAYID_SPINE 7362 73 74 struct TRINITY_DLL_DECL mob_najentus_spineAI : public ScriptedAI 75 { 76 mob_najentus_spineAI(Creature *c) : ScriptedAI(c) 77 { 78 Reset(); 79 } 80 81 uint64 SpineVictimGUID; 82 83 void Reset() { SpineVictimGUID = 0; } 84 85 void SetSpineVictimGUID(uint64 guid){ SpineVictimGUID = guid; } 86 87 void JustDied(Unit *killer) 88 { 89 // Make the killer have the Najentus Spine item to pierce Tidal Shield 90 if(killer) 91 killer->CastSpell(killer, SPELL_CREATE_NAJENTUS_SPINE, true); 92 } 93 94 void DamageTaken(Unit *done_by, uint32 &damage) 95 { 96 if(damage < m_creature->GetHealth()) return; 97 98 // Remove the Impaling Spine DoT from whoever was affected 99 if(SpineVictimGUID) 100 { 101 Unit* victim = Unit::GetUnit((*m_creature), SpineVictimGUID); 102 if(victim && ((victim->HasAura(SPELL_IMPALING_SPINE, 0)) || (victim->HasAura(SPELL_IMPALING_SPINE, 1)) || (victim->HasAura(SPELL_IMPALING_SPINE, 2)))) 103 victim->RemoveAurasDueToSpell(SPELL_IMPALING_SPINE); 104 } 105 } 106 107 void Aggro(Unit* who) {} 108 void AttackStart(Unit* who) {} 109 void MoveInLineOfSight(Unit* who) {} 110 void UpdateAI(const uint32 diff) {} 111 }; 70 #define GOBJECT_SPINE 185584 112 71 113 72 struct TRINITY_DLL_DECL boss_najentusAI : public ScriptedAI 114 73 { 115 boss_najentusAI(Creature *c) : ScriptedAI(c) 74 boss_najentusAI(Creature *c) : ScriptedAI(c) 116 75 { 117 76 pInstance = ((ScriptedInstance*)c->GetInstanceData()); … … 120 79 121 80 ScriptedInstance* pInstance; 122 uint32 CrashingWaveTimer; 81 123 82 uint32 NeedleSpineTimer; 124 83 uint32 EnrageTimer; … … 126 85 uint32 TidalShieldTimer; 127 86 uint32 ImpalingSpineTimer; 128 uint32 CheckTimer; // This timer checks if Najentus is Tidal Shielded and if so, regens health. If not, sets IsShielded to false129 uint32 DispelShieldTimer; // This shield is only supposed to last 30 seconds, but the SPELL_SHIELD_VISUAL lasts forever130 87 131 88 uint64 SpineTargetGUID; 132 uint64 SpineGUID;133 134 bool IsShielded;135 89 136 90 void Reset() 137 91 { 138 IsShielded = false;139 140 CrashingWaveTimer = 28000;141 NeedleSpineTimer = 10000;142 92 EnrageTimer = 480000; 143 93 SpecialYellTimer = 45000 + (rand()%76)*1000; 144 TidalShieldTimer = 60000; 145 ImpalingSpineTimer = 45000; 146 CheckTimer = 2000; 147 DispelShieldTimer = 30000; 94 95 ResetTimer(); 148 96 149 97 SpineTargetGUID = 0; 150 SpineGUID = 0;151 98 152 99 if(pInstance) 153 { 154 if(m_creature->isAlive()) 155 { 156 pInstance->SetData(DATA_HIGHWARLORDNAJENTUSEVENT, NOT_STARTED); 157 ToggleGate(true); 158 } 159 else ToggleGate(false); 100 pInstance->SetData(DATA_HIGHWARLORDNAJENTUSEVENT, NOT_STARTED); 101 } 102 103 void KilledUnit(Unit *victim) 104 { 105 switch(rand()%2) 106 { 107 case 0: 108 DoYell(SAY_SLAY1,LANG_UNIVERSAL,NULL); 109 DoPlaySoundToSet(m_creature, SOUND_SLAY1); 110 break; 111 case 1: 112 DoYell(SAY_SLAY2,LANG_UNIVERSAL,NULL); 113 DoPlaySoundToSet(m_creature, SOUND_SLAY2); 114 break; 160 115 } 161 116 } 162 117 163 void KilledUnit(Unit *victim)164 {165 switch(rand()%2)166 {167 case 0:168 DoYell(SAY_SLAY1,LANG_UNIVERSAL,NULL);169 DoPlaySoundToSet(m_creature, SOUND_SLAY1);170 break;171 case 1:172 DoYell(SAY_SLAY2,LANG_UNIVERSAL,NULL);173 DoPlaySoundToSet(m_creature, SOUND_SLAY2);174 break;175 }176 }177 178 118 void JustDied(Unit *victim) 179 119 { 180 120 if(pInstance) 181 {182 121 pInstance->SetData(DATA_HIGHWARLORDNAJENTUSEVENT, DONE); 183 ToggleGate(false);184 }185 122 186 123 DoYell(SAY_DEATH, LANG_UNIVERSAL, NULL); … … 188 125 } 189 126 190 void ToggleGate(bool close)191 {192 if(GameObject* Gate = GameObject::GetGameObject(*m_creature, pInstance->GetData64(DATA_GAMEOBJECT_NAJENTUS_GATE)))193 if(close) Gate->SetGoState(0); // Closed194 else Gate->SetGoState(2); // Opened195 }196 197 127 void SpellHit(Unit *caster, const SpellEntry *spell) 198 128 { 199 if(IsShielded) 200 { 201 if(spell->Id == SPELL_HURL_SPINE) 202 { 203 if(m_creature->HasAura(SPELL_SHIELD_VISUAL, 0)) 204 m_creature->RemoveAurasDueToSpell(SPELL_SHIELD_VISUAL); 205 if(m_creature->HasAura(SPELL_TIDAL_SHIELD, 0)) 206 m_creature->RemoveAurasDueToSpell(SPELL_TIDAL_SHIELD); 207 DoCast(m_creature->getVictim(), SPELL_TIDAL_BURST); 208 IsShielded = false; 209 } 129 if(spell->Id == SPELL_HURL_SPINE && m_creature->HasAura(SPELL_TIDAL_SHIELD, 0)) 130 { 131 m_creature->RemoveAurasDueToSpell(SPELL_TIDAL_SHIELD); 132 m_creature->CastSpell(m_creature, SPELL_TIDAL_BURST, true); 133 ResetTimer(); 210 134 } 211 }212 213 void DamageTaken(Unit *done_by, uint32 &damage)214 {215 if(IsShielded)216 damage = 0;217 135 } 218 136 … … 224 142 DoYell(SAY_AGGRO, LANG_UNIVERSAL, NULL); 225 143 DoPlaySoundToSet(m_creature, SOUND_AGGRO); 226 227 144 DoZoneInCombat(); 228 145 } 229 146 230 // This is a workaround since we cannot summon GameObjects at will. 231 // Instead, we create a custom creature on top of the player. 232 // When someone kills the creature, the killer gets the "Naj'entus Spine" item. 233 // This item is the only item that should be able to pierce Tidal Shield 234 void DoImpalingSpineWorkaround(Unit* target) 235 { 236 Creature* Spine = NULL; 237 Spine = m_creature->SummonCreature(500000, target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), 0, TEMPSUMMON_DEAD_DESPAWN, 10000); 238 if(Spine) 239 { 240 Spine->setFaction(m_creature->getFaction()); 241 ((mob_najentus_spineAI*)Spine->AI())->SetSpineVictimGUID(target->GetGUID()); 242 SpineTargetGUID = target->GetGUID(); 243 } 244 } 245 246 bool RemoveImpalingSpine(uint64 guid) 247 { 248 if(!IsShielded || guid == SpineTargetGUID) return false; 249 250 if(SpineTargetGUID) 251 { 252 Unit* target = Unit::GetUnit((*m_creature), SpineTargetGUID); 253 if(target && target->HasAura(SPELL_IMPALING_SPINE, 0)) 254 { 255 target->RemoveAurasDueToSpell(SPELL_IMPALING_SPINE); 256 return true; 257 } 258 } 259 260 return false; 147 bool RemoveImpalingSpine() 148 { 149 if(!SpineTargetGUID) return false; 150 Unit* target = Unit::GetUnit(*m_creature, SpineTargetGUID); 151 if(target && target->HasAura(SPELL_IMPALING_SPINE, 1)) 152 target->RemoveAurasDueToSpell(SPELL_IMPALING_SPINE); 153 SpineTargetGUID=0; 154 return true; 155 } 156 157 void ResetTimer(uint32 inc = 0) 158 { 159 NeedleSpineTimer = 10000 + inc; 160 TidalShieldTimer = 60000 + inc; 161 ImpalingSpineTimer = 20000 + inc; 261 162 } 262 163 263 164 void UpdateAI(const uint32 diff) 264 165 { 265 //Return since we have no target266 166 if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) 267 167 return; 268 168 269 if(CheckTimer < diff) 270 { 271 // if(m_creature->HasAura(SPELL_TIDAL_SHIELD, 0)) 272 if(m_creature->HasAura(SPELL_SHIELD_VISUAL, 0)) 273 m_creature->SetHealth(m_creature->GetHealth() + (m_creature->GetMaxHealth()/100)); 274 else 275 IsShielded = false; 276 277 CheckTimer = 2000; 278 }else CheckTimer -= diff; 279 280 if(IsShielded) 281 { 282 m_creature->GetMotionMaster()->Clear(false); 283 m_creature->GetMotionMaster()->MoveIdle(); 284 if(!m_creature->HasAura(SPELL_SHIELD_VISUAL, 0)) 285 DoCast(m_creature, SPELL_SHIELD_VISUAL); 286 if(DispelShieldTimer < diff) 287 { 288 m_creature->GetMotionMaster()->MoveChase(m_creature->getVictim()); 289 if(m_creature->HasAura(SPELL_SHIELD_VISUAL, 0)) 290 m_creature->RemoveAurasDueToSpell(SPELL_SHIELD_VISUAL); 291 IsShielded = false; 292 }else DispelShieldTimer -= diff; 293 294 return; // Don't cast or do anything while Shielded 295 } 296 297 // Crashing Wave 298 if(CrashingWaveTimer < diff) 299 { 300 DoCast(m_creature->getVictim(), SPELL_CRASHINGWAVE); 301 CrashingWaveTimer = 28500; 302 }else CrashingWaveTimer -= diff; 303 304 if(!m_creature->HasAura(SPELL_BERSERK, 0)) 305 if(EnrageTimer < diff) 169 if(TidalShieldTimer < diff) 170 { 171 m_creature->InterruptNonMeleeSpells(false); 172 DoCast(m_creature, SPELL_TIDAL_SHIELD, true); 173 ResetTimer(45000); 174 }else TidalShieldTimer -= diff; 175 176 if(EnrageTimer < diff) 306 177 { 307 178 DoYell(SAY_ENRAGE, LANG_UNIVERSAL, NULL); 308 179 DoPlaySoundToSet(m_creature, SOUND_ENRAGE); 309 DoCast(m_creature, SPELL_BERSERK); 180 m_creature->CastSpell(m_creature, SPELL_BERSERK, true); 181 EnrageTimer = 600000; 310 182 }else EnrageTimer -= diff; 311 183 … … 316 188 { 317 189 Unit* target = SelectUnit(SELECT_TARGET_RANDOM, 1); 318 if(!target) 319 target = m_creature->getVictim(); 320 321 DoCast(target, SPELL_NEEDLE_AOE, true); 322 DoCast(target, SPELL_NEEDLE_SPINE); 323 } 324 325 NeedleSpineTimer = 60000; 190 if(!target) target = m_creature->getVictim(); 191 m_creature->CastSpell(target, SPELL_NEEDLE_SPINE, true); 192 } 193 m_creature->SetInFront(m_creature->getVictim()); 194 NeedleSpineTimer = 30000; 326 195 }else NeedleSpineTimer -= diff; 327 196 … … 330 199 switch(rand()%2) 331 200 { 332 333 334 335 336 337 338 201 case 0: 202 DoPlaySoundToSet(m_creature, SOUND_SPECIAL1); 203 break; 204 case 1: 205 DoYell(SAY_SPECIAL2, LANG_UNIVERSAL, NULL); 206 DoPlaySoundToSet(m_creature, SOUND_SPECIAL2); 207 break; 339 208 } 340 209 SpecialYellTimer = 25000 + (rand()%76)*1000; … … 344 213 { 345 214 Unit* target = SelectUnit(SELECT_TARGET_RANDOM, 1); 346 if(!target) 347 target = m_creature->getVictim(); 348 349 if(target && (target->GetTypeId() == TYPEID_PLAYER)) 350 { 351 DoCast(target, SPELL_IMPALING_SPINE); 352 //DoImpalingSpineWorkaround(target); 353 SpineTargetGUID = target->GetGUID(); 354 ImpalingSpineTimer = 45000; 355 356 switch(rand()%2) 357 { 358 case 0: 359 DoYell(SAY_NEEDLE1, LANG_UNIVERSAL, NULL); 360 DoPlaySoundToSet(m_creature, SOUND_NEEDLE1); 361 break; 362 case 1: 363 DoYell(SAY_NEEDLE2, LANG_UNIVERSAL, NULL); 364 DoPlaySoundToSet(m_creature, SOUND_NEEDLE2); 365 break; 366 } 367 } 215 if(!target) target = m_creature->getVictim(); 216 m_creature->CastSpell(target, SPELL_IMPALING_SPINE, true); 217 m_creature->SetInFront(m_creature->getVictim()); 218 SpineTargetGUID = target->GetGUID(); 219 m_creature->SummonGameObject(GOBJECT_SPINE, target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), m_creature->GetOrientation(), 0, 0, 0, 0, 30); 220 221 switch(rand()%2) 222 { 223 case 0: 224 DoYell(SAY_NEEDLE1, LANG_UNIVERSAL, NULL); 225 DoPlaySoundToSet(m_creature, SOUND_NEEDLE1); 226 break; 227 case 1: 228 DoYell(SAY_NEEDLE2, LANG_UNIVERSAL, NULL); 229 DoPlaySoundToSet(m_creature, SOUND_NEEDLE2); 230 break; 231 } 232 ImpalingSpineTimer = 21000; 368 233 }else ImpalingSpineTimer -= diff; 369 234 370 if(TidalShieldTimer < diff)371 {372 m_creature->InterruptNonMeleeSpells(false);373 DoCast(m_creature, SPELL_SHIELD_VISUAL, true);374 // DoCast(m_creature, SPELL_TIDAL_SHIELD);375 m_creature->GetMotionMaster()->Clear(false);376 m_creature->GetMotionMaster()->MoveIdle();377 IsShielded = true;378 TidalShieldTimer = 60000;379 CheckTimer = 2000;380 DispelShieldTimer = 30000;381 }else TidalShieldTimer -= diff;382 383 235 DoMeleeAttackIfReady(); 384 236 } … … 387 239 bool GOHello_go_najentus_spine(Player *player, GameObject* _GO) 388 240 { 389 ScriptedInstance* pInstance = ((ScriptedInstance*)_GO->GetInstanceData()); 390 if(pInstance) 391 { 392 uint64 NajentusGUID = pInstance->GetData64(DATA_HIGHWARLORDNAJENTUS); 393 if(NajentusGUID) 394 { 395 Creature* Najentus = ((Creature*)Unit::GetUnit((*_GO), NajentusGUID)); 396 if(Najentus) 397 { 398 if(((boss_najentusAI*)Najentus->AI())->RemoveImpalingSpine(player->GetGUID())) 399 return true; 400 }else error_log("ERROR: Na'entus Spine GameObject unable to find Naj'entus"); 401 }else error_log("ERROR: Invalid GUID acquired for Naj'entus by Naj'entus Spine GameObject"); 402 } 403 else error_log("ERROR: Naj'entus Spine spawned in invalid instance or location"); 404 241 if(ScriptedInstance* pInstance = (ScriptedInstance*)_GO->GetInstanceData()) 242 if(Creature* Najentus = (Creature*)Unit::GetUnit(*_GO, pInstance->GetData64(DATA_HIGHWARLORDNAJENTUS))) 243 if(((boss_najentusAI*)Najentus->AI())->RemoveImpalingSpine()) 244 { 245 player->CastSpell(player, SPELL_CREATE_NAJENTUS_SPINE, true); 246 _GO->SetLootState(GO_NOT_READY); 247 _GO->SetRespawnTime(0); 248 } 405 249 return true; 406 }407 408 CreatureAI* GetAI_mob_najentus_spine(Creature *_Creature)409 {410 return new mob_najentus_spineAI (_Creature);411 250 } 412 251 … … 425 264 426 265 newscript = new Script; 427 newscript->Name = "mob_najentus_spine";428 newscript->GetAI = GetAI_mob_najentus_spine;429 m_scripts[nrscripts++] = newscript;430 431 newscript = new Script;432 266 newscript->Name = "go_najentus_spine"; 433 267 newscript->pGOHello = &GOHello_go_najentus_spine; -
trunk/src/bindings/scripts/scripts/zone/black_temple/instance_black_temple.cpp
r48 r57 127 127 case 185905: // Gate leading to Temple Summit 128 128 IllidanGate = go->GetGUID(); 129 go->SetUInt32Value(GAMEOBJECT_FLAGS,GO_FLAG_NODESPAWN+GO_FLAG_INTERACT_COND); 129 130 break; 130 131 case 186261: // Right door at Temple Summit 131 132 IllidanDoor[0] = go->GetGUID(); 133 go->SetUInt32Value(GAMEOBJECT_FLAGS,GO_FLAG_NODESPAWN+GO_FLAG_INTERACT_COND); 132 134 break; 133 135 case 186262: // Left door at Temple Summit 134 136 IllidanDoor[1] = go->GetGUID(); 137 go->SetUInt32Value(GAMEOBJECT_FLAGS,GO_FLAG_NODESPAWN+GO_FLAG_INTERACT_COND); 135 138 break; 136 139 } -
trunk/src/bindings/scripts/scripts/zone/karazhan/boss_maiden_of_virtue.cpp
r48 r57 28 28 #define SPELL_HOLYWRATH 32445 29 29 #define SPELL_HOLYGROUND 29512 30 #define SPELL_BERSERK 26662 30 31 31 32 #define SAY_AGGRO "Your behavior will not be tolerated!" … … 53 54 uint32 Holywrath_Timer; 54 55 uint32 Holyground_Timer; 56 uint32 Enrage_Timer; 57 58 bool Enraged; 55 59 56 60 void Reset() … … 60 64 Holywrath_Timer = 20000+(rand()%10000); 61 65 Holyground_Timer = 3000; 66 Enrage_Timer = 600000; 67 68 Enraged = false; 69 70 m_creature->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_MOD_TAUNT, true); 71 m_creature->ApplySpellImmune(1, IMMUNITY_EFFECT,SPELL_EFFECT_ATTACK_ME, true); 62 72 } 63 73 … … 68 78 switch(rand()%3) 69 79 { 70 71 72 73 74 75 76 77 78 79 80 81 80 case 0: 81 DoYell(SAY_SLAY1,LANG_UNIVERSAL,Victim); 82 DoPlaySoundToSet(m_creature, SOUND_SLAY1); 83 break; 84 case 1: 85 DoYell(SAY_SLAY2,LANG_UNIVERSAL,Victim); 86 DoPlaySoundToSet(m_creature, SOUND_SLAY2); 87 break; 88 case 2: 89 DoYell(SAY_SLAY3,LANG_UNIVERSAL,Victim); 90 DoPlaySoundToSet(m_creature, SOUND_SLAY3); 91 break; 82 92 } 83 93 } … … 100 110 return; 101 111 112 if (Enrage_Timer < diff && !Enraged) 113 { 114 DoCast(m_creature, SPELL_BERSERK,true); 115 Enraged = true; 116 }else Enrage_Timer -=diff; 117 102 118 if (Holyground_Timer < diff) 103 119 { … … 112 128 switch(rand()%2) 113 129 { 114 115 116 117 118 119 120 121 130 case 0: 131 DoYell(SAY_REPENTANCE1,LANG_UNIVERSAL,NULL); 132 DoPlaySoundToSet(m_creature, SOUND_REPENTANCE1); 133 break; 134 case 1: 135 DoYell(SAY_REPENTANCE2,LANG_UNIVERSAL,NULL); 136 DoPlaySoundToSet(m_creature, SOUND_REPENTANCE2); 137 break; 122 138 } 123 139 Repentance_Timer = 30000 + rand()%15000; //A little randomness on that spell … … 126 142 if (Holyfire_Timer < diff) 127 143 { 128 //Time for an omgwtfpwn code to make maiden cast holy fire only on units outside the holy ground's 18 yard range129 144 Unit* target = NULL; 130 std::list<HostilReference *> t_list = m_creature->getThreatManager().getThreatList();131 std::vector<Unit *> target_list; 132 for(std::list<HostilReference *>::iterator itr = t_list.begin(); itr!= t_list.end(); ++itr)145 target = SelectUnit(SELECT_TARGET_RANDOM,0); 146 147 if(target) 133 148 { 134 target = Unit::GetUnit(*m_creature, (*itr)->getUnitGuid()); 135 if(target && target->GetDistance2d(m_creature) > 12 ) 136 target_list.push_back(target); 137 target = NULL; 149 DoCast(target,SPELL_HOLYFIRE); 150 Holyfire_Timer = 8000 + rand()%17000; //Anywhere from 8 to 25 seconds, good luck having several of those in a row! 138 151 } 139 if(target_list.size())140 target = *(target_list.begin()+rand()%target_list.size());141 142 DoCast(target,SPELL_HOLYFIRE);143 144 Holyfire_Timer = 8000 + rand()%17000; //Anywhere from 8 to 25 seconds, good luck having several of those in a row!145 152 }else Holyfire_Timer -= diff; 146 153 -
trunk/src/bindings/scripts/scripts/zone/tempest_keep/the_eye/boss_void_reaver.cpp
r48 r57 26 26 27 27 #define SPELL_POUNDING 34162 28 #define SPELL_ARCANE_ORB _TRIGGER3417228 #define SPELL_ARCANE_ORB 34172 29 29 #define SPELL_KNOCK_AWAY 11130 30 30 #define SPELL_BERSERK 27680 … … 46 46 #define SOUND_POUNDING2 11219 47 47 48 #define CREATURE_ORB_TARGET 1957749 50 48 struct TRINITY_DLL_DECL boss_void_reaverAI : public ScriptedAI 51 49 { … … 65 63 void Reset() 66 64 { 65 m_creature->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_MOD_TAUNT, true); 66 m_creature->ApplySpellImmune(0, IMMUNITY_EFFECT, SPELL_EFFECT_ATTACK_ME, true); 67 67 68 Pounding_Timer = 12000; 68 ArcaneOrb_Timer = 3000;69 ArcaneOrb_Timer = 6000; 69 70 KnockAway_Timer = 30000; 70 71 Berserk_Timer = 600000; … … 144 145 { 145 146 target = Unit::GetUnit(*m_creature, (*itr)->getUnitGuid()); 146 //1 5yard radius minimum147 if(target && target->GetDistance2d(m_creature) > 1 5)147 //18 yard radius minimum 148 if(target && target->GetDistance2d(m_creature) > 18) 148 149 target_list.push_back(target); 149 150 target = NULL; … … 153 154 154 155 if (target) 155 { 156 Unit* Spawn = NULL; 157 Spawn = m_creature->SummonCreature(CREATURE_ORB_TARGET, target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN, 10000); 158 if (Spawn) 159 m_creature->CastSpell(Spawn, SPELL_ARCANE_ORB_TRIGGER, true); 160 } 156 m_creature->CastSpell(target, SPELL_ARCANE_ORB, true); 161 157 162 ArcaneOrb_Timer = 3000;158 ArcaneOrb_Timer = 6000; 163 159 }else ArcaneOrb_Timer -= diff; 164 160 -
trunk/src/game/SpellAuras.cpp
r44 r57 1651 1651 // // Prismatic Shield 1652 1652 // case 40879: break; 1653 // // Aura of Desire 1654 // case 41350: break; 1653 // Aura of Desire 1654 case 41350: 1655 { 1656 Unit::AuraList const& mMod = m_target->GetAurasByType(SPELL_AURA_MOD_INCREASE_ENERGY_PERCENT); 1657 for(Unit::AuraList::const_iterator i = mMod.begin(); i != mMod.end(); ++i) 1658 { 1659 if ((*i)->GetId() == 41350) 1660 { 1661 (*i)->ApplyModifier(false); 1662 (*i)->GetModifier()->m_amount -= 5; 1663 (*i)->ApplyModifier(true); 1664 break; 1665 } 1666 } 1667 }break; 1655 1668 // // Dementia 1656 1669 // case 41404: break; … … 5615 5628 break; 5616 5629 } 5630 case 41337:// aura of anger 5631 { 5632 Unit::AuraList const& mMod = m_target->GetAurasByType(SPELL_AURA_MOD_DAMAGE_PERCENT_DONE); 5633 for(Unit::AuraList::const_iterator i = mMod.begin(); i != mMod.end(); ++i) 5634 { 5635 if ((*i)->GetId() == 41337) 5636 { 5637 (*i)->ApplyModifier(false); 5638 (*i)->GetModifier()->m_amount += 5; 5639 (*i)->ApplyModifier(true); 5640 break; 5641 } 5642 } 5643 m_modifier.m_amount += 100; 5644 }break; 5617 5645 default: 5618 5646 break; -
trunk/src/game/SpellEffects.cpp
r56 r57 4666 4666 } 4667 4667 4668 // Dreaming Glory4669 case 28698:4670 {4671 if(!unitTarget)4672 return;4673 unitTarget->CastSpell(unitTarget, 28694, true);4674 break;4675 }4676 4677 4668 // Netherbloom 4678 4669 case 28702: … … 4747 4738 } 4748 4739 } 4749 break;4750 }4751 case 41126: // Flame Crash4752 {4753 if(!unitTarget)4754 return;4755 4756 unitTarget->CastSpell(unitTarget, 41131, true);4757 break;4758 }4759 case 44876: // Force Cast - Portal Effect: Sunwell Isle4760 {4761 if(!unitTarget)4762 return;4763 4764 unitTarget->CastSpell(unitTarget, 44870, true);4765 4740 break; 4766 4741 } … … 4791 4766 break; 4792 4767 } 4768 4769 } 4770 4771 if(!unitTarget || !unitTarget->isAlive()) // can we remove this check? 4772 { 4773 sLog.outError("Spell %u in EffectScriptEffect does not have unitTarget", m_spellInfo->Id); 4774 return; 4775 } 4776 4777 switch(m_spellInfo->Id) 4778 { 4779 // Dreaming Glory 4780 case 28698: unitTarget->CastSpell(unitTarget, 28694, true); break; 4781 // Needle Spine 4782 case 39835: unitTarget->CastSpell(unitTarget, 39968, true); break; 4783 // Draw Soul 4784 case 40904: unitTarget->CastSpell(m_caster, 40903, true); break; 4785 // Flame Crash 4786 case 41126: unitTarget->CastSpell(unitTarget, 41131, true); break; 4787 // Force Cast - Portal Effect: Sunwell Isle 4788 case 44876: unitTarget->CastSpell(unitTarget, 44870, true); break; 4793 4789 //5,000 Gold 4794 4790 case 46642: 4795 4791 { 4796 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER) 4797 return; 4798 4799 ((Player*)unitTarget)->ModifyMoney(50000000); 4800 4792 if(unitTarget->GetTypeId() == TYPEID_PLAYER) 4793 ((Player*)unitTarget)->ModifyMoney(50000000); 4801 4794 break; 4802 4795 } … … 4810 4803 case 0x800000: 4811 4804 { 4812 if(!unitTarget || !unitTarget->isAlive())4813 return;4814 4805 uint32 spellId2 = 0; 4815 4806 … … 4862 4853 4863 4854 // normal DB scripted effect 4864 if(!unitTarget)4865 return;4866 4867 4855 sLog.outDebug("Spell ScriptStart spellid %u in EffectScriptEffect ", m_spellInfo->Id); 4868 4856 sWorld.ScriptsStart(sSpellScripts, m_spellInfo->Id, m_caster, unitTarget);