SHOW:
|
|
- or go back to the newest paste.
| 1 | - | /* |
| 1 | + | //Trinity Based --Untested ICC Final Battle// |
| 2 | - | * Copyright (C) 2008-2012 TrinityCore <http://www.trinitycore.org/> |
| 2 | + | |
| 3 | - | * |
| 3 | + | |
| 4 | - | * This program is free software; you can redistribute it and/or modify it |
| 4 | + | |
| 5 | - | * under the terms of the GNU General Public License as published by the |
| 5 | + | |
| 6 | - | * Free Software Foundation; either version 2 of the License, or (at your |
| 6 | + | |
| 7 | - | * option) any later version. |
| 7 | + | |
| 8 | - | * |
| 8 | + | |
| 9 | - | * This program is distributed in the hope that it will be useful, but WITHOUT |
| 9 | + | |
| 10 | - | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| 10 | + | |
| 11 | - | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for |
| 11 | + | |
| 12 | - | * more details. |
| 12 | + | |
| 13 | - | * |
| 13 | + | |
| 14 | - | * You should have received a copy of the GNU General Public License along |
| 14 | + | |
| 15 | - | * with this program. If not, see <http://www.gnu.org/licenses/>. |
| 15 | + | |
| 16 | - | */ |
| 16 | + | |
| 17 | {
| |
| 18 | // The Lich King | |
| 19 | SAY_LK_INTRO_1 = 0, | |
| 20 | SAY_LK_INTRO_2 = 1, | |
| 21 | SAY_LK_INTRO_3 = 2, | |
| 22 | SAY_LK_REMORSELESS_WINTER = 4, | |
| 23 | SAY_LK_QUAKE = 5, | |
| 24 | SAY_LK_SUMMON_VALKYR = 6, | |
| 25 | SAY_LK_HARVEST_SOUL = 7, | |
| 26 | SAY_LK_FROSTMOURNE_ESCAPE = 8, // not said on heroic | |
| 27 | SAY_LK_FROSTMOURNE_KILL = 9, // not said on heroic | |
| 28 | SAY_LK_KILL = 10, | |
| 29 | SAY_LK_BERSERK = 11, | |
| 30 | EMOTE_DEFILE_WARNING = 12, | |
| 31 | EMOTE_NECROTIC_PLAGUE_WARNING = 13, | |
| 32 | SAY_LK_OUTRO_1 = 14, | |
| 33 | SAY_LK_OUTRO_2 = 15, | |
| 34 | SAY_LK_OUTRO_3 = 16, | |
| 35 | SAY_LK_OUTRO_4 = 17, | |
| 36 | SAY_LK_OUTRO_5 = 18, | |
| 37 | SAY_LK_OUTRO_6 = 19, | |
| 38 | SAY_LK_OUTRO_7 = 20, | |
| 39 | SAY_LK_OUTRO_8 = 21, | |
| 40 | ||
| 41 | // Highlord Tirion Fordring | |
| 42 | SAY_TIRION_INTRO_1 = 0, | |
| 43 | SAY_TIRION_INTRO_2 = 1, | |
| 44 | SAY_TIRION_OUTRO_1 = 2, | |
| 45 | SAY_TIRION_OUTRO_2 = 3, | |
| 46 | ||
| 47 | // Terenas Menethil (outro) | |
| 48 | SAY_TERENAS_OUTRO_1 = 0, | |
| 49 | SAY_TERENAS_OUTRO_2 = 1, | |
| 50 | ||
| 51 | // Terenas Menethil (Frostmourne) | |
| 52 | SAY_TERENAS_INTRO_1 = 0, | |
| 53 | SAY_TERENAS_INTRO_2 = 1, | |
| 54 | SAY_TERENAS_INTRO_3 = 2, | |
| 55 | }; | |
| 56 | ||
| 57 | enum Spells | |
| 58 | {
| |
| 59 | // The Lich King | |
| 60 | SPELL_PLAGUE_AVOIDANCE = 72846, // raging spirits also get it | |
| 61 | SPELL_EMOTE_SIT_NO_SHEATH = 73220, | |
| 62 | SPELL_BOSS_HITTIN_YA = 73878, | |
| 63 | SPELL_EMOTE_SHOUT_NO_SHEATH = 73213, | |
| 64 | SPELL_ICE_LOCK = 71614, | |
| 65 | ||
| 66 | // Phase 1 | |
| 67 | SPELL_SUMMON_SHAMBLING_HORROR = 70372, | |
| 68 | SPELL_RISEN_WITCH_DOCTOR_SPAWN = 69639, | |
| 69 | SPELL_SUMMON_DRUDGE_GHOULS = 70358, | |
| 70 | SPELL_INFEST = 70541, | |
| 71 | SPELL_NECROTIC_PLAGUE = 70337, | |
| 72 | SPELL_NECROTIC_PLAGUE_JUMP = 70338, | |
| 73 | SPELL_PLAGUE_SIPHON = 74074, | |
| 74 | SPELL_SHADOW_TRAP = 73539, | |
| 75 | SPELL_SHADOW_TRAP_AURA = 73525, | |
| 76 | SPELL_SHADOW_TRAP_KNOCKBACK = 73529, | |
| 77 | ||
| 78 | // Phase Transition | |
| 79 | SPELL_REMORSELESS_WINTER_1 = 68981, | |
| 80 | SPELL_REMORSELESS_WINTER_2 = 72259, | |
| 81 | SPELL_PAIN_AND_SUFFERING = 72133, | |
| 82 | SPELL_SUMMON_ICE_SPHERE = 69104, | |
| 83 | SPELL_ICE_SPHERE = 69090, | |
| 84 | SPELL_ICE_BURST_TARGET_SEARCH = 69109, | |
| 85 | SPELL_ICE_PULSE = 69091, | |
| 86 | SPELL_ICE_BURST = 69108, | |
| 87 | SPELL_RAGING_SPIRIT = 69200, | |
| 88 | SPELL_RAGING_SPIRIT_VISUAL = 69197, | |
| 89 | SPELL_RAGING_SPIRIT_VISUAL_CLONE = 69198, | |
| 90 | SPELL_SOUL_SHRIEK = 69242, | |
| 91 | SPELL_QUAKE = 72262, | |
| 92 | ||
| 93 | // Phase 2 | |
| 94 | SPELL_DEFILE = 72762, | |
| 95 | SPELL_DEFILE_AURA = 72743, | |
| 96 | SPELL_DEFILE_GROW = 72756, | |
| 97 | SPELL_SUMMON_VALKYR = 69037, | |
| 98 | SPELL_SUMMON_VALKYR_PERIODIC = 74361, | |
| 99 | SPELL_HARVEST_SOUL_VALKYR = 68985, // Val'kyr Shadowguard vehicle aura | |
| 100 | SPELL_SOUL_REAPER = 69409, | |
| 101 | SPELL_SOUL_REAPER_BUFF = 69410, | |
| 102 | SPELL_WINGS_OF_THE_DAMNED = 74352, | |
| 103 | SPELL_VALKYR_TARGET_SEARCH = 69030, | |
| 104 | SPELL_CHARGE = 74399, // cast on selected target | |
| 105 | SPELL_VALKYR_CARRY = 74445, // removes unselectable flag | |
| 106 | SPELL_LIFE_SIPHON = 73488, | |
| 107 | SPELL_LIFE_SIPHON_HEAL = 73489, | |
| 108 | SPELL_EJECT_ALL_PASSENGERS = 68576, | |
| 109 | ||
| 110 | // Phase 3 | |
| 111 | SPELL_VILE_SPIRITS = 70498, | |
| 112 | SPELL_VILE_SPIRIT_MOVE_SEARCH = 70501, | |
| 113 | SPELL_VILE_SPIRIT_DAMAGE_SEARCH = 70502, | |
| 114 | SPELL_SPIRIT_BURST = 70503, | |
| 115 | SPELL_HARVEST_SOUL = 68980, | |
| 116 | SPELL_HARVEST_SOULS = 73654, // Heroic version, weird because it has all 4 difficulties just like above spell | |
| 117 | SPELL_HARVEST_SOUL_VEHICLE = 68984, | |
| 118 | SPELL_HARVEST_SOUL_VISUAL = 71372, | |
| 119 | SPELL_HARVEST_SOUL_TELEPORT = 72546, | |
| 120 | SPELL_HARVEST_SOULS_TELEPORT = 73655, | |
| 121 | SPELL_HARVEST_SOUL_TELEPORT_BACK = 72597, | |
| 122 | SPELL_IN_FROSTMOURNE_ROOM = 74276, | |
| 123 | SPELL_KILL_FROSTMOURNE_PLAYERS = 75127, | |
| 124 | SPELL_HARVESTED_SOUL = 72679, | |
| 125 | SPELL_TRIGGER_VILE_SPIRIT_HEROIC = 73582, | |
| 126 | ||
| 127 | // Frostmourne | |
| 128 | SPELL_LIGHTS_FAVOR = 69382, | |
| 129 | SPELL_RESTORE_SOUL = 72595, | |
| 130 | SPELL_RESTORE_SOULS = 73650, // Heroic | |
| 131 | SPELL_DARK_HUNGER = 69383, // Passive proc healing | |
| 132 | SPELL_DESTROY_SOUL = 74086, // Used when Terenas Menethil dies | |
| 133 | SPELL_SOUL_RIP = 69397, // Deals increasing damage | |
| 134 | SPELL_SOUL_RIP_DAMAGE = 69398, | |
| 135 | SPELL_TERENAS_LOSES_INSIDE = 72572, | |
| 136 | SPELL_SUMMON_SPIRIT_BOMB_1 = 73581, // (Heroic) | |
| 137 | SPELL_SUMMON_SPIRIT_BOMB_2 = 74299, // (Heroic) | |
| 138 | SPELL_EXPLOSION = 73576, // Spirit Bomb (Heroic) | |
| 139 | ||
| 140 | // Outro | |
| 141 | SPELL_FURY_OF_FROSTMOURNE = 72350, | |
| 142 | SPELL_FURY_OF_FROSTMOURNE_NO_REZ = 72351, | |
| 143 | SPELL_EMOTE_QUESTION_NO_SHEATH = 73330, | |
| 144 | SPELL_RAISE_DEAD = 71769, | |
| 145 | SPELL_LIGHTS_BLESSING = 71797, | |
| 146 | SPELL_JUMP = 71809, | |
| 147 | SPELL_JUMP_TRIGGERED = 71811, | |
| 148 | SPELL_JUMP_2 = 72431, | |
| 149 | SPELL_SUMMON_BROKEN_FROSTMOURNE = 74081, // visual | |
| 150 | SPELL_SUMMON_BROKEN_FROSTMOURNE_2 = 72406, // animation | |
| 151 | SPELL_SUMMON_BROKEN_FROSTMOURNE_3 = 73017, // real summon | |
| 152 | SPELL_BROKEN_FROSTMOURNE = 72398, | |
| 153 | SPELL_BROKEN_FROSTMOURNE_KNOCK = 72405, | |
| 154 | SPELL_SOUL_BARRAGE = 72305, | |
| 155 | SPELL_SUMMON_TERENAS = 72420, | |
| 156 | SPELL_MASS_RESURRECTION = 72429, | |
| 157 | SPELL_MASS_RESURRECTION_REAL = 72423, | |
| 158 | SPELL_PLAY_MOVIE = 73159, | |
| 159 | ||
| 160 | // Shambling Horror | |
| 161 | SPELL_SHOCKWAVE = 72149, | |
| 162 | SPELL_ENRAGE = 72143, | |
| 163 | SPELL_FRENZY = 28747, | |
| 164 | }; | |
| 165 | ||
| 166 | #define NECROTIC_PLAGUE_LK RAID_MODE<uint32>(70337, 73912, 73913, 73914) | |
| 167 | #define NECROTIC_PLAGUE_PLR RAID_MODE<uint32>(70338, 73785, 73786, 73787) | |
| 168 | #define REMORSELESS_WINTER_1 RAID_MODE<uint32>(68981, 74270, 74271, 74272) | |
| 169 | #define REMORSELESS_WINTER_2 RAID_MODE<uint32>(72259, 74273, 74274, 74275) | |
| 170 | #define SUMMON_VALKYR RAID_MODE<uint32>(69037, 74361, 69037, 74361) | |
| 171 | #define HARVEST_SOUL RAID_MODE<uint32>(68980, 74325, 74296, 74297) | |
| 172 | ||
| 173 | enum Events | |
| 174 | {
| |
| 175 | // The Lich King | |
| 176 | // intro events | |
| 177 | EVENT_INTRO_MOVE_1 = 1, | |
| 178 | EVENT_INTRO_MOVE_2 = 2, | |
| 179 | EVENT_INTRO_MOVE_3 = 3, | |
| 180 | EVENT_INTRO_TALK_1 = 4, | |
| 181 | EVENT_EMOTE_CAST_SHOUT = 5, | |
| 182 | EVENT_INTRO_EMOTE_1 = 6, | |
| 183 | EVENT_INTRO_CHARGE = 7, | |
| 184 | EVENT_INTRO_CAST_FREEZE = 8, | |
| 185 | EVENT_FINISH_INTRO = 9, | |
| 186 | ||
| 187 | // combat events | |
| 188 | EVENT_SUMMON_SHAMBLING_HORROR = 10, | |
| 189 | EVENT_SUMMON_DRUDGE_GHOUL = 11, | |
| 190 | EVENT_INFEST = 12, | |
| 191 | EVENT_NECROTIC_PLAGUE = 13, | |
| 192 | EVENT_SHADOW_TRAP = 14, // heroic only | |
| 193 | EVENT_SOUL_REAPER = 15, | |
| 194 | EVENT_DEFILE = 16, | |
| 195 | EVENT_HARVEST_SOUL = 17, // normal mode only | |
| 196 | EVENT_PAIN_AND_SUFFERING = 18, | |
| 197 | EVENT_SUMMON_ICE_SPHERE = 19, | |
| 198 | EVENT_SUMMON_RAGING_SPIRIT = 20, | |
| 199 | EVENT_QUAKE = 21, | |
| 200 | EVENT_SUMMON_VALKYR = 22, | |
| 201 | EVENT_GRAB_PLAYER = 23, | |
| 202 | EVENT_MOVE_TO_DROP_POS = 24, | |
| 203 | EVENT_LIFE_SIPHON = 25, // heroic only | |
| 204 | EVENT_START_ATTACK = 26, | |
| 205 | EVENT_QUAKE_2 = 27, | |
| 206 | EVENT_VILE_SPIRITS = 28, | |
| 207 | EVENT_HARVEST_SOULS = 29, // heroic only | |
| 208 | EVENT_WICKED_SPIRITS = 30, | |
| 209 | EVENT_SOUL_RIP = 31, | |
| 210 | EVENT_DESTROY_SOUL = 32, | |
| 211 | EVENT_FROSTMOURNE_TALK_1 = 33, | |
| 212 | EVENT_FROSTMOURNE_TALK_2 = 34, | |
| 213 | EVENT_FROSTMOURNE_TALK_3 = 35, | |
| 214 | EVENT_TELEPORT_BACK = 36, | |
| 215 | EVENT_FROSTMOURNE_HEROIC = 37, | |
| 216 | EVENT_OUTRO_TALK_1 = 38, | |
| 217 | EVENT_OUTRO_TALK_2 = 39, | |
| 218 | EVENT_OUTRO_EMOTE_TALK = 40, | |
| 219 | EVENT_OUTRO_TALK_3 = 41, | |
| 220 | EVENT_OUTRO_MOVE_CENTER = 42, | |
| 221 | EVENT_OUTRO_TALK_4 = 43, | |
| 222 | EVENT_OUTRO_RAISE_DEAD = 44, | |
| 223 | EVENT_OUTRO_TALK_5 = 45, | |
| 224 | EVENT_OUTRO_BLESS = 46, | |
| 225 | EVENT_OUTRO_REMOVE_ICE = 47, | |
| 226 | EVENT_OUTRO_MOVE_1 = 48, | |
| 227 | EVENT_OUTRO_JUMP = 49, | |
| 228 | EVENT_OUTRO_TALK_6 = 50, | |
| 229 | EVENT_OUTRO_KNOCK_BACK = 51, | |
| 230 | EVENT_OUTRO_SOUL_BARRAGE = 52, | |
| 231 | EVENT_OUTRO_SUMMON_TERENAS = 53, | |
| 232 | EVENT_OUTRO_TERENAS_TALK_1 = 54, | |
| 233 | EVENT_OUTRO_TERENAS_TALK_2 = 55, | |
| 234 | EVENT_OUTRO_TALK_7 = 56, | |
| 235 | EVENT_OUTRO_TALK_8 = 57, | |
| 236 | EVENT_BERSERK = 58, | |
| 237 | ||
| 238 | // Shambling Horror | |
| 239 | EVENT_SHOCKWAVE = 59, | |
| 240 | EVENT_ENRAGE = 60, | |
| 241 | ||
| 242 | // Raging Spirit | |
| 243 | EVENT_SOUL_SHRIEK = 61, | |
| 244 | ||
| 245 | // Strangulate Vehicle (Harvest Soul) | |
| 246 | EVENT_TELEPORT = 62, | |
| 247 | EVENT_MOVE_TO_LICH_KING = 63, | |
| 248 | EVENT_DESPAWN_SELF = 64, | |
| 249 | }; | |
| 250 | ||
| 251 | enum EventGroups | |
| 252 | {
| |
| 253 | EVENT_GROUP_BERSERK = 1, | |
| 254 | EVENT_GROUP_VILE_SPIRITS = 2, | |
| 255 | }; | |
| 256 | ||
| 257 | enum Phases | |
| 258 | {
| |
| 259 | PHASE_INTRO = 1, | |
| 260 | PHASE_ONE = 2, | |
| 261 | PHASE_TWO = 3, | |
| 262 | PHASE_THREE = 4, | |
| 263 | PHASE_TRANSITION = 5, | |
| 264 | PHASE_FROSTMOURNE = 6, // only set on heroic mode when all players are sent into frostmourne | |
| 265 | PHASE_OUTRO = 7, | |
| 266 | ||
| 267 | PHASE_MASK_INTRO = 1 << PHASE_INTRO, | |
| 268 | PHASE_MASK_ONE = 1 << PHASE_ONE, | |
| 269 | PHASE_MASK_TWO = 1 << PHASE_TWO, | |
| 270 | PHASE_MASK_THREE = 1 << PHASE_THREE, | |
| 271 | PHASE_MASK_TRANSITION = 1 << PHASE_TRANSITION, | |
| 272 | PHASE_MASK_NO_CAST_CHECK = (1 << PHASE_TRANSITION) | (1 << PHASE_FROSTMOURNE) | (1 << PHASE_OUTRO), | |
| 273 | PHASE_MASK_FROSTMOURNE = 1 << PHASE_FROSTMOURNE, | |
| 274 | PHASE_MASK_OUTRO = 1 << PHASE_OUTRO, | |
| 275 | PHASE_MASK_NO_VICTIM = (1 << PHASE_INTRO) | (1 << PHASE_OUTRO) | (1 << PHASE_FROSTMOURNE), | |
| 276 | }; | |
| 277 | ||
| 278 | #define PHASE_TWO_THREE (events.GetPhaseMask() & PHASE_MASK_TWO ? PHASE_TWO : PHASE_THREE) | |
| 279 | ||
| 280 | Position const CenterPosition = {503.6282f, -2124.655f, 1040.8602f, 0.0f};
| |
| 281 | Position const TirionIntro = {489.2970f, -2124.840f, 1040.8602f, 0.0f};
| |
| 282 | Position const TirionCharge = {482.9019f, -2124.479f, 1040.8602f, 0.0f};
| |
| 283 | Position const LichKingIntro[3] = | |
| 284 | {
| |
| 285 | {432.0851f, -2123.673f, 1064.6615f, 0.0f},
| |
| 286 | {457.8351f, -2123.423f, 1041.1615f, 0.0f},
| |
| 287 | {465.0730f, -2123.470f, 1040.8602f, 0.0f},
| |
| 288 | }; | |
| 289 | Position const OutroPosition1 = {493.6286f, -2124.569f, 1040.8602f, 0.0f};
| |
| 290 | Position const OutroFlying = {508.9897f, -2124.561f, 1045.8598f, 0.0f};
| |
| 291 | Position const TerenasSpawn = {495.5542f, -2517.012f, 1050.000f, 4.6993f};
| |
| 292 | Position const TerenasSpawnHeroic = {495.7080f, -2523.760f, 1050.000f, 0.0f};
| |
| 293 | Position const SpiritWardenSpawn = {495.3406f, -2529.983f, 1050.000f, 1.5592f};
| |
| 294 | ||
| 295 | enum MovePoints | |
| 296 | {
| |
| 297 | POINT_CENTER_1 = 1, | |
| 298 | POINT_CENTER_2 = 2, | |
| 299 | POINT_TIRION_INTRO = 3, | |
| 300 | POINT_LK_INTRO_1 = 4, | |
| 301 | POINT_LK_INTRO_2 = 5, | |
| 302 | POINT_LK_INTRO_3 = 6, | |
| 303 | POINT_TIRION_CHARGE = 7, | |
| 304 | POINT_DROP_PLAYER = 8, | |
| 305 | POINT_LK_OUTRO_1 = 9, | |
| 306 | POINT_TIRION_OUTRO_1 = 10, | |
| 307 | POINT_OUTRO_JUMP = 11, | |
| 308 | POINT_LK_OUTRO_2 = 12, | |
| 309 | POINT_GROUND = 13, | |
| 310 | POINT_CHARGE = 1003, // globally used number for charge spell effects | |
| 311 | }; | |
| 312 | ||
| 313 | enum EncounterActions | |
| 314 | {
| |
| 315 | ACTION_START_ENCOUNTER = 0, | |
| 316 | ACTION_CONTINUE_INTRO = 1, | |
| 317 | ACTION_START_ATTACK = 2, | |
| 318 | ACTION_OUTRO = 3, | |
| 319 | ACTION_PLAY_MUSIC = 4, | |
| 320 | ACTION_BREAK_FROSTMOURNE = 5, | |
| 321 | ACTION_SUMMON_TERENAS = 6, | |
| 322 | ACTION_FINISH_OUTRO = 7, | |
| 323 | ACTION_TELEPORT_BACK = 8, | |
| 324 | }; | |
| 325 | ||
| 326 | enum MiscData | |
| 327 | {
| |
| 328 | LIGHT_SNOWSTORM = 2490, | |
| 329 | LIGHT_SOULSTORM = 2508, | |
| 330 | ||
| 331 | MUSIC_FROZEN_THRONE = 17457, | |
| 332 | MUSIC_SPECIAL = 17458, // Summon Shambling Horror, Remorseless Winter, Quake, Summon Val'kyr Periodic, Harvest Soul, Vile Spirits | |
| 333 | MUSIC_FURY_OF_FROSTMOURNE = 17459, | |
| 334 | MUSIC_FINAL = 17460, // Raise Dead, Light's Blessing | |
| 335 | ||
| 336 | SOUND_PAIN = 17360, // separate sound, not attached to any text | |
| 337 | ||
| 338 | EQUIP_ASHBRINGER_GLOWING = 50442, | |
| 339 | EQUIP_BROKEN_FROSTMOURNE = 50840, | |
| 340 | ||
| 341 | MOVIE_FALL_OF_THE_LICH_KING = 16, | |
| 342 | }; | |
| 343 | ||
| 344 | #define DATA_PLAGUE_STACK 70337 | |
| 345 | #define DATA_VILE 45814622 | |
| 346 | ||
| 347 | class NecroticPlagueTargetCheck : public std::unary_function<Unit*, bool> | |
| 348 | {
| |
| 349 | public: | |
| 350 | NecroticPlagueTargetCheck(Unit const* obj, uint32 notAura1 = 0, uint32 notAura2 = 0) | |
| 351 | : _sourceObj(obj), _notAura1(notAura1), _notAura2(notAura2) | |
| 352 | {
| |
| 353 | } | |
| 354 | ||
| 355 | bool operator()(Unit* unit) const | |
| 356 | {
| |
| 357 | if (!unit || unit == _sourceObj || !unit->isTargetableForAttack() || unit->isTotem() || unit->HasAura(SPELL_PLAGUE_AVOIDANCE)) | |
| 358 | return false; | |
| 359 | if ((_notAura1 && unit->HasAura(_notAura1)) || (_notAura2 && unit->HasAura(_notAura2))) | |
| 360 | return false; | |
| 361 | return true; | |
| 362 | } | |
| 363 | ||
| 364 | private: | |
| 365 | Unit const* _sourceObj; | |
| 366 | uint32 _notAura1; | |
| 367 | uint32 _notAura2; | |
| 368 | }; | |
| 369 | ||
| 370 | class HeightDifferenceCheck | |
| 371 | {
| |
| 372 | public: | |
| 373 | HeightDifferenceCheck(GameObject* go, float diff, bool reverse) | |
| 374 | : _baseObject(go), _difference(diff), _reverse(reverse) | |
| 375 | {
| |
| 376 | } | |
| 377 | ||
| 378 | bool operator()(Unit* unit) const | |
| 379 | {
| |
| 380 | return (unit->GetPositionZ() - _baseObject->GetPositionZ() > _difference) != _reverse; | |
| 381 | } | |
| 382 | ||
| 383 | private: | |
| 384 | GameObject* _baseObject; | |
| 385 | float _difference; | |
| 386 | bool _reverse; | |
| 387 | }; | |
| 388 | ||
| 389 | class FrozenThroneResetWorker | |
| 390 | {
| |
| 391 | public: | |
| 392 | FrozenThroneResetWorker() { }
| |
| 393 | ||
| 394 | bool operator()(GameObject* go) | |
| 395 | {
| |
| 396 | switch (go->GetEntry()) | |
| 397 | {
| |
| 398 | case GO_ARTHAS_PLATFORM: | |
| 399 | go->SetDestructibleState(GO_DESTRUCTIBLE_REBUILDING); | |
| 400 | break; | |
| 401 | case GO_DOODAD_ICECROWN_THRONEFROSTYWIND01: | |
| 402 | go->SetGoState(GO_STATE_ACTIVE); | |
| 403 | break; | |
| 404 | case GO_DOODAD_ICECROWN_THRONEFROSTYEDGE01: | |
| 405 | go->SetGoState(GO_STATE_READY); | |
| 406 | break; | |
| 407 | case GO_DOODAD_ICESHARD_STANDING02: | |
| 408 | case GO_DOODAD_ICESHARD_STANDING01: | |
| 409 | case GO_DOODAD_ICESHARD_STANDING03: | |
| 410 | case GO_DOODAD_ICESHARD_STANDING04: | |
| 411 | go->ResetDoorOrButton(); | |
| 412 | break; | |
| 413 | default: | |
| 414 | break; | |
| 415 | } | |
| 416 | ||
| 417 | return false; | |
| 418 | } | |
| 419 | }; | |
| 420 | ||
| 421 | class StartMovementEvent : public BasicEvent | |
| 422 | {
| |
| 423 | public: | |
| 424 | StartMovementEvent(Creature* summoner, Creature* owner) | |
| 425 | : _summoner(summoner), _owner(owner) | |
| 426 | {
| |
| 427 | } | |
| 428 | ||
| 429 | bool Execute(uint64 /*time*/, uint32 /*diff*/) | |
| 430 | {
| |
| 431 | _owner->SetReactState(REACT_AGGRESSIVE); | |
| 432 | if (Unit* target = _summoner->AI()->SelectTarget(SELECT_TARGET_RANDOM, 0, NonTankTargetSelector(_summoner))) | |
| 433 | _owner->AI()->AttackStart(target); | |
| 434 | return true; | |
| 435 | } | |
| 436 | ||
| 437 | private: | |
| 438 | Creature* _summoner; | |
| 439 | Creature* _owner; | |
| 440 | }; | |
| 441 | ||
| 442 | class VileSpiritActivateEvent : public BasicEvent | |
| 443 | {
| |
| 444 | public: | |
| 445 | explicit VileSpiritActivateEvent(Creature* owner) | |
| 446 | : _owner(owner) | |
| 447 | {
| |
| 448 | } | |
| 449 | ||
| 450 | bool Execute(uint64 /*time*/, uint32 /*diff*/) | |
| 451 | {
| |
| 452 | _owner->SetReactState(REACT_AGGRESSIVE); | |
| 453 | _owner->CastSpell(_owner, SPELL_VILE_SPIRIT_MOVE_SEARCH, true); | |
| 454 | _owner->CastSpell((Unit*)NULL, SPELL_VILE_SPIRIT_DAMAGE_SEARCH, true); | |
| 455 | return true; | |
| 456 | } | |
| 457 | ||
| 458 | private: | |
| 459 | Creature* _owner; | |
| 460 | }; | |
| 461 | ||
| 462 | class boss_the_lich_king : public CreatureScript | |
| 463 | {
| |
| 464 | public: | |
| 465 | boss_the_lich_king() : CreatureScript("boss_the_lich_king") { }
| |
| 466 | ||
| 467 | struct boss_the_lich_kingAI : public BossAI | |
| 468 | {
| |
| 469 | boss_the_lich_kingAI(Creature* creature) : BossAI(creature, DATA_THE_LICH_KING) | |
| 470 | {
| |
| 471 | } | |
| 472 | ||
| 473 | void Reset() | |
| 474 | {
| |
| 475 | _Reset(); | |
| 476 | events.SetPhase(PHASE_INTRO); | |
| 477 | _necroticPlagueStack = 0; | |
| 478 | _vileSpiritExplosions = 0; | |
| 479 | SetEquipmentSlots(true); | |
| 480 | } | |
| 481 | ||
| 482 | void JustDied(Unit* /*killer*/) | |
| 483 | {
| |
| 484 | _JustDied(); | |
| 485 | DoCastAOE(SPELL_PLAY_MOVIE, false); | |
| 486 | me->RemoveUnitMovementFlag(MOVEMENTFLAG_LEVITATING); | |
| 487 | me->RemoveByteFlag(UNIT_FIELD_BYTES_1, 3, 0x03); | |
| 488 | ||
| 489 | //me->GetMotionMaster()->MoveFall(); | |
| 490 | } | |
| 491 | ||
| 492 | void EnterCombat(Unit* target) | |
| 493 | {
| |
| 494 | if (!instance->CheckRequiredBosses(DATA_THE_LICH_KING, target->ToPlayer())) | |
| 495 | {
| |
| 496 | EnterEvadeMode(); | |
| 497 | instance->DoCastSpellOnPlayers(LIGHT_S_HAMMER_TELEPORT); | |
| 498 | return; | |
| 499 | } | |
| 500 | ||
| 501 | me->setActive(true); | |
| 502 | DoZoneInCombat(); | |
| 503 | ||
| 504 | events.SetPhase(PHASE_ONE); | |
| 505 | events.ScheduleEvent(EVENT_SUMMON_SHAMBLING_HORROR, 20000, 0, PHASE_ONE); | |
| 506 | events.ScheduleEvent(EVENT_SUMMON_DRUDGE_GHOUL, 10000, 0, PHASE_ONE); | |
| 507 | events.ScheduleEvent(EVENT_INFEST, 5000, 0, PHASE_ONE); | |
| 508 | events.ScheduleEvent(EVENT_NECROTIC_PLAGUE, urand(30000, 33000), 0, PHASE_ONE); | |
| 509 | events.ScheduleEvent(EVENT_BERSERK, 900000, EVENT_GROUP_BERSERK); | |
| 510 | if (IsHeroic()) | |
| 511 | events.ScheduleEvent(EVENT_SHADOW_TRAP, 15500, 0, PHASE_ONE); | |
| 512 | } | |
| 513 | ||
| 514 | void JustReachedHome() | |
| 515 | {
| |
| 516 | _JustReachedHome(); | |
| 517 | instance->SetBossState(DATA_THE_LICH_KING, NOT_STARTED); | |
| 518 | ||
| 519 | // Reset The Frozen Throne gameobjects | |
| 520 | FrozenThroneResetWorker reset; | |
| 521 | Trinity::GameObjectWorker<FrozenThroneResetWorker> worker(me, reset); | |
| 522 | me->VisitNearbyGridObject(333.0f, worker); | |
| 523 | ||
| 524 | // Reset any light override | |
| 525 | SendLightOverride(0, 5000); | |
| 526 | } | |
| 527 | ||
| 528 | bool CanAIAttack(Unit const* target) const | |
| 529 | {
| |
| 530 | // The Lich King must not select targets in frostmourne room if he killed everyone outside | |
| 531 | return !target->HasAura(SPELL_IN_FROSTMOURNE_ROOM); | |
| 532 | } | |
| 533 | ||
| 534 | void EnterEvadeMode() | |
| 535 | {
| |
| 536 | instance->SetBossState(DATA_THE_LICH_KING, FAIL); | |
| 537 | BossAI::EnterEvadeMode(); | |
| 538 | if (Creature* tirion = ObjectAccessor::GetCreature(*me, instance->GetData64(DATA_HIGHLORD_TIRION_FORDRING))) | |
| 539 | tirion->AI()->EnterEvadeMode(); | |
| 540 | DoCastAOE(SPELL_KILL_FROSTMOURNE_PLAYERS); | |
| 541 | summons.DoAction(NPC_STRANGULATE_VEHICLE, ACTION_TELEPORT_BACK); | |
| 542 | } | |
| 543 | ||
| 544 | void KilledUnit(Unit* victim) | |
| 545 | {
| |
| 546 | if (victim->GetTypeId() == TYPEID_PLAYER && !me->IsInEvadeMode() && !(events.GetPhaseMask() & PHASE_MASK_OUTRO)) | |
| 547 | Talk(SAY_LK_KILL); | |
| 548 | } | |
| 549 | ||
| 550 | void DoAction(int32 const action) | |
| 551 | {
| |
| 552 | switch (action) | |
| 553 | {
| |
| 554 | case ACTION_START_ENCOUNTER: | |
| 555 | instance->SetBossState(DATA_THE_LICH_KING, IN_PROGRESS); | |
| 556 | Talk(SAY_LK_INTRO_1); | |
| 557 | SendMusicToPlayers(MUSIC_FROZEN_THRONE); | |
| 558 | // schedule talks | |
| 559 | me->SetStandState(UNIT_STAND_STATE_STAND); | |
| 560 | events.ScheduleEvent(EVENT_INTRO_MOVE_1, 4000); | |
| 561 | break; | |
| 562 | case ACTION_START_ATTACK: | |
| 563 | events.ScheduleEvent(EVENT_START_ATTACK, 5000); | |
| 564 | break; | |
| 565 | case ACTION_PLAY_MUSIC: | |
| 566 | SendMusicToPlayers(MUSIC_FINAL); | |
| 567 | break; | |
| 568 | case ACTION_RESTORE_LIGHT: | |
| 569 | SendLightOverride(0, 5000); | |
| 570 | break; | |
| 571 | case ACTION_BREAK_FROSTMOURNE: | |
| 572 | DoCastAOE(SPELL_SUMMON_BROKEN_FROSTMOURNE); | |
| 573 | DoCastAOE(SPELL_SUMMON_BROKEN_FROSTMOURNE_2); | |
| 574 | SetEquipmentSlots(false, EQUIP_BROKEN_FROSTMOURNE); | |
| 575 | events.ScheduleEvent(EVENT_OUTRO_TALK_6, 2500, 0, PHASE_OUTRO); | |
| 576 | break; | |
| 577 | case ACTION_FINISH_OUTRO: | |
| 578 | events.ScheduleEvent(EVENT_OUTRO_TALK_7, 7000, 0, PHASE_OUTRO); | |
| 579 | events.ScheduleEvent(EVENT_OUTRO_TALK_8, 17000, 0, PHASE_OUTRO); | |
| 580 | break; | |
| 581 | case ACTION_TELEPORT_BACK: | |
| 582 | summons.DoAction(NPC_STRANGULATE_VEHICLE, ACTION_TELEPORT_BACK); | |
| 583 | if (!IsHeroic()) | |
| 584 | Talk(SAY_LK_FROSTMOURNE_ESCAPE); | |
| 585 | else | |
| 586 | DoCastAOE(SPELL_TRIGGER_VILE_SPIRIT_HEROIC); | |
| 587 | break; | |
| 588 | default: | |
| 589 | break; | |
| 590 | } | |
| 591 | } | |
| 592 | ||
| 593 | uint32 GetData(uint32 type) | |
| 594 | {
| |
| 595 | switch (type) | |
| 596 | {
| |
| 597 | case DATA_PLAGUE_STACK: | |
| 598 | return _necroticPlagueStack; | |
| 599 | case DATA_VILE: | |
| 600 | return _vileSpiritExplosions; | |
| 601 | default: | |
| 602 | break; | |
| 603 | } | |
| 604 | ||
| 605 | return 0; | |
| 606 | } | |
| 607 | ||
| 608 | void SetData(uint32 type, uint32 value) | |
| 609 | {
| |
| 610 | switch (type) | |
| 611 | {
| |
| 612 | case DATA_PLAGUE_STACK: | |
| 613 | _necroticPlagueStack = std::max(value, _necroticPlagueStack); | |
| 614 | break; | |
| 615 | case DATA_VILE: | |
| 616 | _vileSpiritExplosions += value; | |
| 617 | break; | |
| 618 | default: | |
| 619 | break; | |
| 620 | } | |
| 621 | } | |
| 622 | ||
| 623 | void DamageTaken(Unit* /*attacker*/, uint32& /*damage*/) | |
| 624 | {
| |
| 625 | if (events.GetPhaseMask() & PHASE_MASK_ONE && !HealthAbovePct(70)) | |
| 626 | {
| |
| 627 | events.SetPhase(PHASE_TRANSITION); | |
| 628 | me->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_MOD_TAUNT, true); | |
| 629 | me->GetMotionMaster()->MovePoint(POINT_CENTER_1, CenterPosition); | |
| 630 | return; | |
| 631 | } | |
| 632 | ||
| 633 | if (events.GetPhaseMask() & PHASE_MASK_TWO && !HealthAbovePct(40)) | |
| 634 | {
| |
| 635 | events.SetPhase(PHASE_TRANSITION); | |
| 636 | me->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_MOD_TAUNT, true); | |
| 637 | me->GetMotionMaster()->MovePoint(POINT_CENTER_2, CenterPosition); | |
| 638 | return; | |
| 639 | } | |
| 640 | ||
| 641 | if (events.GetPhaseMask() & PHASE_MASK_THREE && !HealthAbovePct(10)) | |
| 642 | {
| |
| 643 | me->SetReactState(REACT_PASSIVE); | |
| 644 | me->AttackStop(); | |
| 645 | events.Reset(); | |
| 646 | events.SetPhase(PHASE_OUTRO); | |
| 647 | summons.DespawnAll(); | |
| 648 | SendMusicToPlayers(MUSIC_FURY_OF_FROSTMOURNE); | |
| 649 | DoCastAOE(SPELL_FURY_OF_FROSTMOURNE); | |
| 650 | me->AddUnitMovementFlag(MOVEMENTFLAG_WALKING); | |
| 651 | events.ScheduleEvent(EVENT_OUTRO_TALK_1, 2600, 0, PHASE_OUTRO); | |
| 652 | events.ScheduleEvent(EVENT_OUTRO_EMOTE_TALK, 6600, 0, PHASE_OUTRO); | |
| 653 | events.ScheduleEvent(EVENT_OUTRO_EMOTE_TALK, 17600, 0, PHASE_OUTRO); | |
| 654 | events.ScheduleEvent(EVENT_OUTRO_EMOTE_TALK, 27600, 0, PHASE_OUTRO); | |
| 655 | events.ScheduleEvent(EVENT_OUTRO_TALK_2, 34600, 0, PHASE_OUTRO); | |
| 656 | events.ScheduleEvent(EVENT_OUTRO_TALK_3, 43600, 0, PHASE_OUTRO); | |
| 657 | events.ScheduleEvent(EVENT_EMOTE_CAST_SHOUT, 54600, 0, PHASE_OUTRO); | |
| 658 | events.ScheduleEvent(EVENT_OUTRO_EMOTE_TALK, 58600, 0, PHASE_OUTRO); | |
| 659 | events.ScheduleEvent(EVENT_OUTRO_MOVE_CENTER, 69600, 0, PHASE_OUTRO); | |
| 660 | // stop here. rest will get scheduled from MovementInform | |
| 661 | return; | |
| 662 | } | |
| 663 | } | |
| 664 | ||
| 665 | void JustSummoned(Creature* summon) | |
| 666 | {
| |
| 667 | switch (summon->GetEntry()) | |
| 668 | {
| |
| 669 | case NPC_SHAMBLING_HORROR: | |
| 670 | case NPC_DRUDGE_GHOUL: | |
| 671 | summon->CastSpell(summon, SPELL_RISEN_WITCH_DOCTOR_SPAWN, true); | |
| 672 | summon->SetReactState(REACT_PASSIVE); | |
| 673 | summon->HandleEmoteCommand(EMOTE_ONESHOT_EMERGE); | |
| 674 | summon->m_Events.AddEvent(new StartMovementEvent(me, summon), summon->m_Events.CalculateTime(5000)); | |
| 675 | break; | |
| 676 | case NPC_ICE_SPHERE: | |
| 677 | {
| |
| 678 | if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 0.0f, true)) | |
| 679 | {
| |
| 680 | summon->SetReactState(REACT_PASSIVE); | |
| 681 | summon->CastSpell(summon, SPELL_ICE_SPHERE, false); | |
| 682 | summon->CastSpell(summon, SPELL_ICE_BURST_TARGET_SEARCH, false); | |
| 683 | summon->CastSpell(target, SPELL_ICE_PULSE, false); | |
| 684 | summon->ClearUnitState(UNIT_STAT_CASTING); | |
| 685 | summon->GetMotionMaster()->MoveFollow(target, 0.0f, 0.0f); | |
| 686 | } | |
| 687 | else | |
| 688 | summon->DespawnOrUnsummon(); | |
| 689 | break; | |
| 690 | } | |
| 691 | case NPC_DEFILE: | |
| 692 | summon->SetReactState(REACT_PASSIVE); | |
| 693 | summon->CastSpell(summon, SPELL_DEFILE_AURA, false); | |
| 694 | break; | |
| 695 | case NPC_FROSTMOURNE_TRIGGER: | |
| 696 | {
| |
| 697 | summons.Summon(summon); | |
| 698 | summon->CastSpell((Unit*)NULL, SPELL_BROKEN_FROSTMOURNE, true); | |
| 699 | ||
| 700 | SendLightOverride(LIGHT_SOULSTORM, 10000); | |
| 701 | SendWeather(WEATHER_STATE_BLACKSNOW); | |
| 702 | ||
| 703 | events.ScheduleEvent(EVENT_OUTRO_SOUL_BARRAGE, 5000, 0, PHASE_OUTRO); | |
| 704 | return; | |
| 705 | } | |
| 706 | case NPC_VILE_SPIRIT: | |
| 707 | {
| |
| 708 | summons.Summon(summon); | |
| 709 | if (events.GetPhaseMask() & PHASE_MASK_FROSTMOURNE) | |
| 710 | {
| |
| 711 | TeleportSpirit(summon); | |
| 712 | return; | |
| 713 | } | |
| 714 | ||
| 715 | summon->SetReactState(REACT_PASSIVE); | |
| 716 | summon->SetSpeed(MOVE_FLIGHT, 0.5f); | |
| 717 | summon->GetMotionMaster()->MoveRandom(10.0f); | |
| 718 | summon->m_Events.AddEvent(new VileSpiritActivateEvent(summon), summon->m_Events.CalculateTime(15000)); | |
| 719 | return; | |
| 720 | } | |
| 721 | case NPC_STRANGULATE_VEHICLE: | |
| 722 | summons.Summon(summon); | |
| 723 | return; | |
| 724 | default: | |
| 725 | break; | |
| 726 | } | |
| 727 | ||
| 728 | BossAI::JustSummoned(summon); | |
| 729 | } | |
| 730 | ||
| 731 | void SummonedCreatureDies(Creature* summon, Unit* /*killer*/) | |
| 732 | {
| |
| 733 | switch (summon->GetEntry()) | |
| 734 | {
| |
| 735 | case NPC_SHAMBLING_HORROR: | |
| 736 | case NPC_DRUDGE_GHOUL: | |
| 737 | case NPC_ICE_SPHERE: | |
| 738 | case NPC_VALKYR_SHADOWGUARD: | |
| 739 | case NPC_RAGING_SPIRIT: | |
| 740 | case NPC_VILE_SPIRIT: | |
| 741 | case NPC_WICKED_SPIRIT: | |
| 742 | summon->ToTempSummon()->SetTempSummonType(TEMPSUMMON_CORPSE_DESPAWN); | |
| 743 | break; | |
| 744 | default: | |
| 745 | break; | |
| 746 | } | |
| 747 | } | |
| 748 | ||
| 749 | void SpellHit(Unit* /*caster*/, SpellInfo const* spell) | |
| 750 | {
| |
| 751 | if (spell->Id == SPELL_HARVESTED_SOUL && me->isInCombat() && !IsHeroic()) | |
| 752 | Talk(SAY_LK_FROSTMOURNE_KILL); | |
| 753 | } | |
| 754 | ||
| 755 | void SpellHitTarget(Unit* /*target*/, SpellInfo const* spell) | |
| 756 | {
| |
| 757 | if (spell->Id == REMORSELESS_WINTER_1 || spell->Id == REMORSELESS_WINTER_2) | |
| 758 | {
| |
| 759 | SendLightOverride(LIGHT_SNOWSTORM, 5000); | |
| 760 | SendWeather(WEATHER_STATE_LIGHT_SNOW); | |
| 761 | } | |
| 762 | } | |
| 763 | ||
| 764 | void MovementInform(uint32 type, uint32 pointId) | |
| 765 | {
| |
| 766 | if (type != POINT_MOTION_TYPE) | |
| 767 | return; | |
| 768 | ||
| 769 | switch (pointId) | |
| 770 | {
| |
| 771 | case POINT_LK_INTRO_1: | |
| 772 | // schedule for next update cycle, current update must finalize movement | |
| 773 | events.ScheduleEvent(EVENT_INTRO_MOVE_2, 1, 0, PHASE_INTRO); | |
| 774 | break; | |
| 775 | case POINT_LK_INTRO_2: | |
| 776 | events.ScheduleEvent(EVENT_INTRO_MOVE_3, 1, 0, PHASE_INTRO); | |
| 777 | break; | |
| 778 | case POINT_LK_INTRO_3: | |
| 779 | if (Creature* tirion = ObjectAccessor::GetCreature(*me, instance->GetData64(DATA_HIGHLORD_TIRION_FORDRING))) | |
| 780 | tirion->AI()->DoAction(ACTION_CONTINUE_INTRO); | |
| 781 | events.ScheduleEvent(EVENT_INTRO_TALK_1, 9000, 0, PHASE_INTRO); | |
| 782 | break; | |
| 783 | case POINT_CENTER_1: | |
| 784 | me->SetFacing(0.0f); | |
| 785 | Talk(SAY_LK_REMORSELESS_WINTER); | |
| 786 | SendMusicToPlayers(MUSIC_SPECIAL); | |
| 787 | me->SetReactState(REACT_PASSIVE); | |
| 788 | me->AttackStop(); | |
| 789 | DoCast(me, SPELL_REMORSELESS_WINTER_1); | |
| 790 | events.DelayEvents(62500, EVENT_GROUP_BERSERK); // delay berserk timer, its not ticking during phase transitions | |
| 791 | events.ScheduleEvent(EVENT_QUAKE, 62500, 0, PHASE_TRANSITION); | |
| 792 | events.ScheduleEvent(EVENT_PAIN_AND_SUFFERING, 4000, 0, PHASE_TRANSITION); | |
| 793 | events.ScheduleEvent(EVENT_SUMMON_ICE_SPHERE, 8000, 0, PHASE_TRANSITION); | |
| 794 | events.ScheduleEvent(EVENT_SUMMON_RAGING_SPIRIT, 3000, 0, PHASE_TRANSITION); | |
| 795 | events.ScheduleEvent(EVENT_SUMMON_VALKYR, 78000, 0, PHASE_TWO); | |
| 796 | events.ScheduleEvent(EVENT_INFEST, 70000, 0, PHASE_TWO); | |
| 797 | events.ScheduleEvent(EVENT_DEFILE, 97000, 0, PHASE_TWO); | |
| 798 | events.ScheduleEvent(EVENT_SOUL_REAPER, 94000, 0, PHASE_TWO); | |
| 799 | me->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_MOD_TAUNT, false); | |
| 800 | break; | |
| 801 | case POINT_CENTER_2: | |
| 802 | me->SetFacing(0.0f); | |
| 803 | Talk(SAY_LK_REMORSELESS_WINTER); | |
| 804 | SendMusicToPlayers(MUSIC_SPECIAL); | |
| 805 | me->SetReactState(REACT_PASSIVE); | |
| 806 | me->AttackStop(); | |
| 807 | DoCast(me, SPELL_REMORSELESS_WINTER_2); | |
| 808 | summons.DespawnEntry(NPC_VALKYR_SHADOWGUARD); | |
| 809 | events.DelayEvents(62500, EVENT_GROUP_BERSERK); // delay berserk timer, its not ticking during phase transitions | |
| 810 | events.ScheduleEvent(EVENT_QUAKE_2, 62500, 0, PHASE_TRANSITION); | |
| 811 | events.ScheduleEvent(EVENT_PAIN_AND_SUFFERING, 6000, 0, PHASE_TRANSITION); | |
| 812 | events.ScheduleEvent(EVENT_SUMMON_ICE_SPHERE, 8000, 0, PHASE_TRANSITION); | |
| 813 | events.ScheduleEvent(EVENT_SUMMON_RAGING_SPIRIT, 5000, 0, PHASE_TRANSITION); | |
| 814 | events.ScheduleEvent(EVENT_DEFILE, 95500, 0, PHASE_THREE); | |
| 815 | events.ScheduleEvent(EVENT_SOUL_REAPER, 99500, 0, PHASE_THREE); | |
| 816 | events.ScheduleEvent(EVENT_VILE_SPIRITS, 79500, EVENT_GROUP_VILE_SPIRITS, PHASE_THREE); | |
| 817 | events.ScheduleEvent(IsHeroic() ? EVENT_HARVEST_SOULS : EVENT_HARVEST_SOUL, 73500, 0, PHASE_THREE); | |
| 818 | me->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_MOD_TAUNT, false); | |
| 819 | break; | |
| 820 | case POINT_LK_OUTRO_1: | |
| 821 | events.ScheduleEvent(EVENT_OUTRO_TALK_4, 1, 0, PHASE_OUTRO); | |
| 822 | events.ScheduleEvent(EVENT_OUTRO_RAISE_DEAD, 1000, 0, PHASE_OUTRO); | |
| 823 | events.ScheduleEvent(EVENT_OUTRO_TALK_5, 29000, 0, PHASE_OUTRO); | |
| 824 | break; | |
| 825 | case POINT_LK_OUTRO_2: | |
| 826 | if (Creature* tirion = ObjectAccessor::GetCreature(*me, instance->GetData64(DATA_HIGHLORD_TIRION_FORDRING))) | |
| 827 | tirion->AI()->Talk(SAY_TIRION_OUTRO_2); | |
| 828 | if (Creature* frostmourne = me->FindNearestCreature(NPC_FROSTMOURNE_TRIGGER, 50.0f)) | |
| 829 | frostmourne->AI()->DoAction(ACTION_SUMMON_TERENAS); | |
| 830 | break; | |
| 831 | default: | |
| 832 | break; | |
| 833 | } | |
| 834 | } | |
| 835 | ||
| 836 | void UpdateAI(uint32 const diff) | |
| 837 | {
| |
| 838 | // check phase first to prevent updating victim and entering evade mode when not wanted | |
| 839 | if (!(events.GetPhaseMask() & PHASE_MASK_NO_VICTIM)) | |
| 840 | if (!UpdateVictim()) | |
| 841 | return; | |
| 842 | ||
| 843 | events.Update(diff); | |
| 844 | ||
| 845 | // during Remorseless Winter phases The Lich King is channeling a spell, but we must continue casting other spells | |
| 846 | if (me->HasUnitState(UNIT_STAT_CASTING) && !(events.GetPhaseMask() & PHASE_MASK_NO_CAST_CHECK)) | |
| 847 | return; | |
| 848 | ||
| 849 | while (uint32 eventId = events.ExecuteEvent()) | |
| 850 | {
| |
| 851 | switch (eventId) | |
| 852 | {
| |
| 853 | case EVENT_INTRO_MOVE_1: | |
| 854 | me->SetSheath(SHEATH_STATE_MELEE); | |
| 855 | me->RemoveAurasDueToSpell(SPELL_EMOTE_SIT_NO_SHEATH); | |
| 856 | me->AddUnitMovementFlag(MOVEMENTFLAG_WALKING); | |
| 857 | me->GetMotionMaster()->MovePoint(POINT_LK_INTRO_1, LichKingIntro[0]); | |
| 858 | break; | |
| 859 | case EVENT_INTRO_MOVE_2: | |
| 860 | me->GetMotionMaster()->MovePoint(POINT_LK_INTRO_2, LichKingIntro[1]); | |
| 861 | break; | |
| 862 | case EVENT_INTRO_MOVE_3: | |
| 863 | me->GetMotionMaster()->MovePoint(POINT_LK_INTRO_3, LichKingIntro[2]); | |
| 864 | break; | |
| 865 | case EVENT_INTRO_TALK_1: | |
| 866 | Talk(SAY_LK_INTRO_2); | |
| 867 | // for some reason blizz sends 2 emotes in row here so (we handle one in Talk) | |
| 868 | me->HandleEmoteCommand(EMOTE_ONESHOT_TALK_NOSHEATHE); | |
| 869 | events.ScheduleEvent(EVENT_EMOTE_CAST_SHOUT, 7000, 0, PHASE_INTRO); | |
| 870 | events.ScheduleEvent(EVENT_INTRO_EMOTE_1, 13000, 0, PHASE_INTRO); | |
| 871 | events.ScheduleEvent(EVENT_EMOTE_CAST_SHOUT, 18000, 0, PHASE_INTRO); | |
| 872 | events.ScheduleEvent(EVENT_INTRO_CAST_FREEZE, 31000, 0, PHASE_INTRO); | |
| 873 | break; | |
| 874 | case EVENT_EMOTE_CAST_SHOUT: | |
| 875 | DoCast(me, SPELL_EMOTE_SHOUT_NO_SHEATH, false); | |
| 876 | break; | |
| 877 | case EVENT_INTRO_EMOTE_1: | |
| 878 | me->HandleEmoteCommand(EMOTE_ONESHOT_POINT_NOSHEATHE); | |
| 879 | break; | |
| 880 | case EVENT_INTRO_CAST_FREEZE: | |
| 881 | Talk(SAY_LK_INTRO_3); | |
| 882 | DoCastAOE(SPELL_ICE_LOCK, false); | |
| 883 | events.ScheduleEvent(EVENT_FINISH_INTRO, 1000, 0, PHASE_INTRO); | |
| 884 | break; | |
| 885 | case EVENT_FINISH_INTRO: | |
| 886 | me->RemoveUnitMovementFlag(MOVEMENTFLAG_WALKING); | |
| 887 | me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_OOC_NOT_ATTACKABLE); | |
| 888 | me->SetReactState(REACT_AGGRESSIVE); | |
| 889 | events.SetPhase(PHASE_ONE); | |
| 890 | me->SetInCombatWithZone(); | |
| 891 | break; | |
| 892 | case EVENT_SUMMON_SHAMBLING_HORROR: | |
| 893 | DoCast(me, SPELL_SUMMON_SHAMBLING_HORROR); | |
| 894 | SendMusicToPlayers(MUSIC_SPECIAL); | |
| 895 | events.ScheduleEvent(EVENT_SUMMON_SHAMBLING_HORROR, 60000, 0, PHASE_ONE); | |
| 896 | break; | |
| 897 | case EVENT_SUMMON_DRUDGE_GHOUL: | |
| 898 | DoCast(me, SPELL_SUMMON_DRUDGE_GHOULS); | |
| 899 | events.ScheduleEvent(EVENT_SUMMON_DRUDGE_GHOUL, 30000, 0, PHASE_ONE); | |
| 900 | break; | |
| 901 | case EVENT_INFEST: | |
| 902 | DoCast(me, SPELL_INFEST); | |
| 903 | events.ScheduleEvent(EVENT_INFEST, urand(21000, 24000), 0, (events.GetPhaseMask() & PHASE_MASK_ONE) ? PHASE_ONE : PHASE_TWO); | |
| 904 | break; | |
| 905 | case EVENT_NECROTIC_PLAGUE: | |
| 906 | if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 1, NecroticPlagueTargetCheck(me, NECROTIC_PLAGUE_LK, NECROTIC_PLAGUE_PLR))) | |
| 907 | {
| |
| 908 | Talk(EMOTE_NECROTIC_PLAGUE_WARNING, target->GetGUID()); | |
| 909 | DoCast(target, SPELL_NECROTIC_PLAGUE); | |
| 910 | } | |
| 911 | events.ScheduleEvent(EVENT_NECROTIC_PLAGUE, urand(30000, 33000), 0, PHASE_ONE); | |
| 912 | break; | |
| 913 | case EVENT_SHADOW_TRAP: | |
| 914 | if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, NonTankTargetSelector(me))) | |
| 915 | DoCast(target, SPELL_SHADOW_TRAP); | |
| 916 | events.ScheduleEvent(EVENT_SHADOW_TRAP, 15500, 0, PHASE_ONE); | |
| 917 | break; | |
| 918 | case EVENT_SOUL_REAPER: | |
| 919 | DoCastVictim(SPELL_SOUL_REAPER); | |
| 920 | events.ScheduleEvent(EVENT_SOUL_REAPER, urand(33000, 35000), 0, PHASE_TWO_THREE); | |
| 921 | break; | |
| 922 | case EVENT_DEFILE: | |
| 923 | if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 1, 0.0f, true, -SPELL_HARVEST_SOUL_VALKYR)) | |
| 924 | {
| |
| 925 | Talk(EMOTE_DEFILE_WARNING); | |
| 926 | DoCast(target, SPELL_DEFILE); | |
| 927 | } | |
| 928 | events.ScheduleEvent(EVENT_DEFILE, urand(32000, 35000), 0, PHASE_TWO_THREE); | |
| 929 | break; | |
| 930 | case EVENT_HARVEST_SOUL: | |
| 931 | Talk(SAY_LK_HARVEST_SOUL); | |
| 932 | if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, SpellTargetSelector(me, SPELL_HARVEST_SOUL))) | |
| 933 | DoCast(target, SPELL_HARVEST_SOUL); | |
| 934 | events.ScheduleEvent(EVENT_HARVEST_SOUL, 75000, 0, PHASE_THREE); | |
| 935 | break; | |
| 936 | case EVENT_PAIN_AND_SUFFERING: | |
| 937 | if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 0.0f, true)) | |
| 938 | me->CastSpell(target, SPELL_PAIN_AND_SUFFERING, TRIGGERED_NONE); | |
| 939 | events.ScheduleEvent(EVENT_PAIN_AND_SUFFERING, urand(1500, 4000), 0, PHASE_TRANSITION); | |
| 940 | break; | |
| 941 | case EVENT_SUMMON_ICE_SPHERE: | |
| 942 | DoCastAOE(SPELL_SUMMON_ICE_SPHERE); | |
| 943 | events.ScheduleEvent(EVENT_SUMMON_ICE_SPHERE, urand(7500, 8500), 0, PHASE_TRANSITION); | |
| 944 | break; | |
| 945 | case EVENT_SUMMON_RAGING_SPIRIT: | |
| 946 | if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 0.0f, true)) | |
| 947 | me->CastSpell(target, SPELL_RAGING_SPIRIT, TRIGGERED_NONE); | |
| 948 | events.ScheduleEvent(EVENT_SUMMON_RAGING_SPIRIT, urand(22000, 23000), 0, PHASE_TRANSITION); | |
| 949 | break; | |
| 950 | case EVENT_QUAKE: | |
| 951 | events.SetPhase(PHASE_TWO); | |
| 952 | me->ClearUnitState(UNIT_STAT_CASTING); // clear state to ensure check in DoCastAOE passes | |
| 953 | DoCastAOE(SPELL_QUAKE); | |
| 954 | SendMusicToPlayers(MUSIC_SPECIAL); | |
| 955 | Talk(SAY_LK_QUAKE); | |
| 956 | break; | |
| 957 | case EVENT_QUAKE_2: | |
| 958 | events.SetPhase(PHASE_THREE); | |
| 959 | me->ClearUnitState(UNIT_STAT_CASTING); // clear state to ensure check in DoCastAOE passes | |
| 960 | DoCastAOE(SPELL_QUAKE); | |
| 961 | SendMusicToPlayers(MUSIC_SPECIAL); | |
| 962 | Talk(SAY_LK_QUAKE); | |
| 963 | break; | |
| 964 | case EVENT_SUMMON_VALKYR: | |
| 965 | SendMusicToPlayers(MUSIC_SPECIAL); | |
| 966 | Talk(SAY_LK_SUMMON_VALKYR); | |
| 967 | DoCastAOE(SUMMON_VALKYR); | |
| 968 | events.ScheduleEvent(EVENT_SUMMON_VALKYR, urand(45000, 50000), 0, PHASE_TWO); | |
| 969 | break; | |
| 970 | case EVENT_START_ATTACK: | |
| 971 | me->SetReactState(REACT_AGGRESSIVE); | |
| 972 | if (events.GetPhaseMask() & PHASE_MASK_FROSTMOURNE) | |
| 973 | events.SetPhase(PHASE_THREE); | |
| 974 | break; | |
| 975 | case EVENT_VILE_SPIRITS: | |
| 976 | SendMusicToPlayers(MUSIC_SPECIAL); | |
| 977 | DoCastAOE(SPELL_VILE_SPIRITS); | |
| 978 | events.ScheduleEvent(EVENT_VILE_SPIRITS, urand(35000, 40000), EVENT_GROUP_VILE_SPIRITS, PHASE_THREE); | |
| 979 | break; | |
| 980 | case EVENT_WICKED_SPIRITS: | |
| 981 | DoCastAOE(SPELL_VILE_SPIRITS); | |
| 982 | events.ScheduleEvent(EVENT_WICKED_SPIRITS, urand(35000, 40000), 0, PHASE_FROSTMOURNE); | |
| 983 | break; | |
| 984 | case EVENT_HARVEST_SOULS: | |
| 985 | Talk(SAY_LK_HARVEST_SOUL); | |
| 986 | DoCastAOE(SPELL_HARVEST_SOULS); | |
| 987 | events.ScheduleEvent(EVENT_HARVEST_SOULS, urand(100000, 110000), 0, PHASE_THREE); | |
| 988 | events.SetPhase(PHASE_FROSTMOURNE); // will stop running UpdateVictim (no evading) | |
| 989 | me->SetReactState(REACT_PASSIVE); | |
| 990 | me->AttackStop(); | |
| 991 | events.ScheduleEvent(EVENT_WICKED_SPIRITS, events.GetNextEventTime(EVENT_VILE_SPIRITS) - events.GetTimer(), 0, PHASE_FROSTMOURNE); | |
| 992 | events.DelayEvents(50000, EVENT_GROUP_VILE_SPIRITS); | |
| 993 | events.RescheduleEvent(EVENT_DEFILE, 50000, 0, PHASE_THREE); | |
| 994 | events.RescheduleEvent(EVENT_SOUL_REAPER, urand(57000, 62000), 0, PHASE_THREE); | |
| 995 | events.ScheduleEvent(EVENT_START_ATTACK, 49000); | |
| 996 | events.ScheduleEvent(EVENT_FROSTMOURNE_HEROIC, 6500); | |
| 997 | break; | |
| 998 | case EVENT_FROSTMOURNE_HEROIC: | |
| 999 | if (TempSummon* terenas = me->GetMap()->SummonCreature(NPC_TERENAS_MENETHIL_FROSTMOURNE_H, TerenasSpawnHeroic, NULL, 50000)) | |
| 1000 | {
| |
| 1001 | terenas->AI()->DoAction(ACTION_FROSTMOURNE_INTRO); | |
| 1002 | std::list<Creature*> triggers; | |
| 1003 | GetCreatureListWithEntryInGrid(triggers, terenas, NPC_WORLD_TRIGGER_INFINITE_AOI, 100.0f); | |
| 1004 | if (!triggers.empty()) | |
| 1005 | {
| |
| 1006 | triggers.sort(Trinity::ObjectDistanceOrderPred(terenas, true)); | |
| 1007 | Unit* spawner = triggers.front(); | |
| 1008 | spawner->CastSpell(spawner, SPELL_SUMMON_SPIRIT_BOMB_1, true); // summons bombs randomly | |
| 1009 | spawner->CastSpell(spawner, SPELL_SUMMON_SPIRIT_BOMB_2, true); // summons bombs on players | |
| 1010 | } | |
| 1011 | ||
| 1012 | for (SummonList::iterator i = summons.begin(); i != summons.end(); ++i) | |
| 1013 | {
| |
| 1014 | Creature* summon = ObjectAccessor::GetCreature(*me, *i); | |
| 1015 | if (summon && summon->GetEntry() == NPC_VILE_SPIRIT) | |
| 1016 | TeleportSpirit(summon); | |
| 1017 | } | |
| 1018 | } | |
| 1019 | break; | |
| 1020 | case EVENT_OUTRO_TALK_1: | |
| 1021 | Talk(SAY_LK_OUTRO_1); | |
| 1022 | DoCastAOE(SPELL_FURY_OF_FROSTMOURNE_NO_REZ, true); | |
| 1023 | break; | |
| 1024 | case EVENT_OUTRO_TALK_2: | |
| 1025 | Talk(SAY_LK_OUTRO_2); | |
| 1026 | DoCastAOE(SPELL_EMOTE_QUESTION_NO_SHEATH); | |
| 1027 | break; | |
| 1028 | case EVENT_OUTRO_EMOTE_TALK: | |
| 1029 | me->HandleEmoteCommand(EMOTE_ONESHOT_TALK_NOSHEATHE); | |
| 1030 | break; | |
| 1031 | case EVENT_OUTRO_TALK_3: | |
| 1032 | if (Creature* tirion = ObjectAccessor::GetCreature(*me, instance->GetData64(DATA_HIGHLORD_TIRION_FORDRING))) | |
| 1033 | me->SetFacing(0.0f, tirion); | |
| 1034 | Talk(SAY_LK_OUTRO_3); | |
| 1035 | break; | |
| 1036 | case EVENT_OUTRO_MOVE_CENTER: | |
| 1037 | me->GetMotionMaster()->MovePoint(POINT_LK_OUTRO_1, CenterPosition); | |
| 1038 | break; | |
| 1039 | case EVENT_OUTRO_TALK_4: | |
| 1040 | me->SetFacing(0.01745329f); | |
| 1041 | Talk(SAY_LK_OUTRO_4); | |
| 1042 | break; | |
| 1043 | case EVENT_OUTRO_RAISE_DEAD: | |
| 1044 | DoCastAOE(SPELL_RAISE_DEAD); | |
| 1045 | me->ClearUnitState(UNIT_STAT_CASTING); | |
| 1046 | SendMusicToPlayers(MUSIC_FINAL); | |
| 1047 | break; | |
| 1048 | case EVENT_OUTRO_TALK_5: | |
| 1049 | Talk(SAY_LK_OUTRO_5); | |
| 1050 | if (Creature* tirion = ObjectAccessor::GetCreature(*me, instance->GetData64(DATA_HIGHLORD_TIRION_FORDRING))) | |
| 1051 | tirion->AI()->DoAction(ACTION_OUTRO); | |
| 1052 | break; | |
| 1053 | case EVENT_OUTRO_TALK_6: | |
| 1054 | Talk(SAY_LK_OUTRO_6); | |
| 1055 | if (Creature* tirion = ObjectAccessor::GetCreature(*me, instance->GetData64(DATA_HIGHLORD_TIRION_FORDRING))) | |
| 1056 | tirion->SetFacing(0.0f, me); | |
| 1057 | me->ClearUnitState(UNIT_STAT_CASTING); | |
| 1058 | DoCastAOE(SPELL_SUMMON_BROKEN_FROSTMOURNE_3); | |
| 1059 | SetEquipmentSlots(false, EQUIP_UNEQUIP); | |
| 1060 | break; | |
| 1061 | case EVENT_OUTRO_SOUL_BARRAGE: | |
| 1062 | DoCastAOE(SPELL_SOUL_BARRAGE); | |
| 1063 | sCreatureTextMgr->SendSound(me, SOUND_PAIN, CHAT_MSG_MONSTER_YELL, 0, TEXT_RANGE_NORMAL, TEAM_OTHER, false); | |
| 1064 | // set flight | |
| 1065 | me->AddUnitMovementFlag(MOVEMENTFLAG_LEVITATING); | |
| 1066 | me->SetByteFlag(UNIT_FIELD_BYTES_1, 3, 0x03); | |
| 1067 | me->GetMotionMaster()->MovePoint(POINT_LK_OUTRO_2, OutroFlying); | |
| 1068 | break; | |
| 1069 | case EVENT_OUTRO_TALK_7: | |
| 1070 | Talk(SAY_LK_OUTRO_7); | |
| 1071 | break; | |
| 1072 | case EVENT_OUTRO_TALK_8: | |
| 1073 | Talk(SAY_LK_OUTRO_8); | |
| 1074 | break; | |
| 1075 | case EVENT_BERSERK: | |
| 1076 | Talk(SAY_LK_BERSERK); | |
| 1077 | DoCast(me, SPELL_BERSERK2); | |
| 1078 | break; | |
| 1079 | default: | |
| 1080 | break; | |
| 1081 | } | |
| 1082 | } | |
| 1083 | ||
| 1084 | DoMeleeAttackIfReady(); | |
| 1085 | } | |
| 1086 | ||
| 1087 | private: | |
| 1088 | ||
| 1089 | void TeleportSpirit(Creature* summon) | |
| 1090 | {
| |
| 1091 | float dist = me->GetObjectSize() + (15.0f - me->GetObjectSize()) * float(rand_norm()); | |
| 1092 | float angle = float(rand_norm()) * float(2.0f * M_PI); | |
| 1093 | Position dest = TerenasSpawnHeroic; | |
| 1094 | me->MovePosition(dest, dist, angle); | |
| 1095 | dest.m_positionZ += 15.0f; | |
| 1096 | summon->UpdateEntry(NPC_WICKED_SPIRIT); | |
| 1097 | summon->SetReactState(REACT_PASSIVE); | |
| 1098 | summon->NearTeleportTo(dest.GetPositionX(), dest.GetPositionY(), dest.GetPositionZ(), dest.GetOrientation()); | |
| 1099 | summon->SetSpeed(MOVE_FLIGHT, 0.5f); | |
| 1100 | summon->m_Events.KillAllEvents(true); | |
| 1101 | summon->m_Events.AddEvent(new VileSpiritActivateEvent(summon), summon->m_Events.CalculateTime(1000)); | |
| 1102 | } | |
| 1103 | ||
| 1104 | void SendMusicToPlayers(uint32 musicId) const | |
| 1105 | {
| |
| 1106 | WorldPacket data(SMSG_PLAY_MUSIC, 4); | |
| 1107 | data << uint32(musicId); | |
| 1108 | SendPacketToPlayers(&data); | |
| 1109 | } | |
| 1110 | ||
| 1111 | void SendLightOverride(uint32 overrideId, uint32 fadeInTime) const | |
| 1112 | {
| |
| 1113 | WorldPacket data(SMSG_OVERRIDE_LIGHT, 12); | |
| 1114 | data << uint32(2488); // Light.dbc entry (map default) | |
| 1115 | data << uint32(overrideId); // Light.dbc entry (override) | |
| 1116 | data << uint32(fadeInTime); | |
| 1117 | SendPacketToPlayers(&data); | |
| 1118 | } | |
| 1119 | ||
| 1120 | void SendWeather(WeatherState weather) const | |
| 1121 | {
| |
| 1122 | WorldPacket data(SMSG_WEATHER, 9); | |
| 1123 | data << uint32(weather); | |
| 1124 | data << float(0.5f); | |
| 1125 | data << uint8(0); | |
| 1126 | SendPacketToPlayers(&data); | |
| 1127 | } | |
| 1128 | ||
| 1129 | // Send packet to all players in The Frozen Throne | |
| 1130 | void SendPacketToPlayers(WorldPacket const* data) const | |
| 1131 | {
| |
| 1132 | Map::PlayerList const& players = me->GetMap()->GetPlayers(); | |
| 1133 | if (!players.isEmpty()) | |
| 1134 | for (Map::PlayerList::const_iterator itr = players.begin(); itr != players.end(); ++itr) | |
| 1135 | if (Player* player = itr->getSource()) | |
| 1136 | if (player->GetAreaId() == AREA_THE_FROZEN_THRONE) | |
| 1137 | player->GetSession()->SendPacket(data); | |
| 1138 | } | |
| 1139 | ||
| 1140 | uint32 _necroticPlagueStack; | |
| 1141 | uint32 _vileSpiritExplosions; | |
| 1142 | }; | |
| 1143 | ||
| 1144 | CreatureAI* GetAI(Creature* creature) const | |
| 1145 | {
| |
| 1146 | return GetIcecrownCitadelAI<boss_the_lich_kingAI>(creature); | |
| 1147 | } | |
| 1148 | }; | |
| 1149 | ||
| 1150 | class npc_tirion_fordring_tft : public CreatureScript | |
| 1151 | {
| |
| 1152 | public: | |
| 1153 | npc_tirion_fordring_tft() : CreatureScript("npc_tirion_fordring_tft") { }
| |
| 1154 | ||
| 1155 | struct npc_tirion_fordringAI : public ScriptedAI | |
| 1156 | {
| |
| 1157 | npc_tirion_fordringAI(Creature* creature) : ScriptedAI(creature), | |
| 1158 | _instance(creature->GetInstanceScript()) | |
| 1159 | {
| |
| 1160 | } | |
| 1161 | ||
| 1162 | void Reset() | |
| 1163 | {
| |
| 1164 | _events.Reset(); | |
| 1165 | if (_instance->GetBossState(DATA_THE_LICH_KING) == DONE) | |
| 1166 | me->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); | |
| 1167 | } | |
| 1168 | ||
| 1169 | void MovementInform(uint32 type, uint32 id) | |
| 1170 | {
| |
| 1171 | if (type != POINT_MOTION_TYPE) | |
| 1172 | return; | |
| 1173 | ||
| 1174 | switch (id) | |
| 1175 | {
| |
| 1176 | case POINT_TIRION_INTRO: | |
| 1177 | me->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_STATE_READY2H); | |
| 1178 | if (Creature* theLichKing = ObjectAccessor::GetCreature(*me, _instance->GetData64(DATA_THE_LICH_KING))) | |
| 1179 | theLichKing->AI()->DoAction(ACTION_START_ENCOUNTER); | |
| 1180 | break; | |
| 1181 | case POINT_TIRION_OUTRO_1: | |
| 1182 | _events.ScheduleEvent(EVENT_OUTRO_JUMP, 1, 0, PHASE_OUTRO); | |
| 1183 | break; | |
| 1184 | } | |
| 1185 | } | |
| 1186 | ||
| 1187 | void DoAction(int32 const action) | |
| 1188 | {
| |
| 1189 | switch (action) | |
| 1190 | {
| |
| 1191 | case ACTION_CONTINUE_INTRO: | |
| 1192 | Talk(SAY_TIRION_INTRO_1); | |
| 1193 | _events.ScheduleEvent(EVENT_INTRO_TALK_1, 34000, 0, PHASE_INTRO); | |
| 1194 | break; | |
| 1195 | case ACTION_OUTRO: | |
| 1196 | _events.SetPhase(PHASE_OUTRO); | |
| 1197 | _events.ScheduleEvent(EVENT_OUTRO_TALK_1, 7000, 0, PHASE_OUTRO); | |
| 1198 | _events.ScheduleEvent(EVENT_OUTRO_BLESS, 18000, 0, PHASE_OUTRO); | |
| 1199 | _events.ScheduleEvent(EVENT_OUTRO_REMOVE_ICE, 23000, 0, PHASE_OUTRO); | |
| 1200 | _events.ScheduleEvent(EVENT_OUTRO_MOVE_1, 25000, 0, PHASE_OUTRO); | |
| 1201 | break; | |
| 1202 | } | |
| 1203 | } | |
| 1204 | ||
| 1205 | void SpellHit(Unit* /*caster*/, SpellInfo const* spell) | |
| 1206 | {
| |
| 1207 | if (spell->Id == SPELL_ICE_LOCK) | |
| 1208 | me->SetFacing(3.085098f); | |
| 1209 | else if (spell->Id == SPELL_BROKEN_FROSTMOURNE_KNOCK) | |
| 1210 | SetEquipmentSlots(true); // remove glow on ashbringer | |
| 1211 | } | |
| 1212 | ||
| 1213 | void sGossipSelect(Player* /*player*/, uint32 sender, uint32 action) | |
| 1214 | {
| |
| 1215 | if (me->GetCreatureInfo()->GossipMenuId == sender && !action) | |
| 1216 | {
| |
| 1217 | _events.SetPhase(PHASE_INTRO); | |
| 1218 | me->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); | |
| 1219 | me->AddUnitMovementFlag(MOVEMENTFLAG_WALKING); | |
| 1220 | me->GetMotionMaster()->MovePoint(POINT_TIRION_INTRO, TirionIntro); | |
| 1221 | } | |
| 1222 | } | |
| 1223 | ||
| 1224 | void JustReachedHome() | |
| 1225 | {
| |
| 1226 | me->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_ONESHOT_NONE); | |
| 1227 | ||
| 1228 | if (_instance->GetBossState(DATA_THE_LICH_KING) == DONE) | |
| 1229 | return; | |
| 1230 | ||
| 1231 | me->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); | |
| 1232 | } | |
| 1233 | ||
| 1234 | void UpdateAI(uint32 const diff) | |
| 1235 | {
| |
| 1236 | if (!UpdateVictim() && !(_events.GetPhaseMask() & (PHASE_MASK_INTRO | PHASE_MASK_OUTRO))) | |
| 1237 | return; | |
| 1238 | ||
| 1239 | _events.Update(diff); | |
| 1240 | ||
| 1241 | if (me->HasUnitState(UNIT_STAT_CASTING)) | |
| 1242 | return; | |
| 1243 | ||
| 1244 | while (uint32 eventId = _events.ExecuteEvent()) | |
| 1245 | {
| |
| 1246 | switch (eventId) | |
| 1247 | {
| |
| 1248 | case EVENT_INTRO_TALK_1: | |
| 1249 | Talk(SAY_TIRION_INTRO_2); | |
| 1250 | _events.ScheduleEvent(EVENT_INTRO_EMOTE_1, 2000, 0, PHASE_INTRO); | |
| 1251 | _events.ScheduleEvent(EVENT_INTRO_CHARGE, 5000, 0, PHASE_INTRO); | |
| 1252 | break; | |
| 1253 | case EVENT_INTRO_EMOTE_1: | |
| 1254 | me->HandleEmoteCommand(EMOTE_ONESHOT_POINT_NOSHEATHE); | |
| 1255 | break; | |
| 1256 | case EVENT_INTRO_CHARGE: | |
| 1257 | me->RemoveUnitMovementFlag(MOVEMENTFLAG_WALKING); | |
| 1258 | me->GetMotionMaster()->MovePoint(POINT_TIRION_CHARGE, TirionCharge); | |
| 1259 | break; | |
| 1260 | case EVENT_OUTRO_TALK_1: | |
| 1261 | Talk(SAY_TIRION_OUTRO_1); | |
| 1262 | break; | |
| 1263 | case EVENT_OUTRO_BLESS: | |
| 1264 | DoCast(me, SPELL_LIGHTS_BLESSING); | |
| 1265 | break; | |
| 1266 | case EVENT_OUTRO_REMOVE_ICE: | |
| 1267 | me->RemoveAurasDueToSpell(SPELL_ICE_LOCK); | |
| 1268 | SetEquipmentSlots(false, EQUIP_ASHBRINGER_GLOWING); | |
| 1269 | if (Creature* lichKing = ObjectAccessor::GetCreature(*me, _instance->GetData64(DATA_THE_LICH_KING))) | |
| 1270 | {
| |
| 1271 | me->SetFacing(0.0f, lichKing); | |
| 1272 | lichKing->AI()->DoAction(ACTION_PLAY_MUSIC); | |
| 1273 | } | |
| 1274 | break; | |
| 1275 | case EVENT_OUTRO_MOVE_1: | |
| 1276 | me->GetMotionMaster()->MovePoint(POINT_TIRION_OUTRO_1, OutroPosition1); | |
| 1277 | break; | |
| 1278 | case EVENT_OUTRO_JUMP: | |
| 1279 | DoCastAOE(SPELL_JUMP); | |
| 1280 | break; | |
| 1281 | default: | |
| 1282 | break; | |
| 1283 | } | |
| 1284 | } | |
| 1285 | ||
| 1286 | DoMeleeAttackIfReady(); | |
| 1287 | } | |
| 1288 | ||
| 1289 | private: | |
| 1290 | EventMap _events; | |
| 1291 | InstanceScript* _instance; | |
| 1292 | }; | |
| 1293 | ||
| 1294 | CreatureAI* GetAI(Creature* creature) const | |
| 1295 | {
| |
| 1296 | return GetIcecrownCitadelAI<npc_tirion_fordringAI>(creature); | |
| 1297 | } | |
| 1298 | }; | |
| 1299 | ||
| 1300 | class npc_shambling_horror_icc : public CreatureScript | |
| 1301 | {
| |
| 1302 | public: | |
| 1303 | npc_shambling_horror_icc() : CreatureScript("npc_shambling_horror_icc") { }
| |
| 1304 | ||
| 1305 | struct npc_shambling_horror_iccAI : public ScriptedAI | |
| 1306 | {
| |
| 1307 | npc_shambling_horror_iccAI(Creature* creature) : ScriptedAI(creature) | |
| 1308 | {
| |
| 1309 | _frenzied = false; | |
| 1310 | } | |
| 1311 | ||
| 1312 | void Reset() | |
| 1313 | {
| |
| 1314 | _events.Reset(); | |
| 1315 | _events.ScheduleEvent(EVENT_SHOCKWAVE, urand(20000, 25000)); | |
| 1316 | _events.ScheduleEvent(EVENT_ENRAGE, urand(11000, 14000)); | |
| 1317 | } | |
| 1318 | ||
| 1319 | void DamageTaken(Unit* /*attacker*/, uint32& damage) | |
| 1320 | {
| |
| 1321 | if (!_frenzied && IsHeroic() && me->HealthBelowPctDamaged(20, damage)) | |
| 1322 | {
| |
| 1323 | _frenzied = true; | |
| 1324 | DoCast(me, SPELL_FRENZY, true); | |
| 1325 | } | |
| 1326 | } | |
| 1327 | ||
| 1328 | void UpdateAI(uint32 const diff) | |
| 1329 | {
| |
| 1330 | if (!UpdateVictim()) | |
| 1331 | return; | |
| 1332 | ||
| 1333 | _events.Update(diff); | |
| 1334 | ||
| 1335 | if (me->HasUnitState(UNIT_STAT_CASTING)) | |
| 1336 | return; | |
| 1337 | ||
| 1338 | while (uint32 eventId = _events.ExecuteEvent()) | |
| 1339 | {
| |
| 1340 | switch (eventId) | |
| 1341 | {
| |
| 1342 | case EVENT_SHOCKWAVE: | |
| 1343 | DoCast(me, SPELL_SHOCKWAVE); | |
| 1344 | _events.ScheduleEvent(EVENT_SHOCKWAVE, urand(20000, 25000)); | |
| 1345 | break; | |
| 1346 | case EVENT_ENRAGE: | |
| 1347 | DoCast(me, SPELL_ENRAGE); | |
| 1348 | _events.ScheduleEvent(EVENT_ENRAGE, urand(20000, 25000)); | |
| 1349 | break; | |
| 1350 | default: | |
| 1351 | break; | |
| 1352 | } | |
| 1353 | } | |
| 1354 | ||
| 1355 | DoMeleeAttackIfReady(); | |
| 1356 | } | |
| 1357 | ||
| 1358 | private: | |
| 1359 | EventMap _events; | |
| 1360 | bool _frenzied; | |
| 1361 | }; | |
| 1362 | ||
| 1363 | CreatureAI* GetAI(Creature* creature) const | |
| 1364 | {
| |
| 1365 | return GetIcecrownCitadelAI<npc_shambling_horror_iccAI>(creature); | |
| 1366 | } | |
| 1367 | }; | |
| 1368 | ||
| 1369 | class npc_raging_spirit : public CreatureScript | |
| 1370 | {
| |
| 1371 | public: | |
| 1372 | npc_raging_spirit() : CreatureScript("npc_raging_spirit") { }
| |
| 1373 | ||
| 1374 | struct npc_raging_spiritAI : public ScriptedAI | |
| 1375 | {
| |
| 1376 | npc_raging_spiritAI(Creature* creature) : ScriptedAI(creature), | |
| 1377 | _instance(creature->GetInstanceScript()) | |
| 1378 | {
| |
| 1379 | } | |
| 1380 | ||
| 1381 | void Reset() | |
| 1382 | {
| |
| 1383 | _events.Reset(); | |
| 1384 | _events.ScheduleEvent(EVENT_SOUL_SHRIEK, urand(12000, 15000)); | |
| 1385 | DoCast(me, SPELL_PLAGUE_AVOIDANCE, true); | |
| 1386 | DoCast(me, SPELL_RAGING_SPIRIT_VISUAL, true); | |
| 1387 | if (TempSummon* summon = me->ToTempSummon()) | |
| 1388 | if (Unit* summoner = summon->GetSummoner()) | |
| 1389 | summoner->CastSpell(me, SPELL_RAGING_SPIRIT_VISUAL_CLONE, true); | |
| 1390 | DoCast(me, SPELL_BOSS_HITTIN_YA, true); | |
| 1391 | } | |
| 1392 | ||
| 1393 | void IsSummonedBy(Unit* /*summoner*/) | |
| 1394 | {
| |
| 1395 | // player is the spellcaster so register summon manually | |
| 1396 | if (Creature* lichKing = ObjectAccessor::GetCreature(*me, _instance->GetData64(DATA_THE_LICH_KING))) | |
| 1397 | lichKing->AI()->JustSummoned(me); | |
| 1398 | } | |
| 1399 | ||
| 1400 | void JustDied(Unit* /*killer*/) | |
| 1401 | {
| |
| 1402 | if (Creature* lichKing = ObjectAccessor::GetCreature(*me, _instance->GetData64(DATA_THE_LICH_KING))) | |
| 1403 | lichKing->AI()->SummonedCreatureDespawn(me); | |
| 1404 | if (TempSummon* summon = me->ToTempSummon()) | |
| 1405 | summon->SetTempSummonType(TEMPSUMMON_CORPSE_DESPAWN); | |
| 1406 | } | |
| 1407 | ||
| 1408 | void UpdateAI(uint32 const diff) | |
| 1409 | {
| |
| 1410 | if (!UpdateVictim()) | |
| 1411 | return; | |
| 1412 | ||
| 1413 | _events.Update(diff); | |
| 1414 | ||
| 1415 | if (me->HasUnitState(UNIT_STAT_CASTING)) | |
| 1416 | return; | |
| 1417 | ||
| 1418 | while (uint32 eventId = _events.ExecuteEvent()) | |
| 1419 | {
| |
| 1420 | switch (eventId) | |
| 1421 | {
| |
| 1422 | case EVENT_SOUL_SHRIEK: | |
| 1423 | DoCastAOE(SPELL_SOUL_SHRIEK); | |
| 1424 | _events.ScheduleEvent(EVENT_SOUL_SHRIEK, urand(12000, 15000)); | |
| 1425 | break; | |
| 1426 | default: | |
| 1427 | break; | |
| 1428 | } | |
| 1429 | } | |
| 1430 | ||
| 1431 | DoMeleeAttackIfReady(); | |
| 1432 | } | |
| 1433 | ||
| 1434 | private: | |
| 1435 | EventMap _events; | |
| 1436 | InstanceScript* _instance; | |
| 1437 | }; | |
| 1438 | ||
| 1439 | CreatureAI* GetAI(Creature* creature) const | |
| 1440 | {
| |
| 1441 | return GetIcecrownCitadelAI<npc_raging_spiritAI>(creature); | |
| 1442 | } | |
| 1443 | }; | |
| 1444 | ||
| 1445 | class npc_valkyr_shadowguard : public CreatureScript | |
| 1446 | {
| |
| 1447 | public: | |
| 1448 | npc_valkyr_shadowguard() : CreatureScript("npc_valkyr_shadowguard") { }
| |
| 1449 | ||
| 1450 | struct npc_valkyr_shadowguardAI : public ScriptedAI | |
| 1451 | {
| |
| 1452 | npc_valkyr_shadowguardAI(Creature* creature) : ScriptedAI(creature), | |
| 1453 | _grabbedPlayer(0), _instance(creature->GetInstanceScript()) | |
| 1454 | {
| |
| 1455 | } | |
| 1456 | ||
| 1457 | void Reset() | |
| 1458 | {
| |
| 1459 | _events.Reset(); | |
| 1460 | me->SetReactState(REACT_PASSIVE); | |
| 1461 | DoCast(me, SPELL_WINGS_OF_THE_DAMNED, false); | |
| 1462 | me->SetSpeed(MOVE_FLIGHT, 0.642857f, true); | |
| 1463 | } | |
| 1464 | ||
| 1465 | void IsSummonedBy(Unit* /*summoner*/) | |
| 1466 | {
| |
| 1467 | _events.Reset(); | |
| 1468 | _events.ScheduleEvent(EVENT_GRAB_PLAYER, 2500); | |
| 1469 | } | |
| 1470 | ||
| 1471 | void DamageTaken(Unit* /*attacker*/, uint32& damage) | |
| 1472 | {
| |
| 1473 | if (!IsHeroic()) | |
| 1474 | return; | |
| 1475 | ||
| 1476 | if (!me->HasAuraType(SPELL_AURA_CONTROL_VEHICLE)) | |
| 1477 | return; | |
| 1478 | ||
| 1479 | if (me->HealthBelowPctDamaged(50, damage)) | |
| 1480 | {
| |
| 1481 | _events.Reset(); | |
| 1482 | DoCastAOE(SPELL_EJECT_ALL_PASSENGERS); | |
| 1483 | me->GetMotionMaster()->MoveTargetedHome(); | |
| 1484 | me->ClearUnitState(UNIT_STAT_EVADE); | |
| 1485 | } | |
| 1486 | } | |
| 1487 | ||
| 1488 | void JustReachedHome() | |
| 1489 | {
| |
| 1490 | // schedule siphon life event (heroic only) | |
| 1491 | DoZoneInCombat(); | |
| 1492 | _events.Reset(); | |
| 1493 | _events.ScheduleEvent(EVENT_LIFE_SIPHON, 2000); | |
| 1494 | } | |
| 1495 | ||
| 1496 | void AttackStart(Unit* /*target*/) | |
| 1497 | {
| |
| 1498 | } | |
| 1499 | ||
| 1500 | void MovementInform(uint32 type, uint32 id) | |
| 1501 | {
| |
| 1502 | if (type != POINT_MOTION_TYPE) | |
| 1503 | return; | |
| 1504 | ||
| 1505 | switch (id) | |
| 1506 | {
| |
| 1507 | case POINT_DROP_PLAYER: | |
| 1508 | DoCastAOE(SPELL_EJECT_ALL_PASSENGERS); | |
| 1509 | me->DespawnOrUnsummon(1000); | |
| 1510 | break; | |
| 1511 | case POINT_CHARGE: | |
| 1512 | if (Player* target = ObjectAccessor::GetPlayer(*me, _grabbedPlayer)) | |
| 1513 | {
| |
| 1514 | me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); | |
| 1515 | if (GameObject* platform = ObjectAccessor::GetGameObject(*me, _instance->GetData64(DATA_ARTHAS_PLATFORM))) | |
| 1516 | {
| |
| 1517 | std::list<Creature*> triggers; | |
| 1518 | GetCreatureListWithEntryInGrid(triggers, me, NPC_WORLD_TRIGGER, 150.0f); | |
| 1519 | triggers.remove_if(HeightDifferenceCheck(platform, 5.0f, true)); | |
| 1520 | if (triggers.empty()) | |
| 1521 | return; | |
| 1522 | ||
| 1523 | triggers.sort(Trinity::ObjectDistanceOrderPred(me)); | |
| 1524 | DoCast(target, SPELL_VALKYR_CARRY); | |
| 1525 | _dropPoint.Relocate(triggers.front()); | |
| 1526 | _events.ScheduleEvent(EVENT_MOVE_TO_DROP_POS, 1500); | |
| 1527 | ||
| 1528 | } | |
| 1529 | } | |
| 1530 | else | |
| 1531 | me->DespawnOrUnsummon(); | |
| 1532 | break; | |
| 1533 | default: | |
| 1534 | break; | |
| 1535 | } | |
| 1536 | } | |
| 1537 | ||
| 1538 | void SetGUID(uint64 guid, int32 /* = 0*/) | |
| 1539 | {
| |
| 1540 | _grabbedPlayer = guid; | |
| 1541 | } | |
| 1542 | ||
| 1543 | void UpdateAI(uint32 const diff) | |
| 1544 | {
| |
| 1545 | if (!UpdateVictim()) | |
| 1546 | return; | |
| 1547 | ||
| 1548 | _events.Update(diff); | |
| 1549 | ||
| 1550 | if (me->HasUnitState(UNIT_STAT_CASTING)) | |
| 1551 | return; | |
| 1552 | ||
| 1553 | while (uint32 eventId = _events.ExecuteEvent()) | |
| 1554 | {
| |
| 1555 | switch (eventId) | |
| 1556 | {
| |
| 1557 | case EVENT_GRAB_PLAYER: | |
| 1558 | if (!_grabbedPlayer) | |
| 1559 | {
| |
| 1560 | DoCastAOE(SPELL_VALKYR_TARGET_SEARCH); | |
| 1561 | _events.ScheduleEvent(EVENT_GRAB_PLAYER, 2000); | |
| 1562 | } | |
| 1563 | break; | |
| 1564 | case EVENT_MOVE_TO_DROP_POS: | |
| 1565 | me->GetMotionMaster()->MovePoint(POINT_DROP_PLAYER, _dropPoint); | |
| 1566 | break; | |
| 1567 | case EVENT_LIFE_SIPHON: | |
| 1568 | if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 1)) | |
| 1569 | DoCast(target, SPELL_LIFE_SIPHON); | |
| 1570 | _events.ScheduleEvent(EVENT_LIFE_SIPHON, 2500); | |
| 1571 | break; | |
| 1572 | default: | |
| 1573 | break; | |
| 1574 | } | |
| 1575 | } | |
| 1576 | ||
| 1577 | // no melee attacks | |
| 1578 | } | |
| 1579 | ||
| 1580 | private: | |
| 1581 | EventMap _events; | |
| 1582 | Position _dropPoint; | |
| 1583 | uint64 _grabbedPlayer; | |
| 1584 | InstanceScript* _instance; | |
| 1585 | }; | |
| 1586 | ||
| 1587 | CreatureAI* GetAI(Creature* creature) const | |
| 1588 | {
| |
| 1589 | return GetIcecrownCitadelAI<npc_valkyr_shadowguardAI>(creature); | |
| 1590 | } | |
| 1591 | }; | |
| 1592 | ||
| 1593 | class npc_strangulate_vehicle : public CreatureScript | |
| 1594 | {
| |
| 1595 | public: | |
| 1596 | npc_strangulate_vehicle() : CreatureScript("npc_strangulate_vehicle") { }
| |
| 1597 | ||
| 1598 | struct npc_strangulate_vehicleAI : public ScriptedAI | |
| 1599 | {
| |
| 1600 | npc_strangulate_vehicleAI(Creature* creature) : ScriptedAI(creature), | |
| 1601 | _instance(creature->GetInstanceScript()) | |
| 1602 | {
| |
| 1603 | } | |
| 1604 | ||
| 1605 | void IsSummonedBy(Unit* summoner) | |
| 1606 | {
| |
| 1607 | me->SetFacing(0.0f, summoner); | |
| 1608 | DoCast(summoner, SPELL_HARVEST_SOUL_VEHICLE); | |
| 1609 | _events.Reset(); | |
| 1610 | _events.ScheduleEvent(EVENT_MOVE_TO_LICH_KING, 2000); | |
| 1611 | _events.ScheduleEvent(EVENT_TELEPORT, 6000); | |
| 1612 | ||
| 1613 | // this will let us easily access all creatures of this entry on heroic mode when its time to teleport back | |
| 1614 | if (Creature* lichKing = ObjectAccessor::GetCreature(*me, _instance->GetData64(DATA_THE_LICH_KING))) | |
| 1615 | lichKing->AI()->JustSummoned(me); | |
| 1616 | } | |
| 1617 | ||
| 1618 | void DoAction(int32 const action) | |
| 1619 | {
| |
| 1620 | if (action != ACTION_TELEPORT_BACK) | |
| 1621 | return; | |
| 1622 | ||
| 1623 | if (TempSummon* summ = me->ToTempSummon()) | |
| 1624 | if (Unit* summoner = summ->GetSummoner()) | |
| 1625 | DoCast(summoner, SPELL_HARVEST_SOUL_TELEPORT_BACK); | |
| 1626 | ||
| 1627 | if (Creature* lichKing = ObjectAccessor::GetCreature(*me, _instance->GetData64(DATA_THE_LICH_KING))) | |
| 1628 | lichKing->AI()->SummonedCreatureDespawn(me); | |
| 1629 | } | |
| 1630 | ||
| 1631 | void UpdateAI(uint32 const diff) | |
| 1632 | {
| |
| 1633 | UpdateVictim(); | |
| 1634 | ||
| 1635 | _events.Update(diff); | |
| 1636 | ||
| 1637 | while (uint32 eventId = _events.ExecuteEvent()) | |
| 1638 | {
| |
| 1639 | switch (eventId) | |
| 1640 | {
| |
| 1641 | case EVENT_TELEPORT: | |
| 1642 | me->GetMotionMaster()->Clear(false); | |
| 1643 | me->GetMotionMaster()->MoveIdle(); | |
| 1644 | if (TempSummon* summ = me->ToTempSummon()) | |
| 1645 | {
| |
| 1646 | if (Unit* summoner = summ->GetSummoner()) | |
| 1647 | {
| |
| 1648 | summoner->CastSpell((Unit*)NULL, SPELL_HARVEST_SOUL_VISUAL, true); | |
| 1649 | summoner->ExitVehicle(summoner); | |
| 1650 | if (!IsHeroic()) | |
| 1651 | summoner->CastSpell(summoner, SPELL_HARVEST_SOUL_TELEPORT, true); | |
| 1652 | else | |
| 1653 | {
| |
| 1654 | summoner->CastSpell(summoner, SPELL_HARVEST_SOULS_TELEPORT, true); | |
| 1655 | summoner->RemoveAurasDueToSpell(HARVEST_SOUL, 0, 0, AURA_REMOVE_BY_EXPIRE); | |
| 1656 | } | |
| 1657 | } | |
| 1658 | } | |
| 1659 | ||
| 1660 | _events.ScheduleEvent(EVENT_DESPAWN_SELF, 65000); | |
| 1661 | break; | |
| 1662 | case EVENT_MOVE_TO_LICH_KING: | |
| 1663 | if (Creature* lichKing = ObjectAccessor::GetCreature(*me, _instance->GetData64(DATA_THE_LICH_KING))) | |
| 1664 | {
| |
| 1665 | if (me->GetExactDist(lichKing) > 10.0f) | |
| 1666 | {
| |
| 1667 | Position pos; | |
| 1668 | lichKing->GetNearPosition(pos, float(rand_norm()) * 5.0f + 7.5f, lichKing->GetAngle(me)); | |
| 1669 | me->GetMotionMaster()->MovePoint(0, pos); | |
| 1670 | } | |
| 1671 | } | |
| 1672 | break; | |
| 1673 | case EVENT_DESPAWN_SELF: | |
| 1674 | if (Creature* lichKing = ObjectAccessor::GetCreature(*me, _instance->GetData64(DATA_THE_LICH_KING))) | |
| 1675 | lichKing->AI()->SummonedCreatureDespawn(me); | |
| 1676 | me->DespawnOrUnsummon(1); | |
| 1677 | break; | |
| 1678 | default: | |
| 1679 | break; | |
| 1680 | } | |
| 1681 | } | |
| 1682 | } | |
| 1683 | ||
| 1684 | private: | |
| 1685 | EventMap _events; | |
| 1686 | InstanceScript* _instance; | |
| 1687 | }; | |
| 1688 | ||
| 1689 | CreatureAI* GetAI(Creature* creature) const | |
| 1690 | {
| |
| 1691 | return GetIcecrownCitadelAI<npc_strangulate_vehicleAI>(creature); | |
| 1692 | } | |
| 1693 | }; | |
| 1694 | ||
| 1695 | class npc_terenas_menethil : public CreatureScript | |
| 1696 | {
| |
| 1697 | public: | |
| 1698 | npc_terenas_menethil() : CreatureScript("npc_terenas_menethil") { }
| |
| 1699 | ||
| 1700 | struct npc_terenas_menethilAI : public ScriptedAI | |
| 1701 | {
| |
| 1702 | npc_terenas_menethilAI(Creature* creature) : ScriptedAI(creature), | |
| 1703 | _instance(creature->GetInstanceScript()) | |
| 1704 | {
| |
| 1705 | } | |
| 1706 | ||
| 1707 | bool CanAIAttack(Unit const* target) const | |
| 1708 | {
| |
| 1709 | return target->GetEntry() != NPC_THE_LICH_KING; | |
| 1710 | } | |
| 1711 | ||
| 1712 | void DoAction(int32 const action) | |
| 1713 | {
| |
| 1714 | switch (action) | |
| 1715 | {
| |
| 1716 | case ACTION_FROSTMOURNE_INTRO: | |
| 1717 | me->setActive(true); | |
| 1718 | if (!IsHeroic()) | |
| 1719 | me->SetHealth(me->GetMaxHealth() / 2); | |
| 1720 | DoCast(me, SPELL_LIGHTS_FAVOR); | |
| 1721 | _events.Reset(); | |
| 1722 | _events.ScheduleEvent(EVENT_FROSTMOURNE_TALK_1, 2000, PHASE_FROSTMOURNE); | |
| 1723 | _events.ScheduleEvent(EVENT_FROSTMOURNE_TALK_2, 11000, PHASE_FROSTMOURNE); | |
| 1724 | if (!IsHeroic()) | |
| 1725 | {
| |
| 1726 | _events.ScheduleEvent(EVENT_DESTROY_SOUL, 60000, PHASE_FROSTMOURNE); | |
| 1727 | _events.ScheduleEvent(EVENT_FROSTMOURNE_TALK_3, 25000); | |
| 1728 | } | |
| 1729 | break; | |
| 1730 | case ACTION_TELEPORT_BACK: | |
| 1731 | me->CastSpell((Unit*)NULL, SPELL_RESTORE_SOUL, TRIGGERED_NONE); | |
| 1732 | me->DespawnOrUnsummon(3000); | |
| 1733 | break; | |
| 1734 | default: | |
| 1735 | break; | |
| 1736 | } | |
| 1737 | } | |
| 1738 | ||
| 1739 | void EnterEvadeMode() | |
| 1740 | {
| |
| 1741 | // no running back home | |
| 1742 | if (!me->isAlive()) | |
| 1743 | return; | |
| 1744 | ||
| 1745 | me->DeleteThreatList(); | |
| 1746 | me->CombatStop(false); | |
| 1747 | } | |
| 1748 | ||
| 1749 | void DamageTaken(Unit* /*attacker*/, uint32& damage) | |
| 1750 | {
| |
| 1751 | if (damage >= me->GetHealth()) | |
| 1752 | {
| |
| 1753 | damage = me->GetHealth() - 1; | |
| 1754 | if (!me->HasAura(SPELL_TERENAS_LOSES_INSIDE) && !IsHeroic()) | |
| 1755 | {
| |
| 1756 | me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); | |
| 1757 | DoCast(SPELL_TERENAS_LOSES_INSIDE); | |
| 1758 | _events.ScheduleEvent(EVENT_TELEPORT_BACK, 1000); | |
| 1759 | if (Creature* warden = me->FindNearestCreature(NPC_SPIRIT_WARDEN, 20.0f)) | |
| 1760 | {
| |
| 1761 | warden->CastSpell((Unit*)NULL, SPELL_DESTROY_SOUL, TRIGGERED_NONE); | |
| 1762 | warden->DespawnOrUnsummon(2000); | |
| 1763 | } | |
| 1764 | ||
| 1765 | me->DespawnOrUnsummon(2000); | |
| 1766 | } | |
| 1767 | } | |
| 1768 | } | |
| 1769 | ||
| 1770 | void IsSummonedBy(Unit* /*summoner*/) | |
| 1771 | {
| |
| 1772 | _events.Reset(); | |
| 1773 | _events.SetPhase(PHASE_OUTRO); | |
| 1774 | if (Creature* lichKing = ObjectAccessor::GetCreature(*me, _instance->GetData64(DATA_THE_LICH_KING))) | |
| 1775 | me->SetFacing(0.0f, lichKing); | |
| 1776 | ||
| 1777 | _events.ScheduleEvent(EVENT_OUTRO_TERENAS_TALK_1, 2000, 0, PHASE_OUTRO); | |
| 1778 | _events.ScheduleEvent(EVENT_OUTRO_TERENAS_TALK_2, 14000, 0, PHASE_OUTRO); | |
| 1779 | } | |
| 1780 | ||
| 1781 | void UpdateAI(uint32 const diff) | |
| 1782 | {
| |
| 1783 | UpdateVictim(); | |
| 1784 | ||
| 1785 | _events.Update(diff); | |
| 1786 | ||
| 1787 | while (uint32 eventId = _events.ExecuteEvent()) | |
| 1788 | {
| |
| 1789 | switch (eventId) | |
| 1790 | {
| |
| 1791 | case EVENT_FROSTMOURNE_TALK_1: | |
| 1792 | Talk(SAY_TERENAS_INTRO_1); | |
| 1793 | if (IsHeroic()) | |
| 1794 | DoCastAOE(SPELL_RESTORE_SOULS); | |
| 1795 | break; | |
| 1796 | case EVENT_FROSTMOURNE_TALK_2: | |
| 1797 | Talk(SAY_TERENAS_INTRO_2); | |
| 1798 | break; | |
| 1799 | case EVENT_FROSTMOURNE_TALK_3: | |
| 1800 | Talk(SAY_TERENAS_INTRO_3); | |
| 1801 | break; | |
| 1802 | case EVENT_OUTRO_TERENAS_TALK_1: | |
| 1803 | Talk(SAY_TERENAS_OUTRO_1); | |
| 1804 | break; | |
| 1805 | case EVENT_OUTRO_TERENAS_TALK_2: | |
| 1806 | Talk(SAY_TERENAS_OUTRO_2); | |
| 1807 | DoCastAOE(SPELL_MASS_RESURRECTION); | |
| 1808 | if (Creature* lichKing = ObjectAccessor::GetCreature(*me, _instance->GetData64(DATA_THE_LICH_KING))) | |
| 1809 | {
| |
| 1810 | lichKing->AI()->DoAction(ACTION_FINISH_OUTRO); | |
| 1811 | lichKing->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PASSIVE); | |
| 1812 | if (Creature* tirion = ObjectAccessor::GetCreature(*me, _instance->GetData64(DATA_HIGHLORD_TIRION_FORDRING))) | |
| 1813 | tirion->AI()->AttackStart(lichKing); | |
| 1814 | } | |
| 1815 | break; | |
| 1816 | case EVENT_DESTROY_SOUL: | |
| 1817 | me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); | |
| 1818 | if (Creature* warden = me->FindNearestCreature(NPC_SPIRIT_WARDEN, 20.0f)) | |
| 1819 | warden->CastSpell((Unit*)NULL, SPELL_DESTROY_SOUL, TRIGGERED_NONE); | |
| 1820 | DoCast(SPELL_TERENAS_LOSES_INSIDE); | |
| 1821 | _events.ScheduleEvent(EVENT_TELEPORT_BACK, 1000); | |
| 1822 | break; | |
| 1823 | case EVENT_TELEPORT_BACK: | |
| 1824 | if (Creature* lichKing = ObjectAccessor::GetCreature(*me, _instance->GetData64(DATA_THE_LICH_KING))) | |
| 1825 | lichKing->AI()->DoAction(ACTION_TELEPORT_BACK); | |
| 1826 | break; | |
| 1827 | default: | |
| 1828 | break; | |
| 1829 | } | |
| 1830 | } | |
| 1831 | ||
| 1832 | // fighting Spirit Warden | |
| 1833 | if (me->isInCombat()) | |
| 1834 | DoMeleeAttackIfReady(); | |
| 1835 | } | |
| 1836 | ||
| 1837 | private: | |
| 1838 | EventMap _events; | |
| 1839 | InstanceScript* _instance; | |
| 1840 | }; | |
| 1841 | ||
| 1842 | CreatureAI* GetAI(Creature* creature) const | |
| 1843 | {
| |
| 1844 | return GetIcecrownCitadelAI<npc_terenas_menethilAI>(creature); | |
| 1845 | } | |
| 1846 | }; | |
| 1847 | ||
| 1848 | class npc_spirit_warden : public CreatureScript | |
| 1849 | {
| |
| 1850 | public: | |
| 1851 | npc_spirit_warden() : CreatureScript("npc_spirit_warden") { }
| |
| 1852 | ||
| 1853 | struct npc_spirit_wardenAI : public ScriptedAI | |
| 1854 | {
| |
| 1855 | npc_spirit_wardenAI(Creature* creature) : ScriptedAI(creature), | |
| 1856 | _instance(creature->GetInstanceScript()) | |
| 1857 | {
| |
| 1858 | } | |
| 1859 | ||
| 1860 | void Reset() | |
| 1861 | {
| |
| 1862 | _events.Reset(); | |
| 1863 | _events.ScheduleEvent(EVENT_SOUL_RIP, urand(12000, 15000)); | |
| 1864 | DoCast(SPELL_DARK_HUNGER); | |
| 1865 | } | |
| 1866 | ||
| 1867 | void JustDied(Unit* /*killer*/) | |
| 1868 | {
| |
| 1869 | if (Creature* terenas = ObjectAccessor::GetCreature(*me, _instance->GetData64(DATA_TERENAS_MENETHIL))) | |
| 1870 | terenas->AI()->DoAction(ACTION_TELEPORT_BACK); | |
| 1871 | } | |
| 1872 | ||
| 1873 | void UpdateAI(uint32 const diff) | |
| 1874 | {
| |
| 1875 | if (!UpdateVictim()) | |
| 1876 | return; | |
| 1877 | ||
| 1878 | _events.Update(diff); | |
| 1879 | ||
| 1880 | while (uint32 eventId = _events.ExecuteEvent()) | |
| 1881 | {
| |
| 1882 | switch (eventId) | |
| 1883 | {
| |
| 1884 | case EVENT_SOUL_RIP: | |
| 1885 | DoCastVictim(SPELL_SOUL_RIP); | |
| 1886 | _events.ScheduleEvent(EVENT_SOUL_RIP, urand(23000, 27000)); | |
| 1887 | break; | |
| 1888 | default: | |
| 1889 | break; | |
| 1890 | } | |
| 1891 | } | |
| 1892 | ||
| 1893 | DoMeleeAttackIfReady(); | |
| 1894 | } | |
| 1895 | ||
| 1896 | private: | |
| 1897 | EventMap _events; | |
| 1898 | InstanceScript* _instance; | |
| 1899 | }; | |
| 1900 | ||
| 1901 | CreatureAI* GetAI(Creature* creature) const | |
| 1902 | {
| |
| 1903 | return GetIcecrownCitadelAI<npc_spirit_wardenAI>(creature); | |
| 1904 | } | |
| 1905 | }; | |
| 1906 | ||
| 1907 | class npc_spirit_bomb : public CreatureScript | |
| 1908 | {
| |
| 1909 | public: | |
| 1910 | npc_spirit_bomb() : CreatureScript("npc_spirit_bomb") { }
| |
| 1911 | ||
| 1912 | struct npc_spirit_bombAI : public CreatureAI | |
| 1913 | {
| |
| 1914 | npc_spirit_bombAI(Creature* creature) : CreatureAI(creature) | |
| 1915 | {
| |
| 1916 | } | |
| 1917 | ||
| 1918 | void IsSummonedBy(Unit* /*summoner*/) | |
| 1919 | {
| |
| 1920 | float destX, destY, destZ; | |
| 1921 | me->GetPosition(destX, destY); | |
| 1922 | destZ = 1055.0f; // approximation, gets more precise later | |
| 1923 | me->UpdateGroundPositionZ(destX, destY, destZ); | |
| 1924 | me->GetMotionMaster()->MovePoint(POINT_GROUND, destX, destY, destZ); | |
| 1925 | } | |
| 1926 | ||
| 1927 | void MovementInform(uint32 type, uint32 point) | |
| 1928 | {
| |
| 1929 | if (type != POINT_MOTION_TYPE || point != POINT_GROUND) | |
| 1930 | return; | |
| 1931 | ||
| 1932 | me->RemoveAllAuras(); | |
| 1933 | DoCastAOE(SPELL_EXPLOSION); | |
| 1934 | me->DespawnOrUnsummon(1000); | |
| 1935 | } | |
| 1936 | ||
| 1937 | void AttackStart(Unit* /*victim*/) | |
| 1938 | {
| |
| 1939 | } | |
| 1940 | ||
| 1941 | void UpdateAI(uint32 const /*diff*/) | |
| 1942 | {
| |
| 1943 | UpdateVictim(); | |
| 1944 | // no melee attacks | |
| 1945 | } | |
| 1946 | }; | |
| 1947 | ||
| 1948 | CreatureAI* GetAI(Creature* creature) const | |
| 1949 | {
| |
| 1950 | return GetIcecrownCitadelAI<npc_spirit_bombAI>(creature); | |
| 1951 | } | |
| 1952 | }; | |
| 1953 | ||
| 1954 | class npc_broken_frostmourne : public CreatureScript | |
| 1955 | {
| |
| 1956 | public: | |
| 1957 | npc_broken_frostmourne() : CreatureScript("npc_broken_frostmourne") { }
| |
| 1958 | ||
| 1959 | struct npc_broken_frostmourneAI : public CreatureAI | |
| 1960 | {
| |
| 1961 | npc_broken_frostmourneAI(Creature* creature) : CreatureAI(creature) | |
| 1962 | {
| |
| 1963 | } | |
| 1964 | ||
| 1965 | void Reset() | |
| 1966 | {
| |
| 1967 | _events.Reset(); | |
| 1968 | } | |
| 1969 | ||
| 1970 | void IsSummonedBy(Unit* /*summoner*/) | |
| 1971 | {
| |
| 1972 | _events.SetPhase(PHASE_OUTRO); | |
| 1973 | _events.ScheduleEvent(EVENT_OUTRO_KNOCK_BACK, 3000, 0, PHASE_OUTRO); | |
| 1974 | } | |
| 1975 | ||
| 1976 | void DoAction(int32 const action) | |
| 1977 | {
| |
| 1978 | if (action == ACTION_SUMMON_TERENAS) | |
| 1979 | _events.ScheduleEvent(EVENT_OUTRO_SUMMON_TERENAS, 6000, 0, PHASE_OUTRO); | |
| 1980 | } | |
| 1981 | ||
| 1982 | void UpdateAI(uint32 const diff) | |
| 1983 | {
| |
| 1984 | UpdateVictim(); | |
| 1985 | ||
| 1986 | _events.Update(diff); | |
| 1987 | ||
| 1988 | while (uint32 eventId = _events.ExecuteEvent()) | |
| 1989 | {
| |
| 1990 | switch (eventId) | |
| 1991 | {
| |
| 1992 | case EVENT_OUTRO_KNOCK_BACK: | |
| 1993 | DoCastAOE(SPELL_BROKEN_FROSTMOURNE_KNOCK); | |
| 1994 | break; | |
| 1995 | case EVENT_OUTRO_SUMMON_TERENAS: | |
| 1996 | DoCastAOE(SPELL_SUMMON_TERENAS); | |
| 1997 | break; | |
| 1998 | default: | |
| 1999 | break; | |
| 2000 | } | |
| 2001 | } | |
| 2002 | ||
| 2003 | // no melee attacks | |
| 2004 | } | |
| 2005 | ||
| 2006 | private: | |
| 2007 | EventMap _events; | |
| 2008 | }; | |
| 2009 | ||
| 2010 | CreatureAI* GetAI(Creature* creature) const | |
| 2011 | {
| |
| 2012 | return GetIcecrownCitadelAI<npc_broken_frostmourneAI>(creature); | |
| 2013 | } | |
| 2014 | }; | |
| 2015 | ||
| 2016 | class spell_the_lich_king_infest : public SpellScriptLoader | |
| 2017 | {
| |
| 2018 | public: | |
| 2019 | spell_the_lich_king_infest() : SpellScriptLoader("spell_the_lich_king_infest") { }
| |
| 2020 | ||
| 2021 | class spell_the_lich_king_infest_AuraScript : public AuraScript | |
| 2022 | {
| |
| 2023 | PrepareAuraScript(spell_the_lich_king_infest_AuraScript); | |
| 2024 | ||
| 2025 | void OnPeriodic(AuraEffect const* /*aurEff*/) | |
| 2026 | {
| |
| 2027 | if (GetUnitOwner()->HealthAbovePct(90)) | |
| 2028 | {
| |
| 2029 | PreventDefaultAction(); | |
| 2030 | Remove(AURA_REMOVE_BY_ENEMY_SPELL); | |
| 2031 | } | |
| 2032 | } | |
| 2033 | ||
| 2034 | void OnUpdate(AuraEffect* aurEff) | |
| 2035 | {
| |
| 2036 | // multiply, starting from 2nd tick | |
| 2037 | if (aurEff->GetTickNumber() == 1) | |
| 2038 | return; | |
| 2039 | ||
| 2040 | aurEff->SetAmount(int32(aurEff->GetAmount() * 1.15f)); | |
| 2041 | } | |
| 2042 | ||
| 2043 | void Register() | |
| 2044 | {
| |
| 2045 | OnEffectPeriodic += AuraEffectPeriodicFn(spell_the_lich_king_infest_AuraScript::OnPeriodic, EFFECT_0, SPELL_AURA_PERIODIC_DAMAGE); | |
| 2046 | OnEffectUpdatePeriodic += AuraEffectUpdatePeriodicFn(spell_the_lich_king_infest_AuraScript::OnUpdate, EFFECT_0, SPELL_AURA_PERIODIC_DAMAGE); | |
| 2047 | } | |
| 2048 | }; | |
| 2049 | ||
| 2050 | AuraScript* GetAuraScript() const | |
| 2051 | {
| |
| 2052 | return new spell_the_lich_king_infest_AuraScript(); | |
| 2053 | } | |
| 2054 | }; | |
| 2055 | ||
| 2056 | class spell_the_lich_king_necrotic_plague : public SpellScriptLoader | |
| 2057 | {
| |
| 2058 | public: | |
| 2059 | spell_the_lich_king_necrotic_plague() : SpellScriptLoader("spell_the_lich_king_necrotic_plague") { }
| |
| 2060 | ||
| 2061 | class spell_the_lich_king_necrotic_plague_AuraScript : public AuraScript | |
| 2062 | {
| |
| 2063 | PrepareAuraScript(spell_the_lich_king_necrotic_plague_AuraScript); | |
| 2064 | ||
| 2065 | bool Validate(SpellInfo const* /*spell*/) | |
| 2066 | {
| |
| 2067 | if (!sSpellMgr->GetSpellInfo(SPELL_NECROTIC_PLAGUE_JUMP)) | |
| 2068 | return false; | |
| 2069 | return true; | |
| 2070 | } | |
| 2071 | ||
| 2072 | void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) | |
| 2073 | {
| |
| 2074 | switch (GetTargetApplication()->GetRemoveMode()) | |
| 2075 | {
| |
| 2076 | case AURA_REMOVE_BY_ENEMY_SPELL: | |
| 2077 | case AURA_REMOVE_BY_EXPIRE: | |
| 2078 | case AURA_REMOVE_BY_DEATH: | |
| 2079 | break; | |
| 2080 | default: | |
| 2081 | return; | |
| 2082 | } | |
| 2083 | ||
| 2084 | CustomSpellValues values; | |
| 2085 | //values.AddSpellMod(SPELLVALUE_AURA_STACK, 2); | |
| 2086 | values.AddSpellMod(SPELLVALUE_MAX_TARGETS, 1); | |
| 2087 | GetTarget()->CastCustomSpell(SPELL_NECROTIC_PLAGUE_JUMP, values, NULL, true, NULL, NULL, GetCasterGUID()); | |
| 2088 | if (Unit* caster = GetCaster()) | |
| 2089 | caster->CastSpell(caster, SPELL_PLAGUE_SIPHON, true); | |
| 2090 | } | |
| 2091 | ||
| 2092 | void Register() | |
| 2093 | {
| |
| 2094 | AfterEffectRemove += AuraEffectRemoveFn(spell_the_lich_king_necrotic_plague_AuraScript::OnRemove, EFFECT_0, SPELL_AURA_PERIODIC_DAMAGE, AURA_EFFECT_HANDLE_REAL); | |
| 2095 | } | |
| 2096 | }; | |
| 2097 | ||
| 2098 | AuraScript* GetAuraScript() const | |
| 2099 | {
| |
| 2100 | return new spell_the_lich_king_necrotic_plague_AuraScript(); | |
| 2101 | } | |
| 2102 | }; | |
| 2103 | ||
| 2104 | class spell_the_lich_king_necrotic_plague_jump : public SpellScriptLoader | |
| 2105 | {
| |
| 2106 | public: | |
| 2107 | spell_the_lich_king_necrotic_plague_jump() : SpellScriptLoader("spell_the_lich_king_necrotic_plague_jump") { }
| |
| 2108 | ||
| 2109 | class spell_the_lich_king_necrotic_plague_SpellScript : public SpellScript | |
| 2110 | {
| |
| 2111 | PrepareSpellScript(spell_the_lich_king_necrotic_plague_SpellScript); | |
| 2112 | ||
| 2113 | bool Load() | |
| 2114 | {
| |
| 2115 | _hadAura = false; | |
| 2116 | return true; | |
| 2117 | } | |
| 2118 | ||
| 2119 | void SelectTarget(std::list<Unit*>& targets) | |
| 2120 | {
| |
| 2121 | targets.sort(Trinity::ObjectDistanceOrderPred(GetCaster())); | |
| 2122 | if (targets.size() < 2) | |
| 2123 | return; | |
| 2124 | ||
| 2125 | targets.resize(1); | |
| 2126 | } | |
| 2127 | ||
| 2128 | void CheckAura() | |
| 2129 | {
| |
| 2130 | if (GetHitUnit()->HasAura(GetSpellInfo()->Id)) | |
| 2131 | _hadAura = true; | |
| 2132 | } | |
| 2133 | ||
| 2134 | void AddMissingStack() | |
| 2135 | {
| |
| 2136 | if (GetHitAura() && !_hadAura && GetSpellValue()->EffectBasePoints[EFFECT_1] != AURA_REMOVE_BY_ENEMY_SPELL) | |
| 2137 | GetHitAura()->ModStackAmount(1); | |
| 2138 | } | |
| 2139 | ||
| 2140 | void Register() | |
| 2141 | {
| |
| 2142 | BeforeHit += SpellHitFn(spell_the_lich_king_necrotic_plague_SpellScript::CheckAura); | |
| 2143 | OnHit += SpellHitFn(spell_the_lich_king_necrotic_plague_SpellScript::AddMissingStack); | |
| 2144 | } | |
| 2145 | ||
| 2146 | bool _hadAura; | |
| 2147 | }; | |
| 2148 | ||
| 2149 | class spell_the_lich_king_necrotic_plague_AuraScript : public AuraScript | |
| 2150 | {
| |
| 2151 | PrepareAuraScript(spell_the_lich_king_necrotic_plague_AuraScript); | |
| 2152 | ||
| 2153 | bool Load() | |
| 2154 | {
| |
| 2155 | _lastAmount = 0; | |
| 2156 | return true; | |
| 2157 | } | |
| 2158 | ||
| 2159 | void OnApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) | |
| 2160 | {
| |
| 2161 | if (Unit* caster = GetCaster()) | |
| 2162 | caster->GetAI()->SetData(DATA_PLAGUE_STACK, GetStackAmount()); | |
| 2163 | } | |
| 2164 | ||
| 2165 | void OnRemove(AuraEffect const* aurEff, AuraEffectHandleModes /*mode*/) | |
| 2166 | {
| |
| 2167 | _lastAmount = aurEff->GetAmount(); | |
| 2168 | switch (GetTargetApplication()->GetRemoveMode()) | |
| 2169 | {
| |
| 2170 | case AURA_REMOVE_BY_EXPIRE: | |
| 2171 | case AURA_REMOVE_BY_DEATH: | |
| 2172 | break; | |
| 2173 | default: | |
| 2174 | return; | |
| 2175 | } | |
| 2176 | ||
| 2177 | CustomSpellValues values; | |
| 2178 | values.AddSpellMod(SPELLVALUE_AURA_STACK, GetStackAmount()); | |
| 2179 | GetTarget()->CastCustomSpell(SPELL_NECROTIC_PLAGUE_JUMP, values, NULL, true, NULL, NULL, GetCasterGUID()); | |
| 2180 | if (Unit* caster = GetCaster()) | |
| 2181 | caster->CastSpell(caster, SPELL_PLAGUE_SIPHON, true); | |
| 2182 | } | |
| 2183 | ||
| 2184 | void OnDispel(AuraEffect const* aurEff, AuraEffectHandleModes /*mode*/) | |
| 2185 | {
| |
| 2186 | _lastAmount = aurEff->GetAmount(); | |
| 2187 | } | |
| 2188 | ||
| 2189 | void AfterDispel(AuraEffect const* aurEff, AuraEffectHandleModes /*mode*/) | |
| 2190 | {
| |
| 2191 | // this means the stack increased so don't process as if dispelled | |
| 2192 | if (aurEff->GetAmount() > _lastAmount) | |
| 2193 | return; | |
| 2194 | ||
| 2195 | CustomSpellValues values; | |
| 2196 | values.AddSpellMod(SPELLVALUE_AURA_STACK, GetStackAmount()); | |
| 2197 | values.AddSpellMod(SPELLVALUE_BASE_POINT1, AURA_REMOVE_BY_ENEMY_SPELL); // add as marker (spell has no effect 1) | |
| 2198 | GetTarget()->CastCustomSpell(SPELL_NECROTIC_PLAGUE_JUMP, values, NULL, true, NULL, NULL, GetCasterGUID()); | |
| 2199 | if (Unit* caster = GetCaster()) | |
| 2200 | caster->CastSpell(caster, SPELL_PLAGUE_SIPHON, true); | |
| 2201 | ||
| 2202 | Remove(AURA_REMOVE_BY_ENEMY_SPELL); | |
| 2203 | } | |
| 2204 | ||
| 2205 | void Register() | |
| 2206 | {
| |
| 2207 | OnEffectApply += AuraEffectApplyFn(spell_the_lich_king_necrotic_plague_AuraScript::OnApply, EFFECT_0, SPELL_AURA_PERIODIC_DAMAGE, AURA_EFFECT_HANDLE_REAL_OR_REAPPLY_MASK); | |
| 2208 | AfterEffectRemove += AuraEffectRemoveFn(spell_the_lich_king_necrotic_plague_AuraScript::OnRemove, EFFECT_0, SPELL_AURA_PERIODIC_DAMAGE, AURA_EFFECT_HANDLE_REAL); | |
| 2209 | AfterEffectRemove += AuraEffectRemoveFn(spell_the_lich_king_necrotic_plague_AuraScript::OnDispel, EFFECT_0, SPELL_AURA_PERIODIC_DAMAGE, AURA_EFFECT_HANDLE_REAPPLY); | |
| 2210 | AfterEffectApply += AuraEffectRemoveFn(spell_the_lich_king_necrotic_plague_AuraScript::AfterDispel, EFFECT_0, SPELL_AURA_PERIODIC_DAMAGE, AURA_EFFECT_HANDLE_REAPPLY); | |
| 2211 | } | |
| 2212 | ||
| 2213 | int32 _lastAmount; | |
| 2214 | }; | |
| 2215 | ||
| 2216 | SpellScript* GetSpellScript() const | |
| 2217 | {
| |
| 2218 | return new spell_the_lich_king_necrotic_plague_SpellScript(); | |
| 2219 | } | |
| 2220 | ||
| 2221 | AuraScript* GetAuraScript() const | |
| 2222 | {
| |
| 2223 | return new spell_the_lich_king_necrotic_plague_AuraScript(); | |
| 2224 | } | |
| 2225 | }; | |
| 2226 | ||
| 2227 | class spell_the_lich_king_shadow_trap_visual : public SpellScriptLoader | |
| 2228 | {
| |
| 2229 | public: | |
| 2230 | spell_the_lich_king_shadow_trap_visual() : SpellScriptLoader("spell_the_lich_king_shadow_trap_visual") { }
| |
| 2231 | ||
| 2232 | class spell_the_lich_king_shadow_trap_visual_AuraScript : public AuraScript | |
| 2233 | {
| |
| 2234 | PrepareAuraScript(spell_the_lich_king_shadow_trap_visual_AuraScript); | |
| 2235 | ||
| 2236 | void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) | |
| 2237 | {
| |
| 2238 | if (GetTargetApplication()->GetRemoveMode() == AURA_REMOVE_BY_EXPIRE) | |
| 2239 | GetTarget()->CastSpell(GetTarget(), SPELL_SHADOW_TRAP_AURA, TRIGGERED_NONE); | |
| 2240 | } | |
| 2241 | ||
| 2242 | void Register() | |
| 2243 | {
| |
| 2244 | AfterEffectRemove += AuraEffectRemoveFn(spell_the_lich_king_shadow_trap_visual_AuraScript::OnRemove, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL); | |
| 2245 | } | |
| 2246 | }; | |
| 2247 | ||
| 2248 | AuraScript* GetAuraScript() const | |
| 2249 | {
| |
| 2250 | return new spell_the_lich_king_shadow_trap_visual_AuraScript(); | |
| 2251 | } | |
| 2252 | }; | |
| 2253 | ||
| 2254 | class spell_the_lich_king_shadow_trap_periodic : public SpellScriptLoader | |
| 2255 | {
| |
| 2256 | public: | |
| 2257 | spell_the_lich_king_shadow_trap_periodic() : SpellScriptLoader("spell_the_lich_king_shadow_trap_periodic") { }
| |
| 2258 | ||
| 2259 | class spell_the_lich_king_shadow_trap_periodic_SpellScript : public SpellScript | |
| 2260 | {
| |
| 2261 | PrepareSpellScript(spell_the_lich_king_shadow_trap_periodic_SpellScript); | |
| 2262 | ||
| 2263 | void CheckTargetCount(std::list<Unit*>& targets) | |
| 2264 | {
| |
| 2265 | if (targets.empty()) | |
| 2266 | return; | |
| 2267 | ||
| 2268 | GetCaster()->CastSpell((Unit*)NULL, SPELL_SHADOW_TRAP_KNOCKBACK, true); | |
| 2269 | } | |
| 2270 | ||
| 2271 | void Register() | |
| 2272 | {
| |
| 2273 | OnUnitTargetSelect += SpellUnitTargetFn(spell_the_lich_king_shadow_trap_periodic_SpellScript::CheckTargetCount, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY); | |
| 2274 | } | |
| 2275 | }; | |
| 2276 | ||
| 2277 | SpellScript* GetSpellScript() const | |
| 2278 | {
| |
| 2279 | return new spell_the_lich_king_shadow_trap_periodic_SpellScript(); | |
| 2280 | } | |
| 2281 | }; | |
| 2282 | ||
| 2283 | class spell_the_lich_king_quake : public SpellScriptLoader | |
| 2284 | {
| |
| 2285 | public: | |
| 2286 | spell_the_lich_king_quake() : SpellScriptLoader("spell_the_lich_king_quake") { }
| |
| 2287 | ||
| 2288 | class spell_the_lich_king_quake_SpellScript : public SpellScript | |
| 2289 | {
| |
| 2290 | PrepareSpellScript(spell_the_lich_king_quake_SpellScript); | |
| 2291 | ||
| 2292 | bool Load() | |
| 2293 | {
| |
| 2294 | return GetCaster()->GetInstanceScript() != NULL; | |
| 2295 | } | |
| 2296 | ||
| 2297 | void FilterTargets(std::list<Unit*>& unitList) | |
| 2298 | {
| |
| 2299 | if (GameObject* platform = ObjectAccessor::GetGameObject(*GetCaster(), GetCaster()->GetInstanceScript()->GetData64(DATA_ARTHAS_PLATFORM))) | |
| 2300 | unitList.remove_if(HeightDifferenceCheck(platform, 5.0f, false)); | |
| 2301 | } | |
| 2302 | ||
| 2303 | void HandleSendEvent(SpellEffIndex /*effIndex*/) | |
| 2304 | {
| |
| 2305 | if (GetCaster()->IsAIEnabled) | |
| 2306 | GetCaster()->GetAI()->DoAction(ACTION_START_ATTACK); | |
| 2307 | } | |
| 2308 | ||
| 2309 | void Register() | |
| 2310 | {
| |
| 2311 | OnUnitTargetSelect += SpellUnitTargetFn(spell_the_lich_king_quake_SpellScript::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENTRY); | |
| 2312 | OnEffectHit += SpellEffectFn(spell_the_lich_king_quake_SpellScript::HandleSendEvent, EFFECT_1, SPELL_EFFECT_SEND_EVENT); | |
| 2313 | } | |
| 2314 | }; | |
| 2315 | ||
| 2316 | SpellScript* GetSpellScript() const | |
| 2317 | {
| |
| 2318 | return new spell_the_lich_king_quake_SpellScript(); | |
| 2319 | } | |
| 2320 | }; | |
| 2321 | ||
| 2322 | class spell_the_lich_king_ice_burst_target_search : public SpellScriptLoader | |
| 2323 | {
| |
| 2324 | public: | |
| 2325 | spell_the_lich_king_ice_burst_target_search() : SpellScriptLoader("spell_the_lich_king_ice_burst_target_search") { }
| |
| 2326 | ||
| 2327 | class spell_the_lich_king_ice_burst_target_search_SpellScript : public SpellScript | |
| 2328 | {
| |
| 2329 | PrepareSpellScript(spell_the_lich_king_ice_burst_target_search_SpellScript); | |
| 2330 | ||
| 2331 | bool Validate(SpellInfo const* /*spell*/) | |
| 2332 | {
| |
| 2333 | if (!sSpellMgr->GetSpellInfo(SPELL_ICE_BURST)) | |
| 2334 | return false; | |
| 2335 | return true; | |
| 2336 | } | |
| 2337 | ||
| 2338 | void CheckTargetCount(std::list<Unit*>& unitList) | |
| 2339 | {
| |
| 2340 | if (unitList.empty()) | |
| 2341 | return; | |
| 2342 | ||
| 2343 | // if there is at least one affected target cast the explosion | |
| 2344 | GetCaster()->CastSpell(GetCaster(), SPELL_ICE_BURST, true); | |
| 2345 | if (GetCaster()->GetTypeId() == TYPEID_UNIT) | |
| 2346 | GetCaster()->ToCreature()->DespawnOrUnsummon(500); | |
| 2347 | } | |
| 2348 | ||
| 2349 | void Register() | |
| 2350 | {
| |
| 2351 | OnUnitTargetSelect += SpellUnitTargetFn(spell_the_lich_king_ice_burst_target_search_SpellScript::CheckTargetCount, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY); | |
| 2352 | } | |
| 2353 | }; | |
| 2354 | ||
| 2355 | SpellScript* GetSpellScript() const | |
| 2356 | {
| |
| 2357 | return new spell_the_lich_king_ice_burst_target_search_SpellScript(); | |
| 2358 | } | |
| 2359 | }; | |
| 2360 | ||
| 2361 | class spell_the_lich_king_raging_spirit : public SpellScriptLoader | |
| 2362 | {
| |
| 2363 | public: | |
| 2364 | spell_the_lich_king_raging_spirit() : SpellScriptLoader("spell_the_lich_king_raging_spirit") { }
| |
| 2365 | ||
| 2366 | class spell_the_lich_king_raging_spirit_SpellScript : public SpellScript | |
| 2367 | {
| |
| 2368 | PrepareSpellScript(spell_the_lich_king_raging_spirit_SpellScript); | |
| 2369 | ||
| 2370 | bool Validate(SpellInfo const* /*spell*/) | |
| 2371 | {
| |
| 2372 | if (!sSpellMgr->GetSpellInfo(SPELL_LIFE_SIPHON_HEAL)) | |
| 2373 | return false; | |
| 2374 | return true; | |
| 2375 | } | |
| 2376 | ||
| 2377 | void HandleScript(SpellEffIndex effIndex) | |
| 2378 | {
| |
| 2379 | PreventHitDefaultEffect(effIndex); | |
| 2380 | GetHitUnit()->CastSpell(GetHitUnit(), uint32(GetEffectValue()), true); | |
| 2381 | } | |
| 2382 | ||
| 2383 | void Register() | |
| 2384 | {
| |
| 2385 | OnEffectHitTarget += SpellEffectFn(spell_the_lich_king_raging_spirit_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT); | |
| 2386 | } | |
| 2387 | }; | |
| 2388 | ||
| 2389 | SpellScript* GetSpellScript() const | |
| 2390 | {
| |
| 2391 | return new spell_the_lich_king_raging_spirit_SpellScript(); | |
| 2392 | } | |
| 2393 | }; | |
| 2394 | ||
| 2395 | class ExactDistanceCheck | |
| 2396 | {
| |
| 2397 | public: | |
| 2398 | ExactDistanceCheck(Unit* source, float dist) : _source(source), _dist(dist) {}
| |
| 2399 | ||
| 2400 | bool operator()(Unit* unit) | |
| 2401 | {
| |
| 2402 | return _source->GetExactDist2d(unit) > _dist; | |
| 2403 | } | |
| 2404 | ||
| 2405 | private: | |
| 2406 | Unit* _source; | |
| 2407 | float _dist; | |
| 2408 | }; | |
| 2409 | ||
| 2410 | class spell_the_lich_king_defile : public SpellScriptLoader | |
| 2411 | {
| |
| 2412 | public: | |
| 2413 | spell_the_lich_king_defile() : SpellScriptLoader("spell_the_lich_king_defile") { }
| |
| 2414 | ||
| 2415 | class spell_the_lich_king_defile_SpellScript : public SpellScript | |
| 2416 | {
| |
| 2417 | PrepareSpellScript(spell_the_lich_king_defile_SpellScript); | |
| 2418 | ||
| 2419 | void CorrectRange(std::list<Unit*>& targets) | |
| 2420 | {
| |
| 2421 | targets.remove_if(ExactDistanceCheck(GetCaster(), 10.0f * GetCaster()->GetFloatValue(OBJECT_FIELD_SCALE_X))); | |
| 2422 | } | |
| 2423 | ||
| 2424 | void ChangeDamageAndGrow() | |
| 2425 | {
| |
| 2426 | SetHitDamage(int32(GetHitDamage() * GetCaster()->GetFloatValue(OBJECT_FIELD_SCALE_X))); | |
| 2427 | // HACK: target player should cast this spell on defile | |
| 2428 | // however with current aura handling auras cast by different units | |
| 2429 | // cannot stack on the same aura object increasing the stack count | |
| 2430 | GetCaster()->CastSpell(GetCaster(), SPELL_DEFILE_GROW, true); | |
| 2431 | } | |
| 2432 | ||
| 2433 | void Register() | |
| 2434 | {
| |
| 2435 | OnUnitTargetSelect += SpellUnitTargetFn(spell_the_lich_king_defile_SpellScript::CorrectRange, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY); | |
| 2436 | OnUnitTargetSelect += SpellUnitTargetFn(spell_the_lich_king_defile_SpellScript::CorrectRange, EFFECT_1, TARGET_UNIT_SRC_AREA_ENEMY); | |
| 2437 | OnHit += SpellHitFn(spell_the_lich_king_defile_SpellScript::ChangeDamageAndGrow); | |
| 2438 | } | |
| 2439 | }; | |
| 2440 | ||
| 2441 | SpellScript* GetSpellScript() const | |
| 2442 | {
| |
| 2443 | return new spell_the_lich_king_defile_SpellScript(); | |
| 2444 | } | |
| 2445 | }; | |
| 2446 | ||
| 2447 | class spell_the_lich_king_summon_into_air : public SpellScriptLoader | |
| 2448 | {
| |
| 2449 | public: | |
| 2450 | spell_the_lich_king_summon_into_air() : SpellScriptLoader("spell_the_lich_king_summon_into_air") { }
| |
| 2451 | ||
| 2452 | class spell_the_lich_king_summon_into_air_SpellScript : public SpellScript | |
| 2453 | {
| |
| 2454 | PrepareSpellScript(spell_the_lich_king_summon_into_air_SpellScript); | |
| 2455 | ||
| 2456 | void ModDestHeight(SpellEffIndex effIndex) | |
| 2457 | {
| |
| 2458 | static Position const offset = {0.0f, 0.0f, 15.0f, 0.0f};
| |
| 2459 | WorldLocation* dest = const_cast<WorldLocation*>(GetTargetDest()); | |
| 2460 | dest->RelocateOffset(offset); | |
| 2461 | // spirit bombs get higher | |
| 2462 | if (GetSpellInfo()->Effects[effIndex].MiscValue == NPC_SPIRIT_BOMB) | |
| 2463 | dest->RelocateOffset(offset); | |
| 2464 | } | |
| 2465 | ||
| 2466 | void Register() | |
| 2467 | {
| |
| 2468 | OnEffectLaunch += SpellEffectFn(spell_the_lich_king_summon_into_air_SpellScript::ModDestHeight, EFFECT_0, SPELL_EFFECT_SUMMON); | |
| 2469 | } | |
| 2470 | }; | |
| 2471 | ||
| 2472 | SpellScript* GetSpellScript() const | |
| 2473 | {
| |
| 2474 | return new spell_the_lich_king_summon_into_air_SpellScript(); | |
| 2475 | } | |
| 2476 | }; | |
| 2477 | ||
| 2478 | class spell_the_lich_king_soul_reaper : public SpellScriptLoader | |
| 2479 | {
| |
| 2480 | public: | |
| 2481 | spell_the_lich_king_soul_reaper() : SpellScriptLoader("spell_the_lich_king_soul_reaper") { }
| |
| 2482 | ||
| 2483 | class spell_the_lich_king_soul_reaper_AuraScript : public AuraScript | |
| 2484 | {
| |
| 2485 | PrepareAuraScript(spell_the_lich_king_soul_reaper_AuraScript); | |
| 2486 | ||
| 2487 | bool Validate(SpellInfo const* /*spell*/) | |
| 2488 | {
| |
| 2489 | if (!sSpellMgr->GetSpellInfo(SPELL_SOUL_REAPER_BUFF)) | |
| 2490 | return false; | |
| 2491 | return true; | |
| 2492 | } | |
| 2493 | ||
| 2494 | void OnPeriodic(AuraEffect const* /*aurEff*/) | |
| 2495 | {
| |
| 2496 | if (Unit* caster = GetCaster()) | |
| 2497 | GetTarget()->CastSpell(caster, SPELL_SOUL_REAPER_BUFF, true); | |
| 2498 | } | |
| 2499 | ||
| 2500 | void Register() | |
| 2501 | {
| |
| 2502 | OnEffectPeriodic += AuraEffectPeriodicFn(spell_the_lich_king_soul_reaper_AuraScript::OnPeriodic, EFFECT_1, SPELL_AURA_PERIODIC_DAMAGE); | |
| 2503 | } | |
| 2504 | }; | |
| 2505 | ||
| 2506 | AuraScript* GetAuraScript() const | |
| 2507 | {
| |
| 2508 | return new spell_the_lich_king_soul_reaper_AuraScript(); | |
| 2509 | } | |
| 2510 | }; | |
| 2511 | ||
| 2512 | class spell_the_lich_king_valkyr_target_search : public SpellScriptLoader | |
| 2513 | {
| |
| 2514 | public: | |
| 2515 | spell_the_lich_king_valkyr_target_search() : SpellScriptLoader("spell_the_lich_king_valkyr_target_search") { }
| |
| 2516 | ||
| 2517 | class spell_the_lich_king_valkyr_target_search_SpellScript : public SpellScript | |
| 2518 | {
| |
| 2519 | PrepareSpellScript(spell_the_lich_king_valkyr_target_search_SpellScript); | |
| 2520 | ||
| 2521 | bool Validate(SpellInfo const* /*spell*/) | |
| 2522 | {
| |
| 2523 | if (!sSpellMgr->GetSpellInfo(SPELL_ICE_BURST)) | |
| 2524 | return false; | |
| 2525 | return true; | |
| 2526 | } | |
| 2527 | ||
| 2528 | bool Load() | |
| 2529 | {
| |
| 2530 | _target = NULL; | |
| 2531 | return true; | |
| 2532 | } | |
| 2533 | ||
| 2534 | void SelectTarget(std::list<Unit*>& unitList) | |
| 2535 | {
| |
| 2536 | if (unitList.empty()) | |
| 2537 | return; | |
| 2538 | ||
| 2539 | unitList.remove_if(Trinity::UnitAuraCheck(true, GetSpellInfo()->Id)); | |
| 2540 | if (unitList.empty()) | |
| 2541 | return; | |
| 2542 | ||
| 2543 | _target = SelectRandomContainerElement(unitList); | |
| 2544 | unitList.clear(); | |
| 2545 | unitList.push_back(_target); | |
| 2546 | GetCaster()->GetAI()->SetGUID(_target->GetGUID()); | |
| 2547 | } | |
| 2548 | ||
| 2549 | void ReplaceTarget(std::list<Unit*>& unitList) | |
| 2550 | {
| |
| 2551 | unitList.clear(); | |
| 2552 | if (_target) | |
| 2553 | unitList.push_back(_target); | |
| 2554 | } | |
| 2555 | ||
| 2556 | void HandleScript(SpellEffIndex effIndex) | |
| 2557 | {
| |
| 2558 | PreventHitDefaultEffect(effIndex); | |
| 2559 | GetCaster()->CastSpell(GetHitUnit(), SPELL_CHARGE, true); | |
| 2560 | } | |
| 2561 | ||
| 2562 | void Register() | |
| 2563 | {
| |
| 2564 | OnUnitTargetSelect += SpellUnitTargetFn(spell_the_lich_king_valkyr_target_search_SpellScript::SelectTarget, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY); | |
| 2565 | OnUnitTargetSelect += SpellUnitTargetFn(spell_the_lich_king_valkyr_target_search_SpellScript::ReplaceTarget, EFFECT_1, TARGET_UNIT_SRC_AREA_ENEMY); | |
| 2566 | OnEffectHitTarget += SpellEffectFn(spell_the_lich_king_valkyr_target_search_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT); | |
| 2567 | } | |
| 2568 | ||
| 2569 | Unit* _target; | |
| 2570 | }; | |
| 2571 | ||
| 2572 | SpellScript* GetSpellScript() const | |
| 2573 | {
| |
| 2574 | return new spell_the_lich_king_valkyr_target_search_SpellScript(); | |
| 2575 | } | |
| 2576 | }; | |
| 2577 | ||
| 2578 | class spell_the_lich_king_eject_all_passengers : public SpellScriptLoader | |
| 2579 | {
| |
| 2580 | public: | |
| 2581 | spell_the_lich_king_eject_all_passengers() : SpellScriptLoader("spell_the_lich_king_eject_all_passengers") { }
| |
| 2582 | ||
| 2583 | class spell_the_lich_king_eject_all_passengers_SpellScript : public SpellScript | |
| 2584 | {
| |
| 2585 | PrepareSpellScript(spell_the_lich_king_eject_all_passengers_SpellScript); | |
| 2586 | ||
| 2587 | bool Load() | |
| 2588 | {
| |
| 2589 | return GetCaster()->IsVehicle(); | |
| 2590 | } | |
| 2591 | ||
| 2592 | void HandleDummy(SpellEffIndex effIndex) | |
| 2593 | {
| |
| 2594 | PreventHitDefaultEffect(effIndex); | |
| 2595 | GetCaster()->GetVehicleKit()->RemoveAllPassengers(); | |
| 2596 | } | |
| 2597 | ||
| 2598 | void Register() | |
| 2599 | {
| |
| 2600 | OnEffectHitTarget += SpellEffectFn(spell_the_lich_king_eject_all_passengers_SpellScript::HandleDummy, EFFECT_0, SPELL_EFFECT_DUMMY); | |
| 2601 | } | |
| 2602 | }; | |
| 2603 | ||
| 2604 | SpellScript* GetSpellScript() const | |
| 2605 | {
| |
| 2606 | return new spell_the_lich_king_eject_all_passengers_SpellScript(); | |
| 2607 | } | |
| 2608 | }; | |
| 2609 | ||
| 2610 | class spell_the_lich_king_cast_back_to_caster : public SpellScriptLoader | |
| 2611 | {
| |
| 2612 | public: | |
| 2613 | spell_the_lich_king_cast_back_to_caster() : SpellScriptLoader("spell_the_lich_king_cast_back_to_caster") { }
| |
| 2614 | ||
| 2615 | class spell_the_lich_king_cast_back_to_caster_SpellScript : public SpellScript | |
| 2616 | {
| |
| 2617 | PrepareSpellScript(spell_the_lich_king_cast_back_to_caster_SpellScript); | |
| 2618 | ||
| 2619 | void HandleScript(SpellEffIndex /*effIndex*/) | |
| 2620 | {
| |
| 2621 | GetHitUnit()->CastSpell(GetCaster(), uint32(GetEffectValue()), true); | |
| 2622 | } | |
| 2623 | ||
| 2624 | void Register() | |
| 2625 | {
| |
| 2626 | OnEffectHitTarget += SpellEffectFn(spell_the_lich_king_cast_back_to_caster_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT); | |
| 2627 | } | |
| 2628 | }; | |
| 2629 | ||
| 2630 | SpellScript* GetSpellScript() const | |
| 2631 | {
| |
| 2632 | return new spell_the_lich_king_cast_back_to_caster_SpellScript(); | |
| 2633 | } | |
| 2634 | }; | |
| 2635 | ||
| 2636 | class spell_the_lich_king_life_siphon : public SpellScriptLoader | |
| 2637 | {
| |
| 2638 | public: | |
| 2639 | spell_the_lich_king_life_siphon() : SpellScriptLoader("spell_the_lich_king_life_siphon") { }
| |
| 2640 | ||
| 2641 | class spell_the_lich_king_life_siphon_SpellScript : public SpellScript | |
| 2642 | {
| |
| 2643 | PrepareSpellScript(spell_the_lich_king_life_siphon_SpellScript); | |
| 2644 | ||
| 2645 | bool Validate(SpellInfo const* /*spell*/) | |
| 2646 | {
| |
| 2647 | if (!sSpellMgr->GetSpellInfo(SPELL_LIFE_SIPHON_HEAL)) | |
| 2648 | return false; | |
| 2649 | return true; | |
| 2650 | } | |
| 2651 | ||
| 2652 | void TriggerHeal() | |
| 2653 | {
| |
| 2654 | GetHitUnit()->CastCustomSpell(SPELL_LIFE_SIPHON_HEAL, SPELLVALUE_BASE_POINT0, GetHitDamage() * 10, GetCaster(), true); | |
| 2655 | } | |
| 2656 | ||
| 2657 | void Register() | |
| 2658 | {
| |
| 2659 | AfterHit += SpellHitFn(spell_the_lich_king_life_siphon_SpellScript::TriggerHeal); | |
| 2660 | } | |
| 2661 | }; | |
| 2662 | ||
| 2663 | SpellScript* GetSpellScript() const | |
| 2664 | {
| |
| 2665 | return new spell_the_lich_king_life_siphon_SpellScript(); | |
| 2666 | } | |
| 2667 | }; | |
| 2668 | ||
| 2669 | class spell_the_lich_king_vile_spirits : public SpellScriptLoader | |
| 2670 | {
| |
| 2671 | public: | |
| 2672 | spell_the_lich_king_vile_spirits() : SpellScriptLoader("spell_the_lich_king_vile_spirits") { }
| |
| 2673 | ||
| 2674 | class spell_the_lich_king_vile_spirits_AuraScript : public AuraScript | |
| 2675 | {
| |
| 2676 | PrepareAuraScript(spell_the_lich_king_vile_spirits_AuraScript); | |
| 2677 | ||
| 2678 | bool Load() | |
| 2679 | {
| |
| 2680 | _is25Man = GetUnitOwner()->GetMap()->Is25ManRaid(); | |
| 2681 | return true; | |
| 2682 | } | |
| 2683 | ||
| 2684 | void OnPeriodic(AuraEffect const* aurEff) | |
| 2685 | {
| |
| 2686 | if (_is25Man || ((aurEff->GetTickNumber() - 1) % 5)) | |
| 2687 | GetTarget()->CastSpell((Unit*)NULL, GetSpellInfo()->Effects[aurEff->GetEffIndex()].TriggerSpell, true, NULL, aurEff, GetCasterGUID()); | |
| 2688 | } | |
| 2689 | ||
| 2690 | void Register() | |
| 2691 | {
| |
| 2692 | OnEffectPeriodic += AuraEffectPeriodicFn(spell_the_lich_king_vile_spirits_AuraScript::OnPeriodic, EFFECT_0, SPELL_AURA_PERIODIC_DUMMY); | |
| 2693 | } | |
| 2694 | ||
| 2695 | bool _is25Man; | |
| 2696 | }; | |
| 2697 | ||
| 2698 | AuraScript* GetAuraScript() const | |
| 2699 | {
| |
| 2700 | return new spell_the_lich_king_vile_spirits_AuraScript(); | |
| 2701 | } | |
| 2702 | }; | |
| 2703 | ||
| 2704 | class spell_the_lich_king_vile_spirits_visual : public SpellScriptLoader | |
| 2705 | {
| |
| 2706 | public: | |
| 2707 | spell_the_lich_king_vile_spirits_visual() : SpellScriptLoader("spell_the_lich_king_vile_spirits_visual") { }
| |
| 2708 | ||
| 2709 | class spell_the_lich_king_vile_spirits_visual_SpellScript : public SpellScript | |
| 2710 | {
| |
| 2711 | PrepareSpellScript(spell_the_lich_king_vile_spirits_visual_SpellScript); | |
| 2712 | ||
| 2713 | void ModDestHeight(SpellEffIndex /*effIndex*/) | |
| 2714 | {
| |
| 2715 | Position offset = {0.0f, 0.0f, 15.0f, 0.0f};
| |
| 2716 | const_cast<WorldLocation*>(GetTargetDest())->RelocateOffset(offset); | |
| 2717 | } | |
| 2718 | ||
| 2719 | void Register() | |
| 2720 | {
| |
| 2721 | OnEffectLaunch += SpellEffectFn(spell_the_lich_king_vile_spirits_visual_SpellScript::ModDestHeight, EFFECT_0, SPELL_EFFECT_DUMMY); | |
| 2722 | } | |
| 2723 | }; | |
| 2724 | ||
| 2725 | SpellScript* GetSpellScript() const | |
| 2726 | {
| |
| 2727 | return new spell_the_lich_king_vile_spirits_visual_SpellScript(); | |
| 2728 | } | |
| 2729 | }; | |
| 2730 | ||
| 2731 | class spell_the_lich_king_vile_spirit_move_target_search : public SpellScriptLoader | |
| 2732 | {
| |
| 2733 | public: | |
| 2734 | spell_the_lich_king_vile_spirit_move_target_search() : SpellScriptLoader("spell_the_lich_king_vile_spirit_move_target_search") { }
| |
| 2735 | ||
| 2736 | class spell_the_lich_king_vile_spirit_move_target_search_SpellScript : public SpellScript | |
| 2737 | {
| |
| 2738 | PrepareSpellScript(spell_the_lich_king_vile_spirit_move_target_search_SpellScript); | |
| 2739 | ||
| 2740 | bool Load() | |
| 2741 | {
| |
| 2742 | _target = NULL; | |
| 2743 | return GetCaster()->GetTypeId() == TYPEID_UNIT; | |
| 2744 | } | |
| 2745 | ||
| 2746 | void SelectTarget(std::list<Unit*>& targets) | |
| 2747 | {
| |
| 2748 | if (targets.empty()) | |
| 2749 | return; | |
| 2750 | ||
| 2751 | _target = SelectRandomContainerElement(targets); | |
| 2752 | } | |
| 2753 | ||
| 2754 | void HandleScript(SpellEffIndex effIndex) | |
| 2755 | {
| |
| 2756 | PreventHitDefaultEffect(effIndex); | |
| 2757 | // for this spell, all units are in target map, however it should select one to attack | |
| 2758 | if (GetHitUnit() != _target) | |
| 2759 | return; | |
| 2760 | ||
| 2761 | GetCaster()->ToCreature()->AI()->AttackStart(GetHitUnit()); | |
| 2762 | GetCaster()->AddThreat(GetHitUnit(), 100000.0f); | |
| 2763 | } | |
| 2764 | ||
| 2765 | void Register() | |
| 2766 | {
| |
| 2767 | OnUnitTargetSelect += SpellUnitTargetFn(spell_the_lich_king_vile_spirit_move_target_search_SpellScript::SelectTarget, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY); | |
| 2768 | OnEffectHitTarget += SpellEffectFn(spell_the_lich_king_vile_spirit_move_target_search_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT); | |
| 2769 | } | |
| 2770 | ||
| 2771 | Unit* _target; | |
| 2772 | }; | |
| 2773 | ||
| 2774 | SpellScript* GetSpellScript() const | |
| 2775 | {
| |
| 2776 | return new spell_the_lich_king_vile_spirit_move_target_search_SpellScript(); | |
| 2777 | } | |
| 2778 | }; | |
| 2779 | ||
| 2780 | class spell_the_lich_king_vile_spirit_damage_target_search : public SpellScriptLoader | |
| 2781 | {
| |
| 2782 | public: | |
| 2783 | spell_the_lich_king_vile_spirit_damage_target_search() : SpellScriptLoader("spell_the_lich_king_vile_spirit_damage_target_search") { }
| |
| 2784 | ||
| 2785 | class spell_the_lich_king_vile_spirit_damage_target_search_SpellScript : public SpellScript | |
| 2786 | {
| |
| 2787 | PrepareSpellScript(spell_the_lich_king_vile_spirit_damage_target_search_SpellScript); | |
| 2788 | ||
| 2789 | bool Load() | |
| 2790 | {
| |
| 2791 | return GetCaster()->GetTypeId() == TYPEID_UNIT; | |
| 2792 | } | |
| 2793 | ||
| 2794 | void CheckTargetCount(std::list<Unit*>& targets) | |
| 2795 | {
| |
| 2796 | if (targets.empty()) | |
| 2797 | return; | |
| 2798 | ||
| 2799 | // this spell has SPELL_AURA_BLOCK_SPELL_FAMILY so every next cast of this | |
| 2800 | // searcher spell will be blocked | |
| 2801 | if (TempSummon* summon = GetCaster()->ToTempSummon()) | |
| 2802 | if (Unit* summoner = summon->GetSummoner()) | |
| 2803 | summoner->GetAI()->SetData(DATA_VILE, 1); | |
| 2804 | GetCaster()->CastSpell((Unit*)NULL, SPELL_SPIRIT_BURST, true); | |
| 2805 | GetCaster()->ToCreature()->DespawnOrUnsummon(3000); | |
| 2806 | GetCaster()->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); | |
| 2807 | } | |
| 2808 | ||
| 2809 | void Register() | |
| 2810 | {
| |
| 2811 | OnUnitTargetSelect += SpellUnitTargetFn(spell_the_lich_king_vile_spirit_damage_target_search_SpellScript::CheckTargetCount, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY); | |
| 2812 | } | |
| 2813 | ||
| 2814 | Unit* _target; | |
| 2815 | }; | |
| 2816 | ||
| 2817 | SpellScript* GetSpellScript() const | |
| 2818 | {
| |
| 2819 | return new spell_the_lich_king_vile_spirit_damage_target_search_SpellScript(); | |
| 2820 | } | |
| 2821 | }; | |
| 2822 | ||
| 2823 | class spell_the_lich_king_harvest_soul : public SpellScriptLoader | |
| 2824 | {
| |
| 2825 | public: | |
| 2826 | spell_the_lich_king_harvest_soul() : SpellScriptLoader("spell_the_lich_king_harvest_soul") { }
| |
| 2827 | ||
| 2828 | class spell_the_lich_king_harvest_soul_AuraScript : public AuraScript | |
| 2829 | {
| |
| 2830 | PrepareAuraScript(spell_the_lich_king_harvest_soul_AuraScript); | |
| 2831 | ||
| 2832 | bool Load() | |
| 2833 | {
| |
| 2834 | return GetOwner()->GetInstanceScript() != NULL; | |
| 2835 | } | |
| 2836 | ||
| 2837 | void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) | |
| 2838 | {
| |
| 2839 | // m_originalCaster to allow stacking from different casters, meh | |
| 2840 | if (GetTargetApplication()->GetRemoveMode() == AURA_REMOVE_BY_DEATH) | |
| 2841 | GetTarget()->CastSpell((Unit*)NULL, SPELL_HARVESTED_SOUL, true, NULL, NULL, GetTarget()->GetInstanceScript()->GetData64(DATA_THE_LICH_KING)); | |
| 2842 | } | |
| 2843 | ||
| 2844 | void Register() | |
| 2845 | {
| |
| 2846 | AfterEffectRemove += AuraEffectRemoveFn(spell_the_lich_king_harvest_soul_AuraScript::OnRemove, EFFECT_0, SPELL_AURA_PERIODIC_DAMAGE, AURA_EFFECT_HANDLE_REAL); | |
| 2847 | } | |
| 2848 | }; | |
| 2849 | ||
| 2850 | AuraScript* GetAuraScript() const | |
| 2851 | {
| |
| 2852 | return new spell_the_lich_king_harvest_soul_AuraScript(); | |
| 2853 | } | |
| 2854 | }; | |
| 2855 | ||
| 2856 | class spell_the_lich_king_lights_favor : public SpellScriptLoader | |
| 2857 | {
| |
| 2858 | public: | |
| 2859 | spell_the_lich_king_lights_favor() : SpellScriptLoader("spell_the_lich_king_lights_favor") { }
| |
| 2860 | ||
| 2861 | class spell_the_lich_king_lights_favor_AuraScript : public AuraScript | |
| 2862 | {
| |
| 2863 | PrepareAuraScript(spell_the_lich_king_lights_favor_AuraScript); | |
| 2864 | ||
| 2865 | void OnPeriodic(AuraEffect const* /*aurEff*/) | |
| 2866 | {
| |
| 2867 | if (Unit* caster = GetCaster()) | |
| 2868 | if (AuraEffect* effect = GetAura()->GetEffect(EFFECT_1)) | |
| 2869 | effect->RecalculateAmount(caster); | |
| 2870 | } | |
| 2871 | ||
| 2872 | void CalculateBonus(AuraEffect const* /*aurEff*/, int32& amount, bool& canBeRecalculated) | |
| 2873 | {
| |
| 2874 | canBeRecalculated = true; | |
| 2875 | amount = 0; | |
| 2876 | if (Unit* caster = GetCaster()) | |
| 2877 | amount = int32(caster->GetHealthPct()); | |
| 2878 | } | |
| 2879 | ||
| 2880 | void Register() | |
| 2881 | {
| |
| 2882 | OnEffectPeriodic += AuraEffectPeriodicFn(spell_the_lich_king_lights_favor_AuraScript::OnPeriodic, EFFECT_0, SPELL_AURA_PERIODIC_HEAL); | |
| 2883 | DoEffectCalcAmount += AuraEffectCalcAmountFn(spell_the_lich_king_lights_favor_AuraScript::CalculateBonus, EFFECT_1, SPELL_AURA_MOD_DAMAGE_PERCENT_DONE); | |
| 2884 | } | |
| 2885 | }; | |
| 2886 | ||
| 2887 | AuraScript* GetAuraScript() const | |
| 2888 | {
| |
| 2889 | return new spell_the_lich_king_lights_favor_AuraScript(); | |
| 2890 | } | |
| 2891 | }; | |
| 2892 | ||
| 2893 | class spell_the_lich_king_soul_rip : public SpellScriptLoader | |
| 2894 | {
| |
| 2895 | public: | |
| 2896 | spell_the_lich_king_soul_rip() : SpellScriptLoader("spell_the_lich_king_soul_rip") { }
| |
| 2897 | ||
| 2898 | class spell_the_lich_king_soul_rip_AuraScript : public AuraScript | |
| 2899 | {
| |
| 2900 | PrepareAuraScript(spell_the_lich_king_soul_rip_AuraScript); | |
| 2901 | ||
| 2902 | void OnPeriodic(AuraEffect const* aurEff) | |
| 2903 | {
| |
| 2904 | PreventDefaultAction(); | |
| 2905 | // shouldn't be needed, this is channeled | |
| 2906 | if (Unit* caster = GetCaster()) | |
| 2907 | caster->CastCustomSpell(SPELL_SOUL_RIP_DAMAGE, SPELLVALUE_BASE_POINT0, 5000 * aurEff->GetTickNumber(), GetTarget(), true, NULL, aurEff, GetCasterGUID()); | |
| 2908 | } | |
| 2909 | ||
| 2910 | void Register() | |
| 2911 | {
| |
| 2912 | OnEffectPeriodic += AuraEffectPeriodicFn(spell_the_lich_king_soul_rip_AuraScript::OnPeriodic, EFFECT_0, SPELL_AURA_PERIODIC_DUMMY); | |
| 2913 | } | |
| 2914 | }; | |
| 2915 | ||
| 2916 | AuraScript* GetAuraScript() const | |
| 2917 | {
| |
| 2918 | return new spell_the_lich_king_soul_rip_AuraScript(); | |
| 2919 | } | |
| 2920 | }; | |
| 2921 | ||
| 2922 | class spell_the_lich_king_restore_soul : public SpellScriptLoader | |
| 2923 | {
| |
| 2924 | public: | |
| 2925 | spell_the_lich_king_restore_soul() : SpellScriptLoader("spell_the_lich_king_restore_soul") { }
| |
| 2926 | ||
| 2927 | class spell_the_lich_king_restore_soul_SpellScript : public SpellScript | |
| 2928 | {
| |
| 2929 | PrepareSpellScript(spell_the_lich_king_restore_soul_SpellScript); | |
| 2930 | ||
| 2931 | bool Load() | |
| 2932 | {
| |
| 2933 | _instance = GetCaster()->GetInstanceScript(); | |
| 2934 | return _instance != NULL; | |
| 2935 | } | |
| 2936 | ||
| 2937 | void HandleScript(SpellEffIndex /*effIndex*/) | |
| 2938 | {
| |
| 2939 | if (Creature* lichKing = ObjectAccessor::GetCreature(*GetCaster(), _instance->GetData64(DATA_THE_LICH_KING))) | |
| 2940 | lichKing->AI()->DoAction(ACTION_TELEPORT_BACK); | |
| 2941 | if (Creature* spawner = GetCaster()->FindNearestCreature(NPC_WORLD_TRIGGER_INFINITE_AOI, 50.0f)) | |
| 2942 | spawner->RemoveAllAuras(); | |
| 2943 | } | |
| 2944 | ||
| 2945 | void RemoveAura() | |
| 2946 | {
| |
| 2947 | if (Unit* target = GetHitUnit()) | |
| 2948 | target->RemoveAurasDueToSpell(target->GetMap()->IsHeroic() ? SPELL_HARVEST_SOULS_TELEPORT : SPELL_HARVEST_SOUL_TELEPORT); | |
| 2949 | } | |
| 2950 | ||
| 2951 | void Register() | |
| 2952 | {
| |
| 2953 | OnEffectHit += SpellEffectFn(spell_the_lich_king_restore_soul_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_APPLY_AURA); | |
| 2954 | BeforeHit += SpellHitFn(spell_the_lich_king_restore_soul_SpellScript::RemoveAura); | |
| 2955 | } | |
| 2956 | ||
| 2957 | InstanceScript* _instance; | |
| 2958 | }; | |
| 2959 | ||
| 2960 | SpellScript* GetSpellScript() const | |
| 2961 | {
| |
| 2962 | return new spell_the_lich_king_restore_soul_SpellScript(); | |
| 2963 | } | |
| 2964 | }; | |
| 2965 | ||
| 2966 | class spell_the_lich_king_in_frostmourne_room : public SpellScriptLoader | |
| 2967 | {
| |
| 2968 | public: | |
| 2969 | spell_the_lich_king_in_frostmourne_room() : SpellScriptLoader("spell_the_lich_king_in_frostmourne_room") { }
| |
| 2970 | ||
| 2971 | class spell_the_lich_king_in_frostmourne_room_AuraScript : public AuraScript | |
| 2972 | {
| |
| 2973 | PrepareAuraScript(spell_the_lich_king_in_frostmourne_room_AuraScript); | |
| 2974 | ||
| 2975 | bool Load() | |
| 2976 | {
| |
| 2977 | return GetOwner()->GetInstanceScript() != NULL; | |
| 2978 | } | |
| 2979 | ||
| 2980 | void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) | |
| 2981 | {
| |
| 2982 | // m_originalCaster to allow stacking from different casters, meh | |
| 2983 | if (GetTargetApplication()->GetRemoveMode() == AURA_REMOVE_BY_DEATH) | |
| 2984 | GetTarget()->CastSpell((Unit*)NULL, SPELL_HARVESTED_SOUL, true, NULL, NULL, GetTarget()->GetInstanceScript()->GetData64(DATA_THE_LICH_KING)); | |
| 2985 | } | |
| 2986 | ||
| 2987 | void Register() | |
| 2988 | {
| |
| 2989 | AfterEffectRemove += AuraEffectRemoveFn(spell_the_lich_king_in_frostmourne_room_AuraScript::OnRemove, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL); | |
| 2990 | } | |
| 2991 | }; | |
| 2992 | ||
| 2993 | AuraScript* GetAuraScript() const | |
| 2994 | {
| |
| 2995 | return new spell_the_lich_king_in_frostmourne_room_AuraScript(); | |
| 2996 | } | |
| 2997 | }; | |
| 2998 | ||
| 2999 | class spell_the_lich_king_summon_spirit_bomb : public SpellScriptLoader | |
| 3000 | {
| |
| 3001 | public: | |
| 3002 | spell_the_lich_king_summon_spirit_bomb() : SpellScriptLoader("spell_the_lich_king_summon_spirit_bomb") { }
| |
| 3003 | ||
| 3004 | class spell_the_lich_king_summon_spirit_bomb_SpellScript : public SpellScript | |
| 3005 | {
| |
| 3006 | PrepareSpellScript(spell_the_lich_king_summon_spirit_bomb_SpellScript); | |
| 3007 | ||
| 3008 | void HandleScript(SpellEffIndex effIndex) | |
| 3009 | {
| |
| 3010 | PreventHitDefaultEffect(effIndex); | |
| 3011 | GetHitUnit()->CastSpell((Unit*)NULL, uint32(GetEffectValue()), true); | |
| 3012 | } | |
| 3013 | ||
| 3014 | void Register() | |
| 3015 | {
| |
| 3016 | OnEffectHitTarget += SpellEffectFn(spell_the_lich_king_summon_spirit_bomb_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT); | |
| 3017 | } | |
| 3018 | }; | |
| 3019 | ||
| 3020 | SpellScript* GetSpellScript() const | |
| 3021 | {
| |
| 3022 | return new spell_the_lich_king_summon_spirit_bomb_SpellScript(); | |
| 3023 | } | |
| 3024 | }; | |
| 3025 | ||
| 3026 | class spell_the_lich_king_trigger_vile_spirit : public SpellScriptLoader | |
| 3027 | {
| |
| 3028 | public: | |
| 3029 | spell_the_lich_king_trigger_vile_spirit() : SpellScriptLoader("spell_the_lich_king_trigger_vile_spirit") { }
| |
| 3030 | ||
| 3031 | class spell_the_lich_king_trigger_vile_spirit_SpellScript : public SpellScript | |
| 3032 | {
| |
| 3033 | PrepareSpellScript(spell_the_lich_king_trigger_vile_spirit_SpellScript); | |
| 3034 | ||
| 3035 | void TeleportOutside() | |
| 3036 | {
| |
| 3037 | Creature* target = GetHitCreature(); | |
| 3038 | if (!target) | |
| 3039 | return; | |
| 3040 | ||
| 3041 | Position dest; | |
| 3042 | Position offset; | |
| 3043 | TerenasSpawnHeroic.GetPositionOffsetTo(*target, offset); | |
| 3044 | GetCaster()->GetPosition(&dest); | |
| 3045 | dest.RelocateOffset(offset); | |
| 3046 | target->NearTeleportTo(dest.GetPositionX(), dest.GetPositionY(), dest.GetPositionZ(), dest.GetOrientation()); | |
| 3047 | } | |
| 3048 | ||
| 3049 | void Register() | |
| 3050 | {
| |
| 3051 | OnHit += SpellHitFn(spell_the_lich_king_trigger_vile_spirit_SpellScript::TeleportOutside); | |
| 3052 | } | |
| 3053 | }; | |
| 3054 | ||
| 3055 | SpellScript* GetSpellScript() const | |
| 3056 | {
| |
| 3057 | return new spell_the_lich_king_trigger_vile_spirit_SpellScript(); | |
| 3058 | } | |
| 3059 | }; | |
| 3060 | ||
| 3061 | class spell_the_lich_king_jump : public SpellScriptLoader | |
| 3062 | {
| |
| 3063 | public: | |
| 3064 | spell_the_lich_king_jump() : SpellScriptLoader("spell_the_lich_king_jump") { }
| |
| 3065 | ||
| 3066 | class spell_the_lich_king_jump_SpellScript : public SpellScript | |
| 3067 | {
| |
| 3068 | PrepareSpellScript(spell_the_lich_king_jump_SpellScript); | |
| 3069 | ||
| 3070 | void HandleScript(SpellEffIndex effIndex) | |
| 3071 | {
| |
| 3072 | PreventHitDefaultEffect(effIndex); | |
| 3073 | GetHitUnit()->RemoveAurasDueToSpell(SPELL_RAISE_DEAD); | |
| 3074 | GetHitUnit()->CastSpell((Unit*)NULL, SPELL_JUMP_2, true); | |
| 3075 | if (Creature* creature = GetHitCreature()) | |
| 3076 | creature->AI()->DoAction(ACTION_BREAK_FROSTMOURNE); | |
| 3077 | } | |
| 3078 | ||
| 3079 | void Register() | |
| 3080 | {
| |
| 3081 | OnEffectHitTarget += SpellEffectFn(spell_the_lich_king_jump_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT); | |
| 3082 | } | |
| 3083 | }; | |
| 3084 | ||
| 3085 | SpellScript* GetSpellScript() const | |
| 3086 | {
| |
| 3087 | return new spell_the_lich_king_jump_SpellScript(); | |
| 3088 | } | |
| 3089 | }; | |
| 3090 | ||
| 3091 | class spell_the_lich_king_jump_remove_aura : public SpellScriptLoader | |
| 3092 | {
| |
| 3093 | public: | |
| 3094 | spell_the_lich_king_jump_remove_aura() : SpellScriptLoader("spell_the_lich_king_jump_remove_aura") { }
| |
| 3095 | ||
| 3096 | class spell_the_lich_king_jump_SpellScript : public SpellScript | |
| 3097 | {
| |
| 3098 | PrepareSpellScript(spell_the_lich_king_jump_SpellScript); | |
| 3099 | ||
| 3100 | void HandleScript(SpellEffIndex effIndex) | |
| 3101 | {
| |
| 3102 | PreventHitDefaultEffect(effIndex); | |
| 3103 | GetHitUnit()->RemoveAurasDueToSpell(uint32(GetEffectValue())); | |
| 3104 | } | |
| 3105 | ||
| 3106 | void Register() | |
| 3107 | {
| |
| 3108 | OnEffectHitTarget += SpellEffectFn(spell_the_lich_king_jump_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT); | |
| 3109 | } | |
| 3110 | }; | |
| 3111 | ||
| 3112 | SpellScript* GetSpellScript() const | |
| 3113 | {
| |
| 3114 | return new spell_the_lich_king_jump_SpellScript(); | |
| 3115 | } | |
| 3116 | }; | |
| 3117 | ||
| 3118 | class spell_the_lich_king_play_movie : public SpellScriptLoader | |
| 3119 | {
| |
| 3120 | public: | |
| 3121 | spell_the_lich_king_play_movie() : SpellScriptLoader("spell_the_lich_king_play_movie") { }
| |
| 3122 | ||
| 3123 | class spell_the_lich_king_play_movie_SpellScript : public SpellScript | |
| 3124 | {
| |
| 3125 | PrepareSpellScript(spell_the_lich_king_play_movie_SpellScript); | |
| 3126 | ||
| 3127 | bool Validate(SpellInfo const* /*spell*/) | |
| 3128 | {
| |
| 3129 | if (!sMovieStore.LookupEntry(MOVIE_FALL_OF_THE_LICH_KING)) | |
| 3130 | return false; | |
| 3131 | return true; | |
| 3132 | } | |
| 3133 | ||
| 3134 | void HandleScript(SpellEffIndex effIndex) | |
| 3135 | {
| |
| 3136 | PreventHitDefaultEffect(effIndex); | |
| 3137 | if (Player* player = GetHitPlayer()) | |
| 3138 | player->SendMovieStart(MOVIE_FALL_OF_THE_LICH_KING); | |
| 3139 | } | |
| 3140 | ||
| 3141 | void Register() | |
| 3142 | {
| |
| 3143 | OnEffectHitTarget += SpellEffectFn(spell_the_lich_king_play_movie_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT); | |
| 3144 | } | |
| 3145 | }; | |
| 3146 | ||
| 3147 | SpellScript* GetSpellScript() const | |
| 3148 | {
| |
| 3149 | return new spell_the_lich_king_play_movie_SpellScript(); | |
| 3150 | } | |
| 3151 | }; | |
| 3152 | ||
| 3153 | class achievement_been_waiting_long_time : public AchievementCriteriaScript | |
| 3154 | {
| |
| 3155 | public: | |
| 3156 | achievement_been_waiting_long_time() : AchievementCriteriaScript("achievement_been_waiting_long_time") { }
| |
| 3157 | ||
| 3158 | bool OnCheck(Player* /*source*/, Unit* target) | |
| 3159 | {
| |
| 3160 | if (!target) | |
| 3161 | return false; | |
| 3162 | ||
| 3163 | return target->GetAI()->GetData(DATA_PLAGUE_STACK) >= 30; | |
| 3164 | } | |
| 3165 | }; | |
| 3166 | ||
| 3167 | class achievement_neck_deep_in_vile : public AchievementCriteriaScript | |
| 3168 | {
| |
| 3169 | public: | |
| 3170 | achievement_neck_deep_in_vile() : AchievementCriteriaScript("achievement_neck_deep_in_vile") { }
| |
| 3171 | ||
| 3172 | bool OnCheck(Player* /*source*/, Unit* target) | |
| 3173 | {
| |
| 3174 | if (!target) | |
| 3175 | return false; | |
| 3176 | ||
| 3177 | return !target->GetAI()->GetData(DATA_VILE); | |
| 3178 | } | |
| 3179 | }; | |
| 3180 | ||
| 3181 | void AddSC_boss_the_lich_king() | |
| 3182 | {
| |
| 3183 | new boss_the_lich_king(); | |
| 3184 | new npc_tirion_fordring_tft(); | |
| 3185 | new npc_shambling_horror_icc(); | |
| 3186 | new npc_raging_spirit(); | |
| 3187 | new npc_valkyr_shadowguard(); | |
| 3188 | new npc_strangulate_vehicle(); | |
| 3189 | new npc_terenas_menethil(); | |
| 3190 | new npc_spirit_warden(); | |
| 3191 | new npc_spirit_bomb(); | |
| 3192 | new npc_broken_frostmourne(); | |
| 3193 | new spell_the_lich_king_infest(); | |
| 3194 | new spell_the_lich_king_necrotic_plague(); | |
| 3195 | new spell_the_lich_king_necrotic_plague_jump(); | |
| 3196 | new spell_the_lich_king_shadow_trap_visual(); | |
| 3197 | new spell_the_lich_king_shadow_trap_periodic(); | |
| 3198 | new spell_the_lich_king_quake(); | |
| 3199 | new spell_the_lich_king_ice_burst_target_search(); | |
| 3200 | new spell_the_lich_king_raging_spirit(); | |
| 3201 | new spell_the_lich_king_defile(); | |
| 3202 | new spell_the_lich_king_summon_into_air(); | |
| 3203 | new spell_the_lich_king_soul_reaper(); | |
| 3204 | new spell_the_lich_king_valkyr_target_search(); | |
| 3205 | new spell_the_lich_king_eject_all_passengers(); | |
| 3206 | new spell_the_lich_king_cast_back_to_caster(); | |
| 3207 | new spell_the_lich_king_life_siphon(); | |
| 3208 | new spell_the_lich_king_vile_spirits(); | |
| 3209 | new spell_the_lich_king_vile_spirits_visual(); | |
| 3210 | new spell_the_lich_king_vile_spirit_move_target_search(); | |
| 3211 | new spell_the_lich_king_vile_spirit_damage_target_search(); | |
| 3212 | new spell_the_lich_king_harvest_soul(); | |
| 3213 | new spell_the_lich_king_lights_favor(); | |
| 3214 | new spell_the_lich_king_soul_rip(); | |
| 3215 | new spell_the_lich_king_restore_soul(); | |
| 3216 | new spell_the_lich_king_in_frostmourne_room(); | |
| 3217 | new spell_the_lich_king_summon_spirit_bomb(); | |
| 3218 | new spell_the_lich_king_trigger_vile_spirit(); | |
| 3219 | new spell_the_lich_king_jump(); | |
| 3220 | new spell_the_lich_king_jump_remove_aura(); | |
| 3221 | new spell_trigger_spell_from_caster("spell_the_lich_king_mass_resurrection", SPELL_MASS_RESURRECTION_REAL);
| |
| 3222 | new spell_the_lich_king_play_movie(); | |
| 3223 | new achievement_been_waiting_long_time(); | |
| 3224 | new achievement_neck_deep_in_vile(); | |
| 3225 | } |