diff options
| -rw-r--r-- | src/server/scripts/Northrend/IcecrownCitadel/boss_the_lich_king.cpp | 4534 | 
1 files changed, 2036 insertions, 2498 deletions
diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_the_lich_king.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_the_lich_king.cpp index f94123c9c2d..23661e925b6 100644 --- a/src/server/scripts/Northrend/IcecrownCitadel/boss_the_lich_king.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_the_lich_king.cpp @@ -511,1961 +511,1736 @@ class TriggerWickedSpirit : public BasicEvent          uint32 _counter;  }; -class boss_the_lich_king : public CreatureScript +struct boss_the_lich_king : public BossAI  { -    public: -        boss_the_lich_king() : CreatureScript("boss_the_lich_king") { } - -        struct boss_the_lich_kingAI : public BossAI -        { -            boss_the_lich_kingAI(Creature* creature) : BossAI(creature, DATA_THE_LICH_KING) -            { -                Initialize(); -            } - -            void Initialize() -            { -                _necroticPlagueStack = 0; -                _vileSpiritExplosions = 0; -            } +    boss_the_lich_king(Creature* creature) : BossAI(creature, DATA_THE_LICH_KING) +    { +        Initialize(); +    } + +    void Initialize() +    { +        _necroticPlagueStack = 0; +        _vileSpiritExplosions = 0; +    } + +    void Reset() override +    { +        _Reset(); +        me->SetImmuneToPC(true); +        me->SetReactState(REACT_PASSIVE); +        events.SetPhase(PHASE_INTRO); +        Initialize(); +        SetEquipmentSlots(true); + +        // Reset The Frozen Throne gameobjects +        FrozenThroneResetWorker reset; +        Trinity::GameObjectWorker<FrozenThroneResetWorker> worker(me, reset); +        Cell::VisitGridObjects(me, worker, 333.0f); + +        // Reset any light override +        me->GetMap()->SetZoneOverrideLight(AREA_ICECROWN_CITADEL, LIGHT_DEFAULT, 0, 5000); + +        if (!ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_HIGHLORD_TIRION_FORDRING))) +            me->SummonCreature(NPC_HIGHLORD_TIRION_FORDRING_LK, TirionSpawn, TEMPSUMMON_MANUAL_DESPAWN); +    } + +    void JustDied(Unit* /*killer*/) override +    { +        _JustDied(); +        DoCastAOE(SPELL_PLAY_MOVIE, false); +        me->SetDisableGravity(false); +        me->RemoveByteFlag(UNIT_FIELD_BYTES_1, UNIT_BYTES_1_OFFSET_ANIM_TIER, UNIT_BYTE1_FLAG_ALWAYS_STAND | UNIT_BYTE1_FLAG_HOVER); +        me->GetMotionMaster()->MoveFall(); +        if (Creature* frostmourne = me->FindNearestCreature(NPC_FROSTMOURNE_TRIGGER, 50.0f)) +            frostmourne->DespawnOrUnsummon(); +        me->GetMap()->SetZoneOverrideLight(AREA_ICECROWN_CITADEL, LIGHT_DEFAULT, LIGHT_FOG, 5000); +        me->GetMap()->SetZoneWeather(AREA_ICECROWN_CITADEL, WEATHER_STATE_FOG, 0.0f); + +        if (Is25ManRaid()) +            if (Player* player = me->GetLootRecipient()) +                player->RewardPlayerAndGroupAtEvent(NPC_THE_LICH_KING_QUEST, player); +    } + +    void JustEngagedWith(Unit* target) override +    { +        if (!instance->CheckRequiredBosses(DATA_THE_LICH_KING, target->ToPlayer())) +        { +            EnterEvadeMode(EVADE_REASON_OTHER); +            instance->DoCastSpellOnPlayers(LIGHT_S_HAMMER_TELEPORT); +            return; +        } -            void Reset() override -            { -                _Reset(); -                me->SetImmuneToPC(true); -                me->SetReactState(REACT_PASSIVE); -                events.SetPhase(PHASE_INTRO); -                Initialize(); -                SetEquipmentSlots(true); - -                // Reset The Frozen Throne gameobjects -                FrozenThroneResetWorker reset; -                Trinity::GameObjectWorker<FrozenThroneResetWorker> worker(me, reset); -                Cell::VisitGridObjects(me, worker, 333.0f); - -                // Reset any light override +        me->setActive(true); +        me->SetCombatPulseDelay(5); +        DoZoneInCombat(); + +        events.SetPhase(PHASE_ONE); +        events.ScheduleEvent(EVENT_SUMMON_SHAMBLING_HORROR, 20s, 0, PHASE_ONE); +        events.ScheduleEvent(EVENT_SUMMON_DRUDGE_GHOUL, 10s, 0, PHASE_ONE); +        events.ScheduleEvent(EVENT_INFEST, 5s, 0, PHASE_ONE); +        events.ScheduleEvent(EVENT_NECROTIC_PLAGUE, 30s, 33s, 0, PHASE_ONE); +        events.ScheduleEvent(EVENT_BERSERK, 15min, EVENT_GROUP_BERSERK); +        if (IsHeroic()) +            events.ScheduleEvent(EVENT_SHADOW_TRAP, 15500ms, 0, PHASE_ONE); +    } + +    bool CanAIAttack(Unit const* target) const override +    { +        // The Lich King must not select targets in frostmourne room if he killed everyone outside +        return !target->HasAura(SPELL_IN_FROSTMOURNE_ROOM) && BossAI::CanAIAttack(target); +    } + +    void EnterEvadeMode(EvadeReason /*why*/) override +    { +        if (Creature* tirion = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_HIGHLORD_TIRION_FORDRING))) +            tirion->DespawnOrUnsummon(); +        DoCastAOE(SPELL_KILL_FROSTMOURNE_PLAYERS); +        EntryCheckPredicate pred(NPC_STRANGULATE_VEHICLE); +        summons.DoAction(ACTION_TELEPORT_BACK, pred); +        summons.DespawnAll(); +        _DespawnAtEvade(); +    } + +    void KilledUnit(Unit* victim) override +    { +        if (victim->GetTypeId() == TYPEID_PLAYER && !me->IsInEvadeMode() && !events.IsInPhase(PHASE_OUTRO)) +            Talk(SAY_LK_KILL); +    } + +    void DoAction(int32 action) override +    { +        switch (action) +        { +            case ACTION_START_ENCOUNTER: +                instance->SetBossState(DATA_THE_LICH_KING, IN_PROGRESS); +                Talk(SAY_LK_INTRO_1); +                me->GetMap()->SetZoneMusic(AREA_ICECROWN_CITADEL, MUSIC_FROZEN_THRONE); +                // schedule talks +                me->SetStandState(UNIT_STAND_STATE_STAND); +                events.ScheduleEvent(EVENT_INTRO_MOVE_1, 4s); +                break; +            case ACTION_START_ATTACK: +                events.ScheduleEvent(EVENT_START_ATTACK, 5s); +                break; +            case ACTION_PLAY_MUSIC: +                me->GetMap()->SetZoneMusic(AREA_ICECROWN_CITADEL, MUSIC_FINAL); +                break; +            case ACTION_RESTORE_LIGHT:                  me->GetMap()->SetZoneOverrideLight(AREA_ICECROWN_CITADEL, LIGHT_DEFAULT, 0, 5000); - -                if (!ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_HIGHLORD_TIRION_FORDRING))) -                    me->SummonCreature(NPC_HIGHLORD_TIRION_FORDRING_LK, TirionSpawn, TEMPSUMMON_MANUAL_DESPAWN); -            } - -            void JustDied(Unit* /*killer*/) override -            { -                _JustDied(); -                DoCastAOE(SPELL_PLAY_MOVIE, false); -                me->SetDisableGravity(false); -                me->RemoveByteFlag(UNIT_FIELD_BYTES_1, UNIT_BYTES_1_OFFSET_ANIM_TIER, UNIT_BYTE1_FLAG_ALWAYS_STAND | UNIT_BYTE1_FLAG_HOVER); -                me->GetMotionMaster()->MoveFall(); -                if (Creature* frostmourne = me->FindNearestCreature(NPC_FROSTMOURNE_TRIGGER, 50.0f)) -                    frostmourne->DespawnOrUnsummon(); -                me->GetMap()->SetZoneOverrideLight(AREA_ICECROWN_CITADEL, LIGHT_DEFAULT, LIGHT_FOG, 5000); -                me->GetMap()->SetZoneWeather(AREA_ICECROWN_CITADEL, WEATHER_STATE_FOG, 0.0f); - -                if (Is25ManRaid()) -                    if (Player* player = me->GetLootRecipient()) -                        player->RewardPlayerAndGroupAtEvent(NPC_THE_LICH_KING_QUEST, player); -            } - -            void JustEngagedWith(Unit* target) override -            { -                if (!instance->CheckRequiredBosses(DATA_THE_LICH_KING, target->ToPlayer())) -                { -                    EnterEvadeMode(EVADE_REASON_OTHER); -                    instance->DoCastSpellOnPlayers(LIGHT_S_HAMMER_TELEPORT); -                    return; -                } - -                me->setActive(true); -                me->SetCombatPulseDelay(5); -                DoZoneInCombat(); - -                events.SetPhase(PHASE_ONE); -                events.ScheduleEvent(EVENT_SUMMON_SHAMBLING_HORROR, 20s, 0, PHASE_ONE); -                events.ScheduleEvent(EVENT_SUMMON_DRUDGE_GHOUL, 10s, 0, PHASE_ONE); -                events.ScheduleEvent(EVENT_INFEST, 5s, 0, PHASE_ONE); -                events.ScheduleEvent(EVENT_NECROTIC_PLAGUE, 30s, 33s, 0, PHASE_ONE); -                events.ScheduleEvent(EVENT_BERSERK, 15min, EVENT_GROUP_BERSERK); -                if (IsHeroic()) -                    events.ScheduleEvent(EVENT_SHADOW_TRAP, 15500ms, 0, PHASE_ONE); -            } - -            bool CanAIAttack(Unit const* target) const override -            { -                // The Lich King must not select targets in frostmourne room if he killed everyone outside -                return !target->HasAura(SPELL_IN_FROSTMOURNE_ROOM) && BossAI::CanAIAttack(target); -            } - -            void EnterEvadeMode(EvadeReason /*why*/) override +                break; +            case ACTION_BREAK_FROSTMOURNE: +                me->CastSpell(nullptr, SPELL_SUMMON_BROKEN_FROSTMOURNE, TRIGGERED_IGNORE_CAST_IN_PROGRESS); +                me->CastSpell(nullptr, SPELL_SUMMON_BROKEN_FROSTMOURNE_2, TRIGGERED_IGNORE_CAST_IN_PROGRESS); +                SetEquipmentSlots(false, EQUIP_BROKEN_FROSTMOURNE); +                events.ScheduleEvent(EVENT_OUTRO_TALK_6, 2500ms, 0, PHASE_OUTRO); +                break; +            case ACTION_FINISH_OUTRO: +                events.ScheduleEvent(EVENT_OUTRO_TALK_7, 7s, 0, PHASE_OUTRO); +                events.ScheduleEvent(EVENT_OUTRO_TALK_8, 17s, 0, PHASE_OUTRO); +                break; +            case ACTION_TELEPORT_BACK:              { -                if (Creature* tirion = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_HIGHLORD_TIRION_FORDRING))) -                    tirion->DespawnOrUnsummon(); -                DoCastAOE(SPELL_KILL_FROSTMOURNE_PLAYERS);                  EntryCheckPredicate pred(NPC_STRANGULATE_VEHICLE);                  summons.DoAction(ACTION_TELEPORT_BACK, pred); -                summons.DespawnAll(); -                _DespawnAtEvade(); +                if (!IsHeroic()) +                    Talk(SAY_LK_FROSTMOURNE_ESCAPE); +                break;              } +            default: +                break; +        } +    } + +    uint32 GetData(uint32 type) const override +    { +        switch (type) +        { +            case DATA_PLAGUE_STACK: +                return _necroticPlagueStack; +            case DATA_VILE: +                return _vileSpiritExplosions; +            default: +                break; +        } -            void KilledUnit(Unit* victim) override -            { -                if (victim->GetTypeId() == TYPEID_PLAYER && !me->IsInEvadeMode() && !events.IsInPhase(PHASE_OUTRO)) -                    Talk(SAY_LK_KILL); -            } +        return 0; +    } + +    void SetData(uint32 type, uint32 value) override +    { +        switch (type) +        { +            case DATA_PLAGUE_STACK: +                _necroticPlagueStack = std::max(value, _necroticPlagueStack); +                break; +            case DATA_VILE: +                _vileSpiritExplosions += value; +                break; +            default: +                break; +        } +    } + +    void DamageTaken(Unit* /*attacker*/, uint32& /*damage*/) override +    { +        if (events.IsInPhase(PHASE_ONE) && !HealthAbovePct(70)) +        { +            events.SetPhase(PHASE_TRANSITION); +            me->SetReactState(REACT_PASSIVE); +            me->AttackStop(); +            me->InterruptNonMeleeSpells(true); +            me->GetMotionMaster()->MovePoint(POINT_CENTER_1, CenterPosition); +            return; +        } -            void DoAction(int32 action) override -            { -                switch (action) -                { -                    case ACTION_START_ENCOUNTER: -                        instance->SetBossState(DATA_THE_LICH_KING, IN_PROGRESS); -                        Talk(SAY_LK_INTRO_1); -                        me->GetMap()->SetZoneMusic(AREA_ICECROWN_CITADEL, MUSIC_FROZEN_THRONE); -                        // schedule talks -                        me->SetStandState(UNIT_STAND_STATE_STAND); -                        events.ScheduleEvent(EVENT_INTRO_MOVE_1, 4s); -                        break; -                    case ACTION_START_ATTACK: -                        events.ScheduleEvent(EVENT_START_ATTACK, 5s); -                        break; -                    case ACTION_PLAY_MUSIC: -                        me->GetMap()->SetZoneMusic(AREA_ICECROWN_CITADEL, MUSIC_FINAL); -                        break; -                    case ACTION_RESTORE_LIGHT: -                        me->GetMap()->SetZoneOverrideLight(AREA_ICECROWN_CITADEL, LIGHT_DEFAULT, 0, 5000); -                        break; -                    case ACTION_BREAK_FROSTMOURNE: -                        me->CastSpell(nullptr, SPELL_SUMMON_BROKEN_FROSTMOURNE, TRIGGERED_IGNORE_CAST_IN_PROGRESS); -                        me->CastSpell(nullptr, SPELL_SUMMON_BROKEN_FROSTMOURNE_2, TRIGGERED_IGNORE_CAST_IN_PROGRESS); -                        SetEquipmentSlots(false, EQUIP_BROKEN_FROSTMOURNE); -                        events.ScheduleEvent(EVENT_OUTRO_TALK_6, 2500ms, 0, PHASE_OUTRO); -                        break; -                    case ACTION_FINISH_OUTRO: -                        events.ScheduleEvent(EVENT_OUTRO_TALK_7, 7s, 0, PHASE_OUTRO); -                        events.ScheduleEvent(EVENT_OUTRO_TALK_8, 17s, 0, PHASE_OUTRO); -                        break; -                    case ACTION_TELEPORT_BACK: -                    { -                        EntryCheckPredicate pred(NPC_STRANGULATE_VEHICLE); -                        summons.DoAction(ACTION_TELEPORT_BACK, pred); -                        if (!IsHeroic()) -                            Talk(SAY_LK_FROSTMOURNE_ESCAPE); -                        break; -                    } -                    default: -                        break; -                } -            } +        if (events.IsInPhase(PHASE_TWO) && !HealthAbovePct(40)) +        { +            events.SetPhase(PHASE_TRANSITION); +            me->SetReactState(REACT_PASSIVE); +            me->AttackStop(); +            me->InterruptNonMeleeSpells(true); +            me->GetMotionMaster()->MovePoint(POINT_CENTER_2, CenterPosition); +            return; +        } -            uint32 GetData(uint32 type) const override -            { -                switch (type) +        if (events.IsInPhase(PHASE_THREE) && !HealthAbovePct(10)) +        { +            me->SetReactState(REACT_PASSIVE); +            me->AttackStop(); +            events.Reset(); +            events.SetPhase(PHASE_OUTRO); +            summons.DespawnAll(); +            me->GetMap()->SetZoneMusic(AREA_ICECROWN_CITADEL, MUSIC_FURY_OF_FROSTMOURNE); +            me->InterruptNonMeleeSpells(true); +            me->CastSpell(nullptr, SPELL_FURY_OF_FROSTMOURNE, TRIGGERED_NONE); +            me->SetWalk(true); +            events.ScheduleEvent(EVENT_OUTRO_TALK_1, 2600ms, 0, PHASE_OUTRO); +            events.ScheduleEvent(EVENT_OUTRO_EMOTE_TALK, 6600ms, 0, PHASE_OUTRO); +            events.ScheduleEvent(EVENT_OUTRO_EMOTE_TALK, 17600ms, 0, PHASE_OUTRO); +            events.ScheduleEvent(EVENT_OUTRO_EMOTE_TALK, 27600ms, 0, PHASE_OUTRO); +            events.ScheduleEvent(EVENT_OUTRO_TALK_2, 34600ms, 0, PHASE_OUTRO); +            events.ScheduleEvent(EVENT_OUTRO_TALK_3, 43600ms, 0, PHASE_OUTRO); +            events.ScheduleEvent(EVENT_EMOTE_CAST_SHOUT, 54600ms, 0, PHASE_OUTRO); +            events.ScheduleEvent(EVENT_OUTRO_EMOTE_TALK, 58600ms, 0, PHASE_OUTRO); +            events.ScheduleEvent(EVENT_OUTRO_MOVE_CENTER, 69600ms, 0, PHASE_OUTRO); +            // stop here. rest will get scheduled from MovementInform +            return; +        } +    } + +    void JustSummoned(Creature* summon) override +    { +        switch (summon->GetEntry()) +        { +            case NPC_SHAMBLING_HORROR: +            case NPC_DRUDGE_GHOUL: +                summon->CastSpell(summon, SPELL_RISEN_WITCH_DOCTOR_SPAWN, true); +                summon->SetReactState(REACT_PASSIVE); +                summon->HandleEmoteCommand(EMOTE_ONESHOT_EMERGE); +                summon->m_Events.AddEvent(new LichKingStartMovementEvent(me, summon), summon->m_Events.CalculateTime(5s)); +                break; +            case NPC_SHADOW_TRAP: +                summon->CastSpell(summon, SPELL_SHADOW_TRAP_VISUAL, true); +                break; +            case NPC_ICE_SPHERE: +            { +                if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 0.0f, true))                  { -                    case DATA_PLAGUE_STACK: -                        return _necroticPlagueStack; -                    case DATA_VILE: -                        return _vileSpiritExplosions; -                    default: -                        break; +                    summon->SetReactState(REACT_PASSIVE); +                    summon->CastSpell(summon, SPELL_ICE_SPHERE, false); +                    summon->CastSpell(summon, SPELL_ICE_BURST_TARGET_SEARCH, false); +                    summon->CastSpell(target, SPELL_ICE_PULSE, false); +                    summon->GetMotionMaster()->MoveFollow(target, 0.0f, 0.0f);                  } +                else +                    summon->DespawnOrUnsummon(); +                break; +            } +            case NPC_DEFILE: +                summon->SetReactState(REACT_PASSIVE); +                summon->CastSpell(summon, SPELL_DEFILE_AURA, false); +                break; +            case NPC_FROSTMOURNE_TRIGGER: +            { +                summon->CastSpell(nullptr, SPELL_BROKEN_FROSTMOURNE, true); + +                me->GetMap()->SetZoneOverrideLight(AREA_ICECROWN_CITADEL, LIGHT_DEFAULT, LIGHT_SOULSTORM, 10000); +                me->GetMap()->SetZoneWeather(AREA_ICECROWN_CITADEL, WEATHER_STATE_BLACKSNOW, 0.5f); + +                events.ScheduleEvent(EVENT_OUTRO_SOUL_BARRAGE, 5s, 0, PHASE_OUTRO); +                return; +            } +            case NPC_VILE_SPIRIT: +            { +                summons.Summon(summon); +                summon->SetReactState(REACT_PASSIVE); +                summon->SetSpeedRate(MOVE_FLIGHT, 0.5f); +                summon->GetMotionMaster()->MoveRandom(10.0f); +                if (!events.IsInPhase(PHASE_FROSTMOURNE)) +                    summon->m_Events.AddEvent(new VileSpiritActivateEvent(summon), summon->m_Events.CalculateTime(15s)); +                return; +            } +            case NPC_STRANGULATE_VEHICLE: +                summons.Summon(summon); +                return; +            case NPC_HIGHLORD_TIRION_FORDRING_LK: +                return; +            default: +                break; +        } -                return 0; -            } +        BossAI::JustSummoned(summon); +    } + +    void SummonedCreatureDies(Creature* summon, Unit* /*killer*/) override +    { +        switch (summon->GetEntry()) +        { +            case NPC_SHAMBLING_HORROR: +            case NPC_DRUDGE_GHOUL: +            case NPC_ICE_SPHERE: +            case NPC_VALKYR_SHADOWGUARD: +            case NPC_RAGING_SPIRIT: +            case NPC_VILE_SPIRIT: +                summon->ToTempSummon()->SetTempSummonType(TEMPSUMMON_CORPSE_DESPAWN); +                break; +            default: +                break; +        } +    } -            void SetData(uint32 type, uint32 value) override -            { -                switch (type) -                { -                    case DATA_PLAGUE_STACK: -                        _necroticPlagueStack = std::max(value, _necroticPlagueStack); -                        break; -                    case DATA_VILE: -                        _vileSpiritExplosions += value; -                        break; -                    default: -                        break; -                } -            } +    void SpellHit(WorldObject* /*caster*/, SpellInfo const* spellInfo) override +    { +        if (spellInfo->Id == SPELL_HARVESTED_SOUL && me->IsInCombat() && !IsHeroic()) +            Talk(SAY_LK_FROSTMOURNE_KILL); -            void DamageTaken(Unit* /*attacker*/, uint32& /*damage*/) override -            { -                if (events.IsInPhase(PHASE_ONE) && !HealthAbovePct(70)) -                { -                    events.SetPhase(PHASE_TRANSITION); -                    me->SetReactState(REACT_PASSIVE); -                    me->AttackStop(); -                    me->InterruptNonMeleeSpells(true); -                    me->GetMotionMaster()->MovePoint(POINT_CENTER_1, CenterPosition); -                    return; -                } +        if (spellInfo->Id == REMORSELESS_WINTER_1 || spellInfo->Id == REMORSELESS_WINTER_2) +        { +            me->GetMap()->SetZoneOverrideLight(AREA_ICECROWN_CITADEL, LIGHT_DEFAULT, LIGHT_SNOWSTORM, 5000); +            me->GetMap()->SetZoneWeather(AREA_ICECROWN_CITADEL, WEATHER_STATE_LIGHT_SNOW, 0.5f); +            summons.DespawnEntry(NPC_SHADOW_TRAP); +        } +    } + +    void MovementInform(uint32 type, uint32 pointId) override +    { +        if (type != POINT_MOTION_TYPE) +            return; + +        switch (pointId) +        { +            case POINT_LK_INTRO_1: +                // schedule for next update cycle, current update must finalize movement +                events.ScheduleEvent(EVENT_INTRO_MOVE_2, 1ms, 0, PHASE_INTRO); +                break; +            case POINT_LK_INTRO_2: +                events.ScheduleEvent(EVENT_INTRO_MOVE_3, 1ms, 0, PHASE_INTRO); +                break; +            case POINT_LK_INTRO_3: +                if (Creature* tirion = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_HIGHLORD_TIRION_FORDRING))) +                    tirion->AI()->DoAction(ACTION_CONTINUE_INTRO); +                events.ScheduleEvent(EVENT_INTRO_TALK_1, 9s, 0, PHASE_INTRO); +                break; +            case POINT_CENTER_1: +                me->SetFacingTo(0.0f); +                Talk(SAY_LK_REMORSELESS_WINTER); +                me->GetMap()->SetZoneMusic(AREA_ICECROWN_CITADEL, MUSIC_SPECIAL); +                DoCastSelf(SPELL_REMORSELESS_WINTER_1); +                events.ScheduleEvent(EVENT_QUAKE, 62500ms, 0, PHASE_TRANSITION); +                events.ScheduleEvent(EVENT_PAIN_AND_SUFFERING, 4s, 0, PHASE_TRANSITION); +                events.ScheduleEvent(EVENT_SUMMON_ICE_SPHERE, 8s, 0, PHASE_TRANSITION); +                events.ScheduleEvent(EVENT_SUMMON_RAGING_SPIRIT, 6s, 0, PHASE_TRANSITION); +                events.ScheduleEvent(EVENT_SUMMON_VALKYR, 78s, 0, PHASE_TWO); +                events.ScheduleEvent(EVENT_INFEST, 70s, 0, PHASE_TWO); +                events.ScheduleEvent(EVENT_DEFILE, 97s, 0, PHASE_TWO); +                events.ScheduleEvent(EVENT_SOUL_REAPER, 94s, 0, PHASE_TWO); +                break; +            case POINT_CENTER_2: +                me->SetFacingTo(0.0f); +                Talk(SAY_LK_REMORSELESS_WINTER); +                me->GetMap()->SetZoneMusic(AREA_ICECROWN_CITADEL, MUSIC_SPECIAL); +                DoCastSelf(SPELL_REMORSELESS_WINTER_2); +                summons.DespawnEntry(NPC_VALKYR_SHADOWGUARD); +                events.ScheduleEvent(EVENT_QUAKE_2, 62500ms, 0, PHASE_TRANSITION); +                events.ScheduleEvent(EVENT_PAIN_AND_SUFFERING, 6s, 0, PHASE_TRANSITION); +                events.ScheduleEvent(EVENT_SUMMON_ICE_SPHERE, 8s, 0, PHASE_TRANSITION); +                events.ScheduleEvent(EVENT_SUMMON_RAGING_SPIRIT_2, 5s, 0, PHASE_TRANSITION); +                events.ScheduleEvent(EVENT_DEFILE, 95500ms, 0, PHASE_THREE); +                events.ScheduleEvent(EVENT_SOUL_REAPER, 99500ms, 0, PHASE_THREE); +                events.ScheduleEvent(EVENT_VILE_SPIRITS, 79500ms, EVENT_GROUP_VILE_SPIRITS, PHASE_THREE); +                events.ScheduleEvent(IsHeroic() ? EVENT_HARVEST_SOULS : EVENT_HARVEST_SOUL, 73500ms, 0, PHASE_THREE); +                break; +            case POINT_LK_OUTRO_1: +                events.ScheduleEvent(EVENT_OUTRO_TALK_4, 1ms, 0, PHASE_OUTRO); +                events.ScheduleEvent(EVENT_OUTRO_RAISE_DEAD, 1s, 0, PHASE_OUTRO); +                events.ScheduleEvent(EVENT_OUTRO_TALK_5, 29s, 0, PHASE_OUTRO); +                break; +            case POINT_LK_OUTRO_2: +                if (Creature* tirion = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_HIGHLORD_TIRION_FORDRING))) +                    tirion->AI()->Talk(SAY_TIRION_OUTRO_2); +                if (Creature* frostmourne = me->FindNearestCreature(NPC_FROSTMOURNE_TRIGGER, 50.0f)) +                    frostmourne->AI()->DoAction(ACTION_SUMMON_TERENAS); +                break; +            default: +                break; +        } +    } -                if (events.IsInPhase(PHASE_TWO) && !HealthAbovePct(40)) -                { -                    events.SetPhase(PHASE_TRANSITION); -                    me->SetReactState(REACT_PASSIVE); -                    me->AttackStop(); -                    me->InterruptNonMeleeSpells(true); -                    me->GetMotionMaster()->MovePoint(POINT_CENTER_2, CenterPosition); -                    return; -                } +    void UpdateAI(uint32 diff) override +    { +        // check phase first to prevent updating victim and entering evade mode when not wanted +        if (!(events.IsInPhase(PHASE_OUTRO) || events.IsInPhase(PHASE_INTRO) || events.IsInPhase(PHASE_FROSTMOURNE))) +            if (!UpdateVictim()) +                return; -                if (events.IsInPhase(PHASE_THREE) && !HealthAbovePct(10)) -                { -                    me->SetReactState(REACT_PASSIVE); -                    me->AttackStop(); -                    events.Reset(); -                    events.SetPhase(PHASE_OUTRO); -                    summons.DespawnAll(); -                    me->GetMap()->SetZoneMusic(AREA_ICECROWN_CITADEL, MUSIC_FURY_OF_FROSTMOURNE); -                    me->InterruptNonMeleeSpells(true); -                    me->CastSpell(nullptr, SPELL_FURY_OF_FROSTMOURNE, TRIGGERED_NONE); -                    me->SetWalk(true); -                    events.ScheduleEvent(EVENT_OUTRO_TALK_1, 2600ms, 0, PHASE_OUTRO); -                    events.ScheduleEvent(EVENT_OUTRO_EMOTE_TALK, 6600ms, 0, PHASE_OUTRO); -                    events.ScheduleEvent(EVENT_OUTRO_EMOTE_TALK, 17600ms, 0, PHASE_OUTRO); -                    events.ScheduleEvent(EVENT_OUTRO_EMOTE_TALK, 27600ms, 0, PHASE_OUTRO); -                    events.ScheduleEvent(EVENT_OUTRO_TALK_2, 34600ms, 0, PHASE_OUTRO); -                    events.ScheduleEvent(EVENT_OUTRO_TALK_3, 43600ms, 0, PHASE_OUTRO); -                    events.ScheduleEvent(EVENT_EMOTE_CAST_SHOUT, 54600ms, 0, PHASE_OUTRO); -                    events.ScheduleEvent(EVENT_OUTRO_EMOTE_TALK, 58600ms, 0, PHASE_OUTRO); -                    events.ScheduleEvent(EVENT_OUTRO_MOVE_CENTER, 69600ms, 0, PHASE_OUTRO); -                    // stop here. rest will get scheduled from MovementInform -                    return; -                } -            } +        events.Update(diff); -            void JustSummoned(Creature* summon) override +        // during Remorseless Winter phases The Lich King is channeling a spell, but we must continue casting other spells +        if (me->HasUnitState(UNIT_STATE_CASTING) && !(events.IsInPhase(PHASE_TRANSITION) || events.IsInPhase(PHASE_OUTRO) || events.IsInPhase(PHASE_FROSTMOURNE))) +            return; + +        while (uint32 eventId = events.ExecuteEvent()) +        { +            switch (eventId)              { -                switch (summon->GetEntry()) -                { -                    case NPC_SHAMBLING_HORROR: -                    case NPC_DRUDGE_GHOUL: -                        summon->CastSpell(summon, SPELL_RISEN_WITCH_DOCTOR_SPAWN, true); -                        summon->SetReactState(REACT_PASSIVE); -                        summon->HandleEmoteCommand(EMOTE_ONESHOT_EMERGE); -                        summon->m_Events.AddEvent(new LichKingStartMovementEvent(me, summon), summon->m_Events.CalculateTime(5s)); -                        break; -                    case NPC_SHADOW_TRAP: -                        summon->CastSpell(summon, SPELL_SHADOW_TRAP_VISUAL, true); -                        break; -                    case NPC_ICE_SPHERE: -                    { -                        if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 0.0f, true)) -                        { -                            summon->SetReactState(REACT_PASSIVE); -                            summon->CastSpell(summon, SPELL_ICE_SPHERE, false); -                            summon->CastSpell(summon, SPELL_ICE_BURST_TARGET_SEARCH, false); -                            summon->CastSpell(target, SPELL_ICE_PULSE, false); -                            summon->GetMotionMaster()->MoveFollow(target, 0.0f, 0.0f); -                        } -                        else -                            summon->DespawnOrUnsummon(); -                        break; -                    } -                    case NPC_DEFILE: -                        summon->SetReactState(REACT_PASSIVE); -                        summon->CastSpell(summon, SPELL_DEFILE_AURA, false); -                        break; -                    case NPC_FROSTMOURNE_TRIGGER: +                case EVENT_INTRO_MOVE_1: +                    me->SetSheath(SHEATH_STATE_MELEE); +                    me->RemoveAurasDueToSpell(SPELL_EMOTE_SIT_NO_SHEATH); +                    me->SetWalk(true); +                    me->GetMotionMaster()->MovePoint(POINT_LK_INTRO_1, LichKingIntro[0]); +                    break; +                case EVENT_INTRO_MOVE_2: +                    me->GetMotionMaster()->MovePoint(POINT_LK_INTRO_2, LichKingIntro[1]); +                    break; +                case EVENT_INTRO_MOVE_3: +                    me->GetMotionMaster()->MovePoint(POINT_LK_INTRO_3, LichKingIntro[2]); +                    break; +                case EVENT_INTRO_TALK_1: +                    Talk(SAY_LK_INTRO_2); +                    // for some reason blizz sends 2 emotes in row here so (we handle one in Talk) +                    me->HandleEmoteCommand(EMOTE_ONESHOT_TALK_NO_SHEATHE); +                    events.ScheduleEvent(EVENT_EMOTE_CAST_SHOUT, 7s, 0, PHASE_INTRO); +                    events.ScheduleEvent(EVENT_INTRO_EMOTE_1, 13s, 0, PHASE_INTRO); +                    events.ScheduleEvent(EVENT_EMOTE_CAST_SHOUT, 18s, 0, PHASE_INTRO); +                    events.ScheduleEvent(EVENT_INTRO_CAST_FREEZE, 31s, 0, PHASE_INTRO); +                    break; +                case EVENT_EMOTE_CAST_SHOUT: +                    DoCastSelf(SPELL_EMOTE_SHOUT_NO_SHEATH, false); +                    break; +                case EVENT_INTRO_EMOTE_1: +                    me->HandleEmoteCommand(EMOTE_ONESHOT_POINT_NO_SHEATHE); +                    break; +                case EVENT_INTRO_CAST_FREEZE: +                    Talk(SAY_LK_INTRO_3); +                    DoCastAOE(SPELL_ICE_LOCK, false); +                    events.ScheduleEvent(EVENT_FINISH_INTRO, 1s, 0, PHASE_INTRO); +                    break; +                case EVENT_FINISH_INTRO: +                    me->SetWalk(false); +                    me->SetImmuneToPC(false); +                    me->SetReactState(REACT_AGGRESSIVE); +                    events.SetPhase(PHASE_ONE); +                    DoZoneInCombat(); +                    break; +                case EVENT_SUMMON_SHAMBLING_HORROR: +                    DoCastSelf(SPELL_SUMMON_SHAMBLING_HORROR); +                    me->GetMap()->SetZoneMusic(AREA_ICECROWN_CITADEL, MUSIC_SPECIAL); +                    events.ScheduleEvent(EVENT_SUMMON_SHAMBLING_HORROR, 1min, 0, PHASE_ONE); +                    break; +                case EVENT_SUMMON_DRUDGE_GHOUL: +                    DoCastSelf(SPELL_SUMMON_DRUDGE_GHOULS); +                    events.ScheduleEvent(EVENT_SUMMON_DRUDGE_GHOUL, 30s, 0, PHASE_ONE); +                    break; +                case EVENT_INFEST: +                    DoCastSelf(SPELL_INFEST); +                    events.ScheduleEvent(EVENT_INFEST, 21s, 24s, 0, events.IsInPhase(PHASE_ONE) ? PHASE_ONE : PHASE_TWO); +                    break; +                case EVENT_NECROTIC_PLAGUE: +                    if (Unit* target = SelectTarget(SelectTargetMethod::Random, 1, NecroticPlagueTargetCheck(me, NECROTIC_PLAGUE_LK, NECROTIC_PLAGUE_PLR)))                      { -                        summon->CastSpell(nullptr, SPELL_BROKEN_FROSTMOURNE, true); - -                        me->GetMap()->SetZoneOverrideLight(AREA_ICECROWN_CITADEL, LIGHT_DEFAULT, LIGHT_SOULSTORM, 10000); -                        me->GetMap()->SetZoneWeather(AREA_ICECROWN_CITADEL, WEATHER_STATE_BLACKSNOW, 0.5f); - -                        events.ScheduleEvent(EVENT_OUTRO_SOUL_BARRAGE, 5s, 0, PHASE_OUTRO); -                        return; +                        Talk(EMOTE_NECROTIC_PLAGUE_WARNING, target); +                        DoCast(target, SPELL_NECROTIC_PLAGUE);                      } -                    case NPC_VILE_SPIRIT: +                    events.ScheduleEvent(EVENT_NECROTIC_PLAGUE, 30s, 33s, 0, PHASE_ONE); +                    break; +                case EVENT_SHADOW_TRAP: +                    if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, SpellTargetSelector(me, SPELL_SHADOW_TRAP))) +                        DoCast(target, SPELL_SHADOW_TRAP); +                    events.ScheduleEvent(EVENT_SHADOW_TRAP, 15500ms, 0, PHASE_ONE); +                    break; +                case EVENT_SOUL_REAPER: +                    DoCastVictim(SPELL_SOUL_REAPER); +                    events.ScheduleEvent(EVENT_SOUL_REAPER, 33s, 35s, 0, PHASE_TWO_THREE); +                    break; +                case EVENT_DEFILE: +                    if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 0.0f, true, true, -SPELL_HARVEST_SOUL_VALKYR))                      { -                        summons.Summon(summon); -                        summon->SetReactState(REACT_PASSIVE); -                        summon->SetSpeedRate(MOVE_FLIGHT, 0.5f); -                        summon->GetMotionMaster()->MoveRandom(10.0f); -                        if (!events.IsInPhase(PHASE_FROSTMOURNE)) -                            summon->m_Events.AddEvent(new VileSpiritActivateEvent(summon), summon->m_Events.CalculateTime(15s)); -                        return; +                        Talk(EMOTE_DEFILE_WARNING); +                        DoCast(target, SPELL_DEFILE);                      } -                    case NPC_STRANGULATE_VEHICLE: -                        summons.Summon(summon); -                        return; -                    case NPC_HIGHLORD_TIRION_FORDRING_LK: -                        return; -                    default: -                        break; -                } - -                BossAI::JustSummoned(summon); -            } - -            void SummonedCreatureDies(Creature* summon, Unit* /*killer*/) override -            { -                switch (summon->GetEntry()) -                { -                    case NPC_SHAMBLING_HORROR: -                    case NPC_DRUDGE_GHOUL: -                    case NPC_ICE_SPHERE: -                    case NPC_VALKYR_SHADOWGUARD: -                    case NPC_RAGING_SPIRIT: -                    case NPC_VILE_SPIRIT: -                        summon->ToTempSummon()->SetTempSummonType(TEMPSUMMON_CORPSE_DESPAWN); -                        break; -                    default: -                        break; -                } -            } - -            void SpellHit(WorldObject* /*caster*/, SpellInfo const* spellInfo) override -            { -                if (spellInfo->Id == SPELL_HARVESTED_SOUL && me->IsInCombat() && !IsHeroic()) -                    Talk(SAY_LK_FROSTMOURNE_KILL); - -                if (spellInfo->Id == REMORSELESS_WINTER_1 || spellInfo->Id == REMORSELESS_WINTER_2) -                { -                    me->GetMap()->SetZoneOverrideLight(AREA_ICECROWN_CITADEL, LIGHT_DEFAULT, LIGHT_SNOWSTORM, 5000); -                    me->GetMap()->SetZoneWeather(AREA_ICECROWN_CITADEL, WEATHER_STATE_LIGHT_SNOW, 0.5f); -                    summons.DespawnEntry(NPC_SHADOW_TRAP); -                } -            } - -            void MovementInform(uint32 type, uint32 pointId) override -            { -                if (type != POINT_MOTION_TYPE) -                    return; - -                switch (pointId) -                { -                    case POINT_LK_INTRO_1: -                        // schedule for next update cycle, current update must finalize movement -                        events.ScheduleEvent(EVENT_INTRO_MOVE_2, 1ms, 0, PHASE_INTRO); -                        break; -                    case POINT_LK_INTRO_2: -                        events.ScheduleEvent(EVENT_INTRO_MOVE_3, 1ms, 0, PHASE_INTRO); -                        break; -                    case POINT_LK_INTRO_3: -                        if (Creature* tirion = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_HIGHLORD_TIRION_FORDRING))) -                            tirion->AI()->DoAction(ACTION_CONTINUE_INTRO); -                        events.ScheduleEvent(EVENT_INTRO_TALK_1, 9s, 0, PHASE_INTRO); -                        break; -                    case POINT_CENTER_1: -                        me->SetFacingTo(0.0f); -                        Talk(SAY_LK_REMORSELESS_WINTER); -                        me->GetMap()->SetZoneMusic(AREA_ICECROWN_CITADEL, MUSIC_SPECIAL); -                        DoCast(me, SPELL_REMORSELESS_WINTER_1); -                        events.ScheduleEvent(EVENT_QUAKE, 62500ms, 0, PHASE_TRANSITION); -                        events.ScheduleEvent(EVENT_PAIN_AND_SUFFERING, 4s, 0, PHASE_TRANSITION); -                        events.ScheduleEvent(EVENT_SUMMON_ICE_SPHERE, 8s, 0, PHASE_TRANSITION); -                        events.ScheduleEvent(EVENT_SUMMON_RAGING_SPIRIT, 6s, 0, PHASE_TRANSITION); -                        events.ScheduleEvent(EVENT_SUMMON_VALKYR, 78s, 0, PHASE_TWO); -                        events.ScheduleEvent(EVENT_INFEST, 70s, 0, PHASE_TWO); -                        events.ScheduleEvent(EVENT_DEFILE, 97s, 0, PHASE_TWO); -                        events.ScheduleEvent(EVENT_SOUL_REAPER, 94s, 0, PHASE_TWO); -                        break; -                    case POINT_CENTER_2: -                        me->SetFacingTo(0.0f); -                        Talk(SAY_LK_REMORSELESS_WINTER); -                        me->GetMap()->SetZoneMusic(AREA_ICECROWN_CITADEL, MUSIC_SPECIAL); -                        DoCast(me, SPELL_REMORSELESS_WINTER_2); -                        summons.DespawnEntry(NPC_VALKYR_SHADOWGUARD); -                        events.ScheduleEvent(EVENT_QUAKE_2, 62500ms, 0, PHASE_TRANSITION); -                        events.ScheduleEvent(EVENT_PAIN_AND_SUFFERING, 6s, 0, PHASE_TRANSITION); -                        events.ScheduleEvent(EVENT_SUMMON_ICE_SPHERE, 8s, 0, PHASE_TRANSITION); -                        events.ScheduleEvent(EVENT_SUMMON_RAGING_SPIRIT_2, 5s, 0, PHASE_TRANSITION); -                        events.ScheduleEvent(EVENT_DEFILE, 95500ms, 0, PHASE_THREE); -                        events.ScheduleEvent(EVENT_SOUL_REAPER, 99500ms, 0, PHASE_THREE); -                        events.ScheduleEvent(EVENT_VILE_SPIRITS, 79500ms, EVENT_GROUP_VILE_SPIRITS, PHASE_THREE); -                        events.ScheduleEvent(IsHeroic() ? EVENT_HARVEST_SOULS : EVENT_HARVEST_SOUL, 73500ms, 0, PHASE_THREE); -                        break; -                    case POINT_LK_OUTRO_1: -                        events.ScheduleEvent(EVENT_OUTRO_TALK_4, 1ms, 0, PHASE_OUTRO); -                        events.ScheduleEvent(EVENT_OUTRO_RAISE_DEAD, 1s, 0, PHASE_OUTRO); -                        events.ScheduleEvent(EVENT_OUTRO_TALK_5, 29s, 0, PHASE_OUTRO); -                        break; -                    case POINT_LK_OUTRO_2: -                        if (Creature* tirion = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_HIGHLORD_TIRION_FORDRING))) -                            tirion->AI()->Talk(SAY_TIRION_OUTRO_2); -                        if (Creature* frostmourne = me->FindNearestCreature(NPC_FROSTMOURNE_TRIGGER, 50.0f)) -                            frostmourne->AI()->DoAction(ACTION_SUMMON_TERENAS); -                        break; -                    default: -                        break; -                } -            } - -            void UpdateAI(uint32 diff) override -            { -                // check phase first to prevent updating victim and entering evade mode when not wanted -                if (!(events.IsInPhase(PHASE_OUTRO) || events.IsInPhase(PHASE_INTRO) || events.IsInPhase(PHASE_FROSTMOURNE))) -                    if (!UpdateVictim()) -                        return; - -                events.Update(diff); - -                // during Remorseless Winter phases The Lich King is channeling a spell, but we must continue casting other spells -                if (me->HasUnitState(UNIT_STATE_CASTING) && !(events.IsInPhase(PHASE_TRANSITION) || events.IsInPhase(PHASE_OUTRO) || events.IsInPhase(PHASE_FROSTMOURNE))) -                    return; - -                while (uint32 eventId = events.ExecuteEvent()) -                { -                    switch (eventId) +                    events.ScheduleEvent(EVENT_DEFILE, 32s, 35s, 0, PHASE_TWO_THREE); +                    break; +                case EVENT_HARVEST_SOUL: +                    Talk(SAY_LK_HARVEST_SOUL); +                    if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, SpellTargetSelector(me, SPELL_HARVEST_SOUL))) +                        DoCast(target, SPELL_HARVEST_SOUL); +                    events.ScheduleEvent(EVENT_HARVEST_SOUL, 75s, 0, PHASE_THREE); +                    break; +                case EVENT_PAIN_AND_SUFFERING: +                    if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 0.0f, true)) +                        me->CastSpell(target, SPELL_PAIN_AND_SUFFERING, TRIGGERED_NONE); +                    events.ScheduleEvent(EVENT_PAIN_AND_SUFFERING, 1500ms, 4s, 0, PHASE_TRANSITION); +                    break; +                case EVENT_SUMMON_ICE_SPHERE: +                    DoCastAOE(SPELL_SUMMON_ICE_SPHERE); +                    events.ScheduleEvent(EVENT_SUMMON_ICE_SPHERE, 7500ms, 8500ms, 0, PHASE_TRANSITION); +                    break; +                case EVENT_SUMMON_RAGING_SPIRIT: +                    if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 0.0f, true)) +                        me->CastSpell(target, SPELL_RAGING_SPIRIT, TRIGGERED_NONE); +                    events.ScheduleEvent(EVENT_SUMMON_RAGING_SPIRIT, 22s, 23s, 0, PHASE_TRANSITION); +                    break; +                case EVENT_SUMMON_RAGING_SPIRIT_2: +                    if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 0.0f, true)) +                        me->CastSpell(target, SPELL_RAGING_SPIRIT, TRIGGERED_NONE); +                    events.ScheduleEvent(EVENT_SUMMON_RAGING_SPIRIT, 18s, 0, PHASE_TRANSITION); +                    break; +                case EVENT_QUAKE: +                    events.SetPhase(PHASE_TWO); +                    me->ClearUnitState(UNIT_STATE_CASTING);  // clear state to ensure check in DoCastAOE passes +                    DoCastAOE(SPELL_QUAKE); +                    me->GetMap()->SetZoneMusic(AREA_ICECROWN_CITADEL, MUSIC_SPECIAL); +                    Talk(SAY_LK_QUAKE); +                    break; +                case EVENT_QUAKE_2: +                    events.SetPhase(PHASE_THREE); +                    me->ClearUnitState(UNIT_STATE_CASTING);  // clear state to ensure check in DoCastAOE passes +                    DoCastAOE(SPELL_QUAKE); +                    me->GetMap()->SetZoneMusic(AREA_ICECROWN_CITADEL, MUSIC_SPECIAL); +                    Talk(SAY_LK_QUAKE); +                    break; +                case EVENT_SUMMON_VALKYR: +                    me->GetMap()->SetZoneMusic(AREA_ICECROWN_CITADEL, MUSIC_SPECIAL); +                    Talk(SAY_LK_SUMMON_VALKYR); +                    DoCastAOE(SUMMON_VALKYR, true); +                    events.ScheduleEvent(EVENT_SUMMON_VALKYR, 45s, 50s, 0, PHASE_TWO); +                    break; +                case EVENT_START_ATTACK: +                    me->SetReactState(REACT_AGGRESSIVE); +                    if (events.IsInPhase(PHASE_FROSTMOURNE)) +                        events.SetPhase(PHASE_THREE); +                    break; +                case EVENT_VILE_SPIRITS: +                    me->GetMap()->SetZoneMusic(AREA_ICECROWN_CITADEL, MUSIC_SPECIAL); +                    DoCastAOE(SPELL_VILE_SPIRITS); +                    events.ScheduleEvent(EVENT_VILE_SPIRITS, 35s, 40s, EVENT_GROUP_VILE_SPIRITS, PHASE_THREE); +                    break; +                case EVENT_HARVEST_SOULS: +                    Talk(SAY_LK_HARVEST_SOUL); +                    DoCastAOE(SPELL_HARVEST_SOULS); +                    events.ScheduleEvent(EVENT_HARVEST_SOULS, 100s, 110s, 0, PHASE_THREE); +                    events.SetPhase(PHASE_FROSTMOURNE); // will stop running UpdateVictim (no evading) +                    me->SetReactState(REACT_PASSIVE); +                    me->AttackStop(); +                    events.DelayEvents(50s, EVENT_GROUP_VILE_SPIRITS); +                    events.RescheduleEvent(EVENT_DEFILE, 50s, 0, PHASE_THREE); +                    events.RescheduleEvent(EVENT_SOUL_REAPER, 57s, 62s, 0, PHASE_THREE); +                    events.ScheduleEvent(EVENT_START_ATTACK, 49s); +                    events.ScheduleEvent(EVENT_FROSTMOURNE_HEROIC, 6500ms); +                    for (ObjectGuid guid : summons)                      { -                        case EVENT_INTRO_MOVE_1: -                            me->SetSheath(SHEATH_STATE_MELEE); -                            me->RemoveAurasDueToSpell(SPELL_EMOTE_SIT_NO_SHEATH); -                            me->SetWalk(true); -                            me->GetMotionMaster()->MovePoint(POINT_LK_INTRO_1, LichKingIntro[0]); -                            break; -                        case EVENT_INTRO_MOVE_2: -                            me->GetMotionMaster()->MovePoint(POINT_LK_INTRO_2, LichKingIntro[1]); -                            break; -                        case EVENT_INTRO_MOVE_3: -                            me->GetMotionMaster()->MovePoint(POINT_LK_INTRO_3, LichKingIntro[2]); -                            break; -                        case EVENT_INTRO_TALK_1: -                            Talk(SAY_LK_INTRO_2); -                            // for some reason blizz sends 2 emotes in row here so (we handle one in Talk) -                            me->HandleEmoteCommand(EMOTE_ONESHOT_TALK_NO_SHEATHE); -                            events.ScheduleEvent(EVENT_EMOTE_CAST_SHOUT, 7s, 0, PHASE_INTRO); -                            events.ScheduleEvent(EVENT_INTRO_EMOTE_1, 13s, 0, PHASE_INTRO); -                            events.ScheduleEvent(EVENT_EMOTE_CAST_SHOUT, 18s, 0, PHASE_INTRO); -                            events.ScheduleEvent(EVENT_INTRO_CAST_FREEZE, 31s, 0, PHASE_INTRO); -                            break; -                        case EVENT_EMOTE_CAST_SHOUT: -                            DoCast(me, SPELL_EMOTE_SHOUT_NO_SHEATH, false); -                            break; -                        case EVENT_INTRO_EMOTE_1: -                            me->HandleEmoteCommand(EMOTE_ONESHOT_POINT_NO_SHEATHE); -                            break; -                        case EVENT_INTRO_CAST_FREEZE: -                            Talk(SAY_LK_INTRO_3); -                            DoCastAOE(SPELL_ICE_LOCK, false); -                            events.ScheduleEvent(EVENT_FINISH_INTRO, 1s, 0, PHASE_INTRO); -                            break; -                        case EVENT_FINISH_INTRO: -                            me->SetWalk(false); -                            me->SetImmuneToPC(false); -                            me->SetReactState(REACT_AGGRESSIVE); -                            events.SetPhase(PHASE_ONE); -                            DoZoneInCombat(); -                            break; -                        case EVENT_SUMMON_SHAMBLING_HORROR: -                            DoCast(me, SPELL_SUMMON_SHAMBLING_HORROR); -                            me->GetMap()->SetZoneMusic(AREA_ICECROWN_CITADEL, MUSIC_SPECIAL); -                            events.ScheduleEvent(EVENT_SUMMON_SHAMBLING_HORROR, 1min, 0, PHASE_ONE); -                            break; -                        case EVENT_SUMMON_DRUDGE_GHOUL: -                            DoCast(me, SPELL_SUMMON_DRUDGE_GHOULS); -                            events.ScheduleEvent(EVENT_SUMMON_DRUDGE_GHOUL, 30s, 0, PHASE_ONE); -                            break; -                        case EVENT_INFEST: -                            DoCast(me, SPELL_INFEST); -                            events.ScheduleEvent(EVENT_INFEST, 21s, 24s, 0, events.IsInPhase(PHASE_ONE) ? PHASE_ONE : PHASE_TWO); -                            break; -                        case EVENT_NECROTIC_PLAGUE: -                            if (Unit* target = SelectTarget(SelectTargetMethod::Random, 1, NecroticPlagueTargetCheck(me, NECROTIC_PLAGUE_LK, NECROTIC_PLAGUE_PLR))) -                            { -                                Talk(EMOTE_NECROTIC_PLAGUE_WARNING, target); -                                DoCast(target, SPELL_NECROTIC_PLAGUE); -                            } -                            events.ScheduleEvent(EVENT_NECROTIC_PLAGUE, 30s, 33s, 0, PHASE_ONE); -                            break; -                        case EVENT_SHADOW_TRAP: -                            if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, SpellTargetSelector(me, SPELL_SHADOW_TRAP))) -                                DoCast(target, SPELL_SHADOW_TRAP); -                            events.ScheduleEvent(EVENT_SHADOW_TRAP, 15500ms, 0, PHASE_ONE); -                            break; -                        case EVENT_SOUL_REAPER: -                            DoCastVictim(SPELL_SOUL_REAPER); -                            events.ScheduleEvent(EVENT_SOUL_REAPER, 33s, 35s, 0, PHASE_TWO_THREE); -                            break; -                        case EVENT_DEFILE: -                            if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 0.0f, true, true, -SPELL_HARVEST_SOUL_VALKYR)) -                            { -                                Talk(EMOTE_DEFILE_WARNING); -                                DoCast(target, SPELL_DEFILE); -                            } -                            events.ScheduleEvent(EVENT_DEFILE, 32s, 35s, 0, PHASE_TWO_THREE); -                            break; -                        case EVENT_HARVEST_SOUL: -                            Talk(SAY_LK_HARVEST_SOUL); -                            if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, SpellTargetSelector(me, SPELL_HARVEST_SOUL))) -                                DoCast(target, SPELL_HARVEST_SOUL); -                            events.ScheduleEvent(EVENT_HARVEST_SOUL, 75s, 0, PHASE_THREE); -                            break; -                        case EVENT_PAIN_AND_SUFFERING: -                            if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 0.0f, true)) -                                me->CastSpell(target, SPELL_PAIN_AND_SUFFERING, TRIGGERED_NONE); -                            events.ScheduleEvent(EVENT_PAIN_AND_SUFFERING, 1500ms, 4s, 0, PHASE_TRANSITION); -                            break; -                        case EVENT_SUMMON_ICE_SPHERE: -                            DoCastAOE(SPELL_SUMMON_ICE_SPHERE); -                            events.ScheduleEvent(EVENT_SUMMON_ICE_SPHERE, 7500ms, 8500ms, 0, PHASE_TRANSITION); -                            break; -                        case EVENT_SUMMON_RAGING_SPIRIT: -                            if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 0.0f, true)) -                                me->CastSpell(target, SPELL_RAGING_SPIRIT, TRIGGERED_NONE); -                            events.ScheduleEvent(EVENT_SUMMON_RAGING_SPIRIT, 22s, 23s, 0, PHASE_TRANSITION); -                            break; -                        case EVENT_SUMMON_RAGING_SPIRIT_2: -                            if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 0.0f, true)) -                                me->CastSpell(target, SPELL_RAGING_SPIRIT, TRIGGERED_NONE); -                            events.ScheduleEvent(EVENT_SUMMON_RAGING_SPIRIT, 18s, 0, PHASE_TRANSITION); -                            break; -                        case EVENT_QUAKE: -                            events.SetPhase(PHASE_TWO); -                            me->ClearUnitState(UNIT_STATE_CASTING);  // clear state to ensure check in DoCastAOE passes -                            DoCastAOE(SPELL_QUAKE); -                            me->GetMap()->SetZoneMusic(AREA_ICECROWN_CITADEL, MUSIC_SPECIAL); -                            Talk(SAY_LK_QUAKE); -                            break; -                        case EVENT_QUAKE_2: -                            events.SetPhase(PHASE_THREE); -                            me->ClearUnitState(UNIT_STATE_CASTING);  // clear state to ensure check in DoCastAOE passes -                            DoCastAOE(SPELL_QUAKE); -                            me->GetMap()->SetZoneMusic(AREA_ICECROWN_CITADEL, MUSIC_SPECIAL); -                            Talk(SAY_LK_QUAKE); -                            break; -                        case EVENT_SUMMON_VALKYR: -                            me->GetMap()->SetZoneMusic(AREA_ICECROWN_CITADEL, MUSIC_SPECIAL); -                            Talk(SAY_LK_SUMMON_VALKYR); -                            DoCastAOE(SUMMON_VALKYR, true); -                            events.ScheduleEvent(EVENT_SUMMON_VALKYR, 45s, 50s, 0, PHASE_TWO); -                            break; -                        case EVENT_START_ATTACK: -                            me->SetReactState(REACT_AGGRESSIVE); -                            if (events.IsInPhase(PHASE_FROSTMOURNE)) -                                events.SetPhase(PHASE_THREE); -                            break; -                        case EVENT_VILE_SPIRITS: -                            me->GetMap()->SetZoneMusic(AREA_ICECROWN_CITADEL, MUSIC_SPECIAL); -                            DoCastAOE(SPELL_VILE_SPIRITS); -                            events.ScheduleEvent(EVENT_VILE_SPIRITS, 35s, 40s, EVENT_GROUP_VILE_SPIRITS, PHASE_THREE); -                            break; -                        case EVENT_HARVEST_SOULS: -                            Talk(SAY_LK_HARVEST_SOUL); -                            DoCastAOE(SPELL_HARVEST_SOULS); -                            events.ScheduleEvent(EVENT_HARVEST_SOULS, 100s, 110s, 0, PHASE_THREE); -                            events.SetPhase(PHASE_FROSTMOURNE); // will stop running UpdateVictim (no evading) -                            me->SetReactState(REACT_PASSIVE); -                            me->AttackStop(); -                            events.DelayEvents(50s, EVENT_GROUP_VILE_SPIRITS); -                            events.RescheduleEvent(EVENT_DEFILE, 50s, 0, PHASE_THREE); -                            events.RescheduleEvent(EVENT_SOUL_REAPER, 57s, 62s, 0, PHASE_THREE); -                            events.ScheduleEvent(EVENT_START_ATTACK, 49s); -                            events.ScheduleEvent(EVENT_FROSTMOURNE_HEROIC, 6500ms); -                            for (ObjectGuid guid : summons) -                            { -                                if (Creature* summon = ObjectAccessor::GetCreature(*me, guid)) -                                { -                                    if (summon->GetEntry() == NPC_VILE_SPIRIT) -                                    { -                                        summon->m_Events.KillAllEvents(true); -                                        summon->m_Events.AddEvent(new VileSpiritActivateEvent(summon), summon->m_Events.CalculateTime(56500ms)); -                                        summon->SetReactState(REACT_PASSIVE); -                                        summon->CombatStop(true); -                                        summon->RemoveAurasDueToSpell(SPELL_VILE_SPIRIT_MOVE_SEARCH); -                                        summon->RemoveAurasDueToSpell(SPELL_VILE_SPIRIT_DAMAGE_SEARCH); -                                        summon->GetMotionMaster()->MoveTargetedHome(); -                                    } -                                    else if (summon->GetEntry() == NPC_RAGING_SPIRIT) -                                        summon->AI()->DoAction(ACTION_DISABLE_RAGING); -                                } -                            } -                            break; -                        case EVENT_FROSTMOURNE_HEROIC: -                            if (TempSummon* terenas = me->GetMap()->SummonCreature(NPC_TERENAS_MENETHIL_FROSTMOURNE_H, TerenasSpawnHeroic, nullptr, 50000)) +                        if (Creature* summon = ObjectAccessor::GetCreature(*me, guid)) +                        { +                            if (summon->GetEntry() == NPC_VILE_SPIRIT)                              { -                                terenas->AI()->DoAction(ACTION_FROSTMOURNE_INTRO); -                                std::list<Creature*> triggers; -                                GetCreatureListWithEntryInGrid(triggers, terenas, NPC_WORLD_TRIGGER_INFINITE_AOI, 100.0f); -                                if (!triggers.empty()) -                                { -                                    triggers.sort(Trinity::ObjectDistanceOrderPred(terenas, true)); -                                    Creature* spawner = triggers.front(); -                                    spawner->setActive(true); -                                    spawner->SetFarVisible(true); -                                    spawner->CastSpell(spawner, SPELL_SUMMON_SPIRIT_BOMB_1, true);  // summons bombs randomly -                                    spawner->CastSpell(spawner, SPELL_SUMMON_SPIRIT_BOMB_2, true);  // summons bombs on players -                                    spawner->m_Events.AddEvent(new TriggerWickedSpirit(spawner), spawner->m_Events.CalculateTime(3s)); -                                } +                                summon->m_Events.KillAllEvents(true); +                                summon->m_Events.AddEvent(new VileSpiritActivateEvent(summon), summon->m_Events.CalculateTime(56500ms)); +                                summon->SetReactState(REACT_PASSIVE); +                                summon->CombatStop(true); +                                summon->RemoveAurasDueToSpell(SPELL_VILE_SPIRIT_MOVE_SEARCH); +                                summon->RemoveAurasDueToSpell(SPELL_VILE_SPIRIT_DAMAGE_SEARCH); +                                summon->GetMotionMaster()->MoveTargetedHome();                              } -                            break; -                        case EVENT_OUTRO_TALK_1: -                            Talk(SAY_LK_OUTRO_1); -                            DoCastAOE(SPELL_FURY_OF_FROSTMOURNE_NO_REZ, true); -                            break; -                        case EVENT_OUTRO_TALK_2: -                            Talk(SAY_LK_OUTRO_2); -                            DoCastAOE(SPELL_EMOTE_QUESTION_NO_SHEATH); -                            break; -                        case EVENT_OUTRO_EMOTE_TALK: -                            me->HandleEmoteCommand(EMOTE_ONESHOT_TALK_NO_SHEATHE); -                            break; -                        case EVENT_OUTRO_TALK_3: -                            if (Creature* tirion = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_HIGHLORD_TIRION_FORDRING))) -                                me->SetFacingToObject(tirion); -                            Talk(SAY_LK_OUTRO_3); -                            break; -                        case EVENT_OUTRO_MOVE_CENTER: -                            me->GetMotionMaster()->MovePoint(POINT_LK_OUTRO_1, CenterPosition); -                            break; -                        case EVENT_OUTRO_TALK_4: -                            me->SetFacingTo(0.01745329f); -                            Talk(SAY_LK_OUTRO_4); -                            break; -                        case EVENT_OUTRO_RAISE_DEAD: -                            DoCastAOE(SPELL_RAISE_DEAD); -                            me->ClearUnitState(UNIT_STATE_CASTING); -                            me->GetMap()->SetZoneMusic(AREA_ICECROWN_CITADEL, MUSIC_FINAL); -                            break; -                        case EVENT_OUTRO_TALK_5: -                            Talk(SAY_LK_OUTRO_5); -                            if (Creature* tirion = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_HIGHLORD_TIRION_FORDRING))) -                                tirion->AI()->DoAction(ACTION_OUTRO); -                            break; -                        case EVENT_OUTRO_TALK_6: -                            Talk(SAY_LK_OUTRO_6); -                            if (Creature* tirion = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_HIGHLORD_TIRION_FORDRING))) -                                tirion->SetFacingToObject(me); -                            me->CastSpell(nullptr, SPELL_SUMMON_BROKEN_FROSTMOURNE_3, TRIGGERED_IGNORE_CAST_IN_PROGRESS); -                            SetEquipmentSlots(false, EQUIP_UNEQUIP); -                            break; -                        case EVENT_OUTRO_SOUL_BARRAGE: -                            me->CastSpell(nullptr, SPELL_SOUL_BARRAGE, TRIGGERED_IGNORE_CAST_IN_PROGRESS); -                            sCreatureTextMgr->SendSound(me, SOUND_PAIN, CHAT_MSG_MONSTER_YELL, 0, TEXT_RANGE_NORMAL, TEAM_OTHER, false); -                            // set flight -                            me->SetDisableGravity(true); -                            me->SetByteFlag(UNIT_FIELD_BYTES_1, UNIT_BYTES_1_OFFSET_ANIM_TIER, UNIT_BYTE1_FLAG_ALWAYS_STAND | UNIT_BYTE1_FLAG_HOVER); -                            me->GetMotionMaster()->MovePoint(POINT_LK_OUTRO_2, OutroFlying); -                            break; -                        case EVENT_OUTRO_TALK_7: -                            Talk(SAY_LK_OUTRO_7); -                            break; -                        case EVENT_OUTRO_TALK_8: -                            Talk(SAY_LK_OUTRO_8); -                            break; -                        case EVENT_BERSERK: -                            Talk(SAY_LK_BERSERK); -                            DoCast(me, SPELL_BERSERK2); -                            break; -                        default: -                            break; +                            else if (summon->GetEntry() == NPC_RAGING_SPIRIT) +                                summon->AI()->DoAction(ACTION_DISABLE_RAGING); +                        }                      } - -                    if (me->HasUnitState(UNIT_STATE_CASTING) && !(events.IsInPhase(PHASE_TRANSITION) || events.IsInPhase(PHASE_OUTRO) || events.IsInPhase(PHASE_FROSTMOURNE))) -                        return; -                } - -                DoMeleeAttackIfReady(); +                    break; +                case EVENT_FROSTMOURNE_HEROIC: +                    if (TempSummon* terenas = me->GetMap()->SummonCreature(NPC_TERENAS_MENETHIL_FROSTMOURNE_H, TerenasSpawnHeroic, nullptr, 50000)) +                    { +                        terenas->AI()->DoAction(ACTION_FROSTMOURNE_INTRO); +                        std::list<Creature*> triggers; +                        GetCreatureListWithEntryInGrid(triggers, terenas, NPC_WORLD_TRIGGER_INFINITE_AOI, 100.0f); +                        if (!triggers.empty()) +                        { +                            triggers.sort(Trinity::ObjectDistanceOrderPred(terenas, true)); +                            Creature* spawner = triggers.front(); +                            spawner->setActive(true); +                            spawner->SetFarVisible(true); +                            spawner->CastSpell(spawner, SPELL_SUMMON_SPIRIT_BOMB_1, true);  // summons bombs randomly +                            spawner->CastSpell(spawner, SPELL_SUMMON_SPIRIT_BOMB_2, true);  // summons bombs on players +                            spawner->m_Events.AddEvent(new TriggerWickedSpirit(spawner), spawner->m_Events.CalculateTime(3s)); +                        } +                    } +                    break; +                case EVENT_OUTRO_TALK_1: +                    Talk(SAY_LK_OUTRO_1); +                    DoCastAOE(SPELL_FURY_OF_FROSTMOURNE_NO_REZ, true); +                    break; +                case EVENT_OUTRO_TALK_2: +                    Talk(SAY_LK_OUTRO_2); +                    DoCastAOE(SPELL_EMOTE_QUESTION_NO_SHEATH); +                    break; +                case EVENT_OUTRO_EMOTE_TALK: +                    me->HandleEmoteCommand(EMOTE_ONESHOT_TALK_NO_SHEATHE); +                    break; +                case EVENT_OUTRO_TALK_3: +                    if (Creature* tirion = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_HIGHLORD_TIRION_FORDRING))) +                        me->SetFacingToObject(tirion); +                    Talk(SAY_LK_OUTRO_3); +                    break; +                case EVENT_OUTRO_MOVE_CENTER: +                    me->GetMotionMaster()->MovePoint(POINT_LK_OUTRO_1, CenterPosition); +                    break; +                case EVENT_OUTRO_TALK_4: +                    me->SetFacingTo(0.01745329f); +                    Talk(SAY_LK_OUTRO_4); +                    break; +                case EVENT_OUTRO_RAISE_DEAD: +                    DoCastAOE(SPELL_RAISE_DEAD); +                    me->ClearUnitState(UNIT_STATE_CASTING); +                    me->GetMap()->SetZoneMusic(AREA_ICECROWN_CITADEL, MUSIC_FINAL); +                    break; +                case EVENT_OUTRO_TALK_5: +                    Talk(SAY_LK_OUTRO_5); +                    if (Creature* tirion = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_HIGHLORD_TIRION_FORDRING))) +                        tirion->AI()->DoAction(ACTION_OUTRO); +                    break; +                case EVENT_OUTRO_TALK_6: +                    Talk(SAY_LK_OUTRO_6); +                    if (Creature* tirion = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_HIGHLORD_TIRION_FORDRING))) +                        tirion->SetFacingToObject(me); +                    me->CastSpell(nullptr, SPELL_SUMMON_BROKEN_FROSTMOURNE_3, TRIGGERED_IGNORE_CAST_IN_PROGRESS); +                    SetEquipmentSlots(false, EQUIP_UNEQUIP); +                    break; +                case EVENT_OUTRO_SOUL_BARRAGE: +                    me->CastSpell(nullptr, SPELL_SOUL_BARRAGE, TRIGGERED_IGNORE_CAST_IN_PROGRESS); +                    sCreatureTextMgr->SendSound(me, SOUND_PAIN, CHAT_MSG_MONSTER_YELL, 0, TEXT_RANGE_NORMAL, TEAM_OTHER, false); +                    // set flight +                    me->SetDisableGravity(true); +                    me->SetByteFlag(UNIT_FIELD_BYTES_1, UNIT_BYTES_1_OFFSET_ANIM_TIER, UNIT_BYTE1_FLAG_ALWAYS_STAND | UNIT_BYTE1_FLAG_HOVER); +                    me->GetMotionMaster()->MovePoint(POINT_LK_OUTRO_2, OutroFlying); +                    break; +                case EVENT_OUTRO_TALK_7: +                    Talk(SAY_LK_OUTRO_7); +                    break; +                case EVENT_OUTRO_TALK_8: +                    Talk(SAY_LK_OUTRO_8); +                    break; +                case EVENT_BERSERK: +                    Talk(SAY_LK_BERSERK); +                    DoCastSelf(SPELL_BERSERK2); +                    break; +                default: +                    break;              } -        private: -            uint32 _necroticPlagueStack; -            uint32 _vileSpiritExplosions; -        }; - -        CreatureAI* GetAI(Creature* creature) const override -        { -            return GetIcecrownCitadelAI<boss_the_lich_kingAI>(creature); +            if (me->HasUnitState(UNIT_STATE_CASTING) && !(events.IsInPhase(PHASE_TRANSITION) || events.IsInPhase(PHASE_OUTRO) || events.IsInPhase(PHASE_FROSTMOURNE))) +                return;          } + +        DoMeleeAttackIfReady(); +    } + +private: +    uint32 _necroticPlagueStack; +    uint32 _vileSpiritExplosions;  }; -class npc_tirion_fordring_tft : public CreatureScript +struct npc_tirion_fordring_tft : public ScriptedAI  { -    public: -        npc_tirion_fordring_tft() : CreatureScript("npc_tirion_fordring_tft") { } +    npc_tirion_fordring_tft(Creature* creature) : ScriptedAI(creature), _instance(creature->GetInstanceScript()) { } + +    void Reset() override +    { +        _events.Reset(); +        if (_instance->GetBossState(DATA_THE_LICH_KING) == DONE) +            me->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); +    } + +    void MovementInform(uint32 type, uint32 id) override +    { +        if (type != POINT_MOTION_TYPE) +            return; + +        switch (id) +        { +            case POINT_TIRION_INTRO: +                me->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_STATE_READY2H); +                if (Creature* theLichKing = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_THE_LICH_KING))) +                    theLichKing->AI()->DoAction(ACTION_START_ENCOUNTER); +                break; +            case POINT_TIRION_OUTRO_1: +                _events.ScheduleEvent(EVENT_OUTRO_JUMP, 1ms, 0, PHASE_OUTRO); +                break; +        } +    } -        struct npc_tirion_fordringAI : public ScriptedAI +    void DoAction(int32 action) override +    { +        switch (action)          { -            npc_tirion_fordringAI(Creature* creature) : ScriptedAI(creature), -                _instance(creature->GetInstanceScript()) -            { -            } - -            void Reset() override -            { -                _events.Reset(); -                if (_instance->GetBossState(DATA_THE_LICH_KING) == DONE) -                    me->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); -            } +            case ACTION_CONTINUE_INTRO: +                Talk(SAY_TIRION_INTRO_1); +                _events.ScheduleEvent(EVENT_INTRO_TALK_1, 34s, 0, PHASE_INTRO); +                break; +            case ACTION_OUTRO: +                _events.SetPhase(PHASE_OUTRO); +                _events.ScheduleEvent(EVENT_OUTRO_TALK_1, 7s, 0, PHASE_OUTRO); +                _events.ScheduleEvent(EVENT_OUTRO_BLESS, 18s, 0, PHASE_OUTRO); +                _events.ScheduleEvent(EVENT_OUTRO_REMOVE_ICE, 23s, 0, PHASE_OUTRO); +                _events.ScheduleEvent(EVENT_OUTRO_MOVE_1, 25s, 0, PHASE_OUTRO); +                break; +        } +    } + +    void SpellHit(WorldObject* /*caster*/, SpellInfo const* spellInfo) override +    { +        if (spellInfo->Id == SPELL_ICE_LOCK) +            me->SetFacingTo(3.085098f); +        else if (spellInfo->Id == SPELL_BROKEN_FROSTMOURNE_KNOCK) +            me->LoadEquipment(1); // remove glow on ashbringer +    } + +    bool GossipSelect(Player* /*player*/, uint32 menuId, uint32 gossipListId) override +    { +        if (me->GetCreatureTemplate()->GossipMenuId == menuId && !gossipListId) +        { +            _events.SetPhase(PHASE_INTRO); +            me->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); +            me->SetWalk(true); +            me->GetMotionMaster()->MovePoint(POINT_TIRION_INTRO, TirionIntro); +        } +        return false; +    } -            void MovementInform(uint32 type, uint32 id) override -            { -                if (type != POINT_MOTION_TYPE) -                    return; +    void JustReachedHome() override +    { +        me->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_ONESHOT_NONE); +    } -                switch (id) -                { -                    case POINT_TIRION_INTRO: -                        me->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_STATE_READY2H); -                        if (Creature* theLichKing = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_THE_LICH_KING))) -                            theLichKing->AI()->DoAction(ACTION_START_ENCOUNTER); -                        break; -                    case POINT_TIRION_OUTRO_1: -                        _events.ScheduleEvent(EVENT_OUTRO_JUMP, 1ms, 0, PHASE_OUTRO); -                        break; -                } -            } +    void UpdateAI(uint32 diff) override +    { +        if (!UpdateVictim() && !(_events.IsInPhase(PHASE_OUTRO) || _events.IsInPhase(PHASE_INTRO))) +            return; -            void DoAction(int32 action) override -            { -                switch (action) -                { -                    case ACTION_CONTINUE_INTRO: -                        Talk(SAY_TIRION_INTRO_1); -                        _events.ScheduleEvent(EVENT_INTRO_TALK_1, 34s, 0, PHASE_INTRO); -                        break; -                    case ACTION_OUTRO: -                        _events.SetPhase(PHASE_OUTRO); -                        _events.ScheduleEvent(EVENT_OUTRO_TALK_1, 7s, 0, PHASE_OUTRO); -                        _events.ScheduleEvent(EVENT_OUTRO_BLESS, 18s, 0, PHASE_OUTRO); -                        _events.ScheduleEvent(EVENT_OUTRO_REMOVE_ICE, 23s, 0, PHASE_OUTRO); -                        _events.ScheduleEvent(EVENT_OUTRO_MOVE_1, 25s, 0, PHASE_OUTRO); -                        break; -                } -            } +        _events.Update(diff); -            void SpellHit(WorldObject* /*caster*/, SpellInfo const* spellInfo) override -            { -                if (spellInfo->Id == SPELL_ICE_LOCK) -                    me->SetFacingTo(3.085098f); -                else if (spellInfo->Id == SPELL_BROKEN_FROSTMOURNE_KNOCK) -                    me->LoadEquipment(1); // remove glow on ashbringer -            } +        if (me->HasUnitState(UNIT_STATE_CASTING)) +            return; -            bool GossipSelect(Player* /*player*/, uint32 menuId, uint32 gossipListId) override -            { -                if (me->GetCreatureTemplate()->GossipMenuId == menuId && !gossipListId) -                { -                    _events.SetPhase(PHASE_INTRO); -                    me->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); -                    me->SetWalk(true); -                    me->GetMotionMaster()->MovePoint(POINT_TIRION_INTRO, TirionIntro); -                } -                return false; -            } - -            void JustReachedHome() override -            { -                me->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_ONESHOT_NONE); -            } - -            void UpdateAI(uint32 diff) override +        while (uint32 eventId = _events.ExecuteEvent()) +        { +            switch (eventId)              { -                if (!UpdateVictim() && !(_events.IsInPhase(PHASE_OUTRO) || _events.IsInPhase(PHASE_INTRO))) -                    return; - -                _events.Update(diff); - -                if (me->HasUnitState(UNIT_STATE_CASTING)) -                    return; - -                while (uint32 eventId = _events.ExecuteEvent()) -                { -                    switch (eventId) +                case EVENT_INTRO_TALK_1: +                    Talk(SAY_TIRION_INTRO_2); +                    _events.ScheduleEvent(EVENT_INTRO_EMOTE_1, 2s, 0, PHASE_INTRO); +                    _events.ScheduleEvent(EVENT_INTRO_CHARGE, 5s, 0, PHASE_INTRO); +                    break; +                case EVENT_INTRO_EMOTE_1: +                    me->HandleEmoteCommand(EMOTE_ONESHOT_POINT_NO_SHEATHE); +                    break; +                case EVENT_INTRO_CHARGE: +                    me->SetWalk(false); +                    me->GetMotionMaster()->MovePoint(POINT_TIRION_CHARGE, TirionCharge); +                    break; +                case EVENT_OUTRO_TALK_1: +                    Talk(SAY_TIRION_OUTRO_1); +                    break; +                case EVENT_OUTRO_BLESS: +                    DoCastSelf(SPELL_LIGHTS_BLESSING); +                    break; +                case EVENT_OUTRO_REMOVE_ICE: +                    me->RemoveAurasDueToSpell(SPELL_ICE_LOCK); +                    SetEquipmentSlots(false, EQUIP_ASHBRINGER_GLOWING); +                    if (Creature* lichKing = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_THE_LICH_KING)))                      { -                        case EVENT_INTRO_TALK_1: -                            Talk(SAY_TIRION_INTRO_2); -                            _events.ScheduleEvent(EVENT_INTRO_EMOTE_1, 2s, 0, PHASE_INTRO); -                            _events.ScheduleEvent(EVENT_INTRO_CHARGE, 5s, 0, PHASE_INTRO); -                            break; -                        case EVENT_INTRO_EMOTE_1: -                            me->HandleEmoteCommand(EMOTE_ONESHOT_POINT_NO_SHEATHE); -                            break; -                        case EVENT_INTRO_CHARGE: -                            me->SetWalk(false); -                            me->GetMotionMaster()->MovePoint(POINT_TIRION_CHARGE, TirionCharge); -                            break; -                        case EVENT_OUTRO_TALK_1: -                            Talk(SAY_TIRION_OUTRO_1); -                            break; -                        case EVENT_OUTRO_BLESS: -                            DoCast(me, SPELL_LIGHTS_BLESSING); -                            break; -                        case EVENT_OUTRO_REMOVE_ICE: -                            me->RemoveAurasDueToSpell(SPELL_ICE_LOCK); -                            SetEquipmentSlots(false, EQUIP_ASHBRINGER_GLOWING); -                            if (Creature* lichKing = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_THE_LICH_KING))) -                            { -                                me->SetFacingToObject(lichKing); -                                lichKing->AI()->DoAction(ACTION_PLAY_MUSIC); -                            } -                            break; -                        case EVENT_OUTRO_MOVE_1: -                            me->GetMotionMaster()->MovePoint(POINT_TIRION_OUTRO_1, OutroPosition1); -                            break; -                        case EVENT_OUTRO_JUMP: -                            DoCastAOE(SPELL_JUMP); -                            break; -                        default: -                            break; +                        me->SetFacingToObject(lichKing); +                        lichKing->AI()->DoAction(ACTION_PLAY_MUSIC);                      } -                } - -                DoMeleeAttackIfReady(); +                    break; +                case EVENT_OUTRO_MOVE_1: +                    me->GetMotionMaster()->MovePoint(POINT_TIRION_OUTRO_1, OutroPosition1); +                    break; +                case EVENT_OUTRO_JUMP: +                    DoCastAOE(SPELL_JUMP); +                    break; +                default: +                    break;              } +        } -        private: -            EventMap _events; -            InstanceScript* _instance; -        }; +        DoMeleeAttackIfReady(); +    } -        CreatureAI* GetAI(Creature* creature) const override -        { -            return GetIcecrownCitadelAI<npc_tirion_fordringAI>(creature); -        } +private: +    EventMap _events; +    InstanceScript* _instance;  }; -class npc_shambling_horror_icc : public CreatureScript +struct npc_shambling_horror_icc : public ScriptedAI  { -    public: -        npc_shambling_horror_icc() :  CreatureScript("npc_shambling_horror_icc") { } +    npc_shambling_horror_icc(Creature* creature) : ScriptedAI(creature) +    { +        _frenzied = false; +    } + +    void Reset() override +    { +        _events.Reset(); +        _events.ScheduleEvent(EVENT_SHOCKWAVE, 20s, 25s); +        _events.ScheduleEvent(EVENT_ENRAGE, 11s, 14s); +    } + +    void DamageTaken(Unit* /*attacker*/, uint32& damage) override +    { +        if (!_frenzied && IsHeroic() && me->HealthBelowPctDamaged(20, damage)) +        { +            _frenzied = true; +            DoCastSelf(SPELL_FRENZY, true); +        } +    } -        struct npc_shambling_horror_iccAI : public ScriptedAI -        { -            npc_shambling_horror_iccAI(Creature* creature) : ScriptedAI(creature) -            { -                _frenzied = false; -            } +    void UpdateAI(uint32 diff) override +    { +        if (!UpdateVictim()) +            return; -            void Reset() override -            { -                _events.Reset(); -                _events.ScheduleEvent(EVENT_SHOCKWAVE, 20s, 25s); -                _events.ScheduleEvent(EVENT_ENRAGE, 11s, 14s); -            } +        _events.Update(diff); -            void DamageTaken(Unit* /*attacker*/, uint32& damage) override -            { -                if (!_frenzied && IsHeroic() && me->HealthBelowPctDamaged(20, damage)) -                { -                    _frenzied = true; -                    DoCast(me, SPELL_FRENZY, true); -                } -            } +        if (me->HasUnitState(UNIT_STATE_CASTING)) +            return; -            void UpdateAI(uint32 diff) override +        while (uint32 eventId = _events.ExecuteEvent()) +        { +            switch (eventId)              { -                if (!UpdateVictim()) -                    return; - -                _events.Update(diff); - -                if (me->HasUnitState(UNIT_STATE_CASTING)) -                    return; - -                while (uint32 eventId = _events.ExecuteEvent()) -                { -                    switch (eventId) -                    { -                        case EVENT_SHOCKWAVE: -                            DoCast(me, SPELL_SHOCKWAVE); -                            _events.ScheduleEvent(EVENT_SHOCKWAVE, 20s, 25s); -                            break; -                        case EVENT_ENRAGE: -                            if (SPELL_CAST_OK != DoCast(me, SPELL_ENRAGE)) -                                _events.ScheduleEvent(EVENT_ENRAGE, 1s); -                            else -                                _events.ScheduleEvent(EVENT_ENRAGE, 20s, 25s); -                            break; -                        default: -                            break; -                    } -                } - -                DoMeleeAttackIfReady(); +                case EVENT_SHOCKWAVE: +                    DoCastSelf(SPELL_SHOCKWAVE); +                    _events.ScheduleEvent(EVENT_SHOCKWAVE, 20s, 25s); +                    break; +                case EVENT_ENRAGE: +                    if (SPELL_CAST_OK != DoCastSelf(SPELL_ENRAGE)) +                        _events.ScheduleEvent(EVENT_ENRAGE, 1s); +                    else +                        _events.ScheduleEvent(EVENT_ENRAGE, 20s, 25s); +                    break; +                default: +                    break;              } +        } -            void OnSpellCastInterrupt(SpellInfo const* spell) override -            { -                ScriptedAI::OnSpellCastInterrupt(spell); +        DoMeleeAttackIfReady(); +    } -                // When enrage is interrupted, reschedule the event -                if (spell->Id == ENRAGE) -                    _events.RescheduleEvent(EVENT_ENRAGE, 1s); -            } +    void OnSpellCastInterrupt(SpellInfo const* spell) override +    { +        ScriptedAI::OnSpellCastInterrupt(spell); -        private: -            EventMap _events; -            bool _frenzied; -        }; +        // When enrage is interrupted, reschedule the event +        if (spell->Id == ENRAGE) +            _events.RescheduleEvent(EVENT_ENRAGE, 1s); +    } -        CreatureAI* GetAI(Creature* creature) const override -        { -            return GetIcecrownCitadelAI<npc_shambling_horror_iccAI>(creature); -        } +private: +    EventMap _events; +    bool _frenzied;  }; -class npc_raging_spirit : public CreatureScript +struct npc_raging_spirit : public ScriptedAI  { -    public: -        npc_raging_spirit() : CreatureScript("npc_raging_spirit") { } +    npc_raging_spirit(Creature* creature) : ScriptedAI(creature), _instance(creature->GetInstanceScript()) { } + +    void Reset() override +    { +        me->SetReactState(REACT_PASSIVE); +        _events.Reset(); +        _events.ScheduleEvent(EVENT_SET_AGRESSIVE, 2s); +        _events.ScheduleEvent(EVENT_SOUL_SHRIEK, 12s, 15s); +        DoCastSelf(SPELL_PLAGUE_AVOIDANCE, true); +        DoCastSelf(SPELL_RAGING_SPIRIT_VISUAL, true); +        if (TempSummon* summon = me->ToTempSummon()) +            if (Unit* summoner = summon->GetSummonerUnit()) +                summoner->CastSpell(me, SPELL_RAGING_SPIRIT_VISUAL_CLONE, true); +        DoCastSelf(SPELL_BOSS_HITTIN_YA, true); +    } + +    void DoAction(int32 action) override +    { +        if (action == ACTION_DISABLE_RAGING) +        { +            _events.Reset(); +            _events.SetPhase(PHASE_FROSTMOURNE); +            _events.ScheduleEvent(EVENT_SET_AGRESSIVE, 52s); +            me->SetReactState(REACT_PASSIVE); +            me->AttackStop(); +            me->InterruptNonMeleeSpells(true); +        } +    } -        struct npc_raging_spiritAI : public ScriptedAI -        { -            npc_raging_spiritAI(Creature* creature) : ScriptedAI(creature), -                _instance(creature->GetInstanceScript()) -            { -            } +    void IsSummonedBy(WorldObject* /*summoner*/) override +    { +        // player is the spellcaster so register summon manually +        if (Creature* lichKing = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_THE_LICH_KING))) +            lichKing->AI()->JustSummoned(me); +    } -            void Reset() override -            { -                me->SetReactState(REACT_PASSIVE); -                _events.Reset(); -                _events.ScheduleEvent(EVENT_SET_AGRESSIVE, 2s); -                _events.ScheduleEvent(EVENT_SOUL_SHRIEK, 12s, 15s); -                DoCast(me, SPELL_PLAGUE_AVOIDANCE, true); -                DoCast(me, SPELL_RAGING_SPIRIT_VISUAL, true); -                if (TempSummon* summon = me->ToTempSummon()) -                    if (Unit* summoner = summon->GetSummonerUnit()) -                        summoner->CastSpell(me, SPELL_RAGING_SPIRIT_VISUAL_CLONE, true); -                DoCast(me, SPELL_BOSS_HITTIN_YA, true); -            } +    void JustDied(Unit* /*killer*/) override +    { +        if (Creature* lichKing = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_THE_LICH_KING))) +            lichKing->AI()->SummonedCreatureDespawn(me); +        if (TempSummon* summon = me->ToTempSummon()) +            summon->SetTempSummonType(TEMPSUMMON_CORPSE_DESPAWN); +    } -            void DoAction(int32 action) override -            { -                if (action == ACTION_DISABLE_RAGING) -                { -                    _events.Reset(); -                    _events.SetPhase(PHASE_FROSTMOURNE); -                    _events.ScheduleEvent(EVENT_SET_AGRESSIVE, 52s); -                    me->SetReactState(REACT_PASSIVE); -                    me->AttackStop(); -                    me->InterruptNonMeleeSpells(true); -                } -            } +    void UpdateAI(uint32 diff) override +    { +        if (!_events.IsInPhase(PHASE_FROSTMOURNE) && !UpdateVictim()) +            return; -            void IsSummonedBy(WorldObject* /*summoner*/) override -            { -                // player is the spellcaster so register summon manually -                if (Creature* lichKing = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_THE_LICH_KING))) -                    lichKing->AI()->JustSummoned(me); -            } +        _events.Update(diff); -            void JustDied(Unit* /*killer*/) override -            { -                if (Creature* lichKing = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_THE_LICH_KING))) -                    lichKing->AI()->SummonedCreatureDespawn(me); -                if (TempSummon* summon = me->ToTempSummon()) -                    summon->SetTempSummonType(TEMPSUMMON_CORPSE_DESPAWN); -            } +        if (me->HasUnitState(UNIT_STATE_CASTING)) +            return; -            void UpdateAI(uint32 diff) override +        while (uint32 eventId = _events.ExecuteEvent()) +        { +            switch (eventId)              { -                if (!_events.IsInPhase(PHASE_FROSTMOURNE) && !UpdateVictim()) -                    return; - -                _events.Update(diff); - -                if (me->HasUnitState(UNIT_STATE_CASTING)) -                    return; - -                while (uint32 eventId = _events.ExecuteEvent()) -                { -                    switch (eventId) +                case EVENT_SOUL_SHRIEK: +                    DoCastAOE(SPELL_SOUL_SHRIEK); +                    _events.ScheduleEvent(EVENT_SOUL_SHRIEK, 12s, 15s); +                    break; +                case EVENT_SET_AGRESSIVE: +                    me->SetReactState(REACT_AGGRESSIVE); +                    if (_events.IsInPhase(PHASE_FROSTMOURNE))                      { -                        case EVENT_SOUL_SHRIEK: -                            DoCastAOE(SPELL_SOUL_SHRIEK); -                            _events.ScheduleEvent(EVENT_SOUL_SHRIEK, 12s, 15s); -                            break; -                        case EVENT_SET_AGRESSIVE: -                            me->SetReactState(REACT_AGGRESSIVE); -                            if (_events.IsInPhase(PHASE_FROSTMOURNE)) -                            { -                                _events.SetPhase(PHASE_THREE); -                                _events.ScheduleEvent(EVENT_SOUL_SHRIEK, 12s, 15s); -                            } -                            break; -                        default: -                            break; +                        _events.SetPhase(PHASE_THREE); +                        _events.ScheduleEvent(EVENT_SOUL_SHRIEK, 12s, 15s);                      } -                } - -                DoMeleeAttackIfReady(); +                    break; +                default: +                    break;              } +        } -        private: -            EventMap _events; -            InstanceScript* _instance; -        }; +        DoMeleeAttackIfReady(); +    } -        CreatureAI* GetAI(Creature* creature) const override -        { -            return GetIcecrownCitadelAI<npc_raging_spiritAI>(creature); -        } +private: +    EventMap _events; +    InstanceScript* _instance;  }; -class npc_valkyr_shadowguard : public CreatureScript +struct npc_valkyr_shadowguard : public ScriptedAI  { -    public: -        npc_valkyr_shadowguard() : CreatureScript("npc_valkyr_shadowguard") { } - -        struct npc_valkyr_shadowguardAI : public ScriptedAI -        { -            npc_valkyr_shadowguardAI(Creature* creature) : ScriptedAI(creature), -                _instance(creature->GetInstanceScript()) -            { -            } - -            void Reset() override -            { -                _events.Reset(); -                me->SetReactState(REACT_PASSIVE); -                DoCast(me, SPELL_WINGS_OF_THE_DAMNED, false); -            } - -            void IsSummonedBy(WorldObject* /*summoner*/) override -            { -                _events.Reset(); -                _events.ScheduleEvent(EVENT_GRAB_PLAYER, 2500ms); -            } +    npc_valkyr_shadowguard(Creature* creature) : ScriptedAI(creature), _instance(creature->GetInstanceScript()) { } -            void DamageTaken(Unit* /*attacker*/, uint32& damage) override -            { -                if (!IsHeroic()) -                    return; - -                if (!me->HasAuraType(SPELL_AURA_CONTROL_VEHICLE)) -                    return; - -                if (me->HealthBelowPctDamaged(50, damage)) -                { -                    DoCastAOE(SPELL_EJECT_ALL_PASSENGERS); -                    ScheduleHeroicEvents(); -                } -            } +    void Reset() override +    { +        _events.Reset(); +        me->SetReactState(REACT_PASSIVE); +        DoCastSelf(SPELL_WINGS_OF_THE_DAMNED, false); +    } -            void ScheduleHeroicEvents() -            { -                _events.Reset(); -                _events.ScheduleEvent(EVENT_MOVE_TO_CENTER, 1ms); -                me->ClearUnitState(UNIT_STATE_EVADE); -            } +    void IsSummonedBy(WorldObject* /*summoner*/) override +    { +        _events.Reset(); +        _events.ScheduleEvent(EVENT_GRAB_PLAYER, 2500ms); +    } -            void AttackStart(Unit* /*target*/) override -            { -            } +    void DamageTaken(Unit* /*attacker*/, uint32& damage) override +    { +        if (!IsHeroic()) +            return; -            void MovementInform(uint32 type, uint32 id) override -            { -                if (type != POINT_MOTION_TYPE) -                    return; +        if (!me->HasAuraType(SPELL_AURA_CONTROL_VEHICLE)) +            return; -                switch (id) -                { -                    case POINT_DROP_PLAYER: -                        DoCastAOE(SPELL_EJECT_ALL_PASSENGERS); -                        if (IsHeroic()) -                            ScheduleHeroicEvents(); -                        else -                            me->DespawnOrUnsummon(1s); -                        break; -                    case POINT_CHARGE: -                        if (Player* target = ObjectAccessor::GetPlayer(*me, _grabbedPlayer)) -                        { -                            me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); -                            if (GameObject* platform = ObjectAccessor::GetGameObject(*me, _instance->GetGuidData(DATA_ARTHAS_PLATFORM))) -                            { -                                std::list<Creature*> triggers; -                                GetCreatureListWithEntryInGrid(triggers, me, NPC_WORLD_TRIGGER, 150.0f); -                                triggers.remove_if(HeightDifferenceCheck(platform, 5.0f, true)); -                                if (triggers.empty()) -                                    return; - -                                triggers.sort(Trinity::ObjectDistanceOrderPred(me)); -                                DoCast(target, SPELL_VALKYR_CARRY); -                                _dropPoint.Relocate(triggers.front()); -                                _events.ScheduleEvent(EVENT_MOVE_TO_DROP_POS, 1500ms); -                            } -                        } -                        else -                            me->DespawnOrUnsummon(); -                        break; -                    case POINT_SIPHON: -                        DoZoneInCombat(); -                        _events.ScheduleEvent(EVENT_LIFE_SIPHON, 2s); -                        break; -                    default: -                        break; -                } -            } - -            void SetGUID(ObjectGuid const& guid, int32 /*id*/) override -            { -                _grabbedPlayer = guid; -            } +        if (me->HealthBelowPctDamaged(50, damage)) +        { +            DoCastAOE(SPELL_EJECT_ALL_PASSENGERS); +            ScheduleHeroicEvents(); +        } +    } -            void UpdateAI(uint32 diff) override -            { -                if (!UpdateVictim()) -                    return; +    void ScheduleHeroicEvents() +    { +        _events.Reset(); +        _events.ScheduleEvent(EVENT_MOVE_TO_CENTER, 1ms); +        me->ClearUnitState(UNIT_STATE_EVADE); +    } -                _events.Update(diff); +    void AttackStart(Unit* /*target*/) override +    { +    } -                if (me->HasUnitState(UNIT_STATE_CASTING)) -                    return; +    void MovementInform(uint32 type, uint32 id) override +    { +        if (type != POINT_MOTION_TYPE) +            return; -                while (uint32 eventId = _events.ExecuteEvent()) +        switch (id) +        { +            case POINT_DROP_PLAYER: +                DoCastAOE(SPELL_EJECT_ALL_PASSENGERS); +                if (IsHeroic()) +                    ScheduleHeroicEvents(); +                else +                    me->DespawnOrUnsummon(1s); +                break; +            case POINT_CHARGE: +                if (Player* target = ObjectAccessor::GetPlayer(*me, _grabbedPlayer))                  { -                    switch (eventId) +                    me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); +                    if (GameObject* platform = ObjectAccessor::GetGameObject(*me, _instance->GetGuidData(DATA_ARTHAS_PLATFORM)))                      { -                        case EVENT_GRAB_PLAYER: -                            if (!_grabbedPlayer) -                            { -                                DoCastAOE(SPELL_VALKYR_TARGET_SEARCH); -                                _events.ScheduleEvent(EVENT_GRAB_PLAYER, 2s); -                            } -                            break; -                        case EVENT_MOVE_TO_DROP_POS: -                            me->GetMotionMaster()->MovePoint(POINT_DROP_PLAYER, _dropPoint); -                            break; -                        case EVENT_LIFE_SIPHON: -                            if (Unit* target = SelectTarget(SelectTargetMethod::Random, 1)) -                                DoCast(target, SPELL_LIFE_SIPHON); -                            _events.ScheduleEvent(EVENT_LIFE_SIPHON, 2500ms); -                            break; -                        case EVENT_MOVE_TO_CENTER: -                        { -                            Position pos = me->GetRandomPoint(CenterPosition, 4.0f); -                            pos.m_positionZ = me->GetHomePosition().m_positionZ; -                            me->GetMotionMaster()->MovePoint(POINT_SIPHON, pos); -                            break; -                        } -                        default: -                            break; +                        std::list<Creature*> triggers; +                        GetCreatureListWithEntryInGrid(triggers, me, NPC_WORLD_TRIGGER, 150.0f); +                        triggers.remove_if(HeightDifferenceCheck(platform, 5.0f, true)); +                        if (triggers.empty()) +                            return; + +                        triggers.sort(Trinity::ObjectDistanceOrderPred(me)); +                        DoCast(target, SPELL_VALKYR_CARRY); +                        _dropPoint.Relocate(triggers.front()); +                        _events.ScheduleEvent(EVENT_MOVE_TO_DROP_POS, 1500ms);                      }                  } - -                // no melee attacks -            } - -        private: -            EventMap _events; -            Position _dropPoint; -            ObjectGuid _grabbedPlayer; -            InstanceScript* _instance; -        }; - -        CreatureAI* GetAI(Creature* creature) const override -        { -            return GetIcecrownCitadelAI<npc_valkyr_shadowguardAI>(creature); +                else +                    me->DespawnOrUnsummon(); +                break; +            case POINT_SIPHON: +                DoZoneInCombat(); +                _events.ScheduleEvent(EVENT_LIFE_SIPHON, 2s); +                break; +            default: +                break;          } -}; +    } -class npc_strangulate_vehicle : public CreatureScript -{ -    public: -        npc_strangulate_vehicle() : CreatureScript("npc_strangulate_vehicle") { } +    void SetGUID(ObjectGuid const& guid, int32 /*id*/) override +    { +        _grabbedPlayer = guid; +    } -        struct npc_strangulate_vehicleAI : public ScriptedAI -        { -            npc_strangulate_vehicleAI(Creature* creature) : ScriptedAI(creature), -                _instance(creature->GetInstanceScript()) -            { -            } +    void UpdateAI(uint32 diff) override +    { +        if (!UpdateVictim()) +            return; -            void IsSummonedBy(WorldObject* summonerWO) override -            { -                Unit* summoner = summonerWO->ToUnit(); -                if (!summoner) -                    return; -                me->SetFacingToObject(summoner); -                DoCast(summoner, SPELL_HARVEST_SOUL_VEHICLE); -                _events.Reset(); -                _events.ScheduleEvent(EVENT_MOVE_TO_LICH_KING, 2s); -                _events.ScheduleEvent(EVENT_TELEPORT, 6s); +        _events.Update(diff); -                // this will let us easily access all creatures of this entry on heroic mode when its time to teleport back -                if (Creature* lichKing = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_THE_LICH_KING))) -                    lichKing->AI()->JustSummoned(me); -            } +        if (me->HasUnitState(UNIT_STATE_CASTING)) +            return; -            void DoAction(int32 action) override +        while (uint32 eventId = _events.ExecuteEvent()) +        { +            switch (eventId)              { -                if (action != ACTION_TELEPORT_BACK) -                    return; - -                if (TempSummon* summ = me->ToTempSummon()) -                { -                    if (Unit* summoner = summ->GetSummonerUnit()) +                case EVENT_GRAB_PLAYER: +                    if (!_grabbedPlayer)                      { -                        DoCast(summoner, SPELL_HARVEST_SOUL_TELEPORT_BACK); -                        summoner->RemoveAurasDueToSpell(SPELL_HARVEST_SOULS_TELEPORT); +                        DoCastAOE(SPELL_VALKYR_TARGET_SEARCH); +                        _events.ScheduleEvent(EVENT_GRAB_PLAYER, 2s);                      } -                } - -                if (Creature* lichKing = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_THE_LICH_KING))) -                    lichKing->AI()->SummonedCreatureDespawn(me); -                me->DespawnOrUnsummon(); -            } - -            void UpdateAI(uint32 diff) override -            { -                UpdateVictim(); - -                _events.Update(diff); - -                while (uint32 eventId = _events.ExecuteEvent()) +                    break; +                case EVENT_MOVE_TO_DROP_POS: +                    me->GetMotionMaster()->MovePoint(POINT_DROP_PLAYER, _dropPoint); +                    break; +                case EVENT_LIFE_SIPHON: +                    if (Unit* target = SelectTarget(SelectTargetMethod::Random, 1)) +                        DoCast(target, SPELL_LIFE_SIPHON); +                    _events.ScheduleEvent(EVENT_LIFE_SIPHON, 2500ms); +                    break; +                case EVENT_MOVE_TO_CENTER:                  { -                    switch (eventId) -                    { -                        case EVENT_TELEPORT: -                            me->GetMotionMaster()->Clear(); -                            me->GetMotionMaster()->MoveIdle(); -                            if (TempSummon* summ = me->ToTempSummon()) -                            { -                                if (Unit* summoner = summ->GetSummonerUnit()) -                                { -                                    summoner->CastSpell(nullptr, SPELL_HARVEST_SOUL_VISUAL, true); -                                    summoner->ExitVehicle(summoner); -                                    if (!IsHeroic()) -                                        summoner->CastSpell(summoner, SPELL_HARVEST_SOUL_TELEPORT, true); -                                    else -                                    { -                                        summoner->CastSpell(summoner, SPELL_HARVEST_SOULS_TELEPORT, true); -                                        summoner->RemoveAurasDueToSpell(HARVEST_SOUL, ObjectGuid::Empty, 0, AURA_REMOVE_BY_EXPIRE); -                                    } -                                } -                            } - -                            _events.ScheduleEvent(EVENT_DESPAWN_SELF, 65s); -                            break; -                        case EVENT_MOVE_TO_LICH_KING: -                            if (Creature* lichKing = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_THE_LICH_KING))) -                            { -                                if (me->GetExactDist(lichKing) > 10.0f) -                                { -                                    Position pos = lichKing->GetNearPosition(float(rand_norm()) * 5.0f  + 7.5f, lichKing->GetAbsoluteAngle(me)); -                                    me->GetMotionMaster()->MovePoint(0, pos); -                                } -                            } -                            break; -                        case EVENT_DESPAWN_SELF: -                            if (Creature* lichKing = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_THE_LICH_KING))) -                                lichKing->AI()->SummonedCreatureDespawn(me); -                            me->DespawnOrUnsummon(1ms); -                            break; -                        default: -                            break; -                    } +                    Position pos = me->GetRandomPoint(CenterPosition, 4.0f); +                    pos.m_positionZ = me->GetHomePosition().m_positionZ; +                    me->GetMotionMaster()->MovePoint(POINT_SIPHON, pos); +                    break;                  } +                default: +                    break;              } +        } -        private: -            EventMap _events; -            InstanceScript* _instance; -        }; +        // no melee attacks +    } -        CreatureAI* GetAI(Creature* creature) const override -        { -            return GetIcecrownCitadelAI<npc_strangulate_vehicleAI>(creature); -        } +private: +    EventMap _events; +    Position _dropPoint; +    ObjectGuid _grabbedPlayer; +    InstanceScript* _instance;  }; -class npc_terenas_menethil : public CreatureScript +struct npc_strangulate_vehicle : public ScriptedAI  { -    public: -        npc_terenas_menethil() : CreatureScript("npc_terenas_menethil") { } +    npc_strangulate_vehicle(Creature* creature) : ScriptedAI(creature), _instance(creature->GetInstanceScript()) { } -        struct npc_terenas_menethilAI : public ScriptedAI -        { -            npc_terenas_menethilAI(Creature* creature) : ScriptedAI(creature), -                _instance(creature->GetInstanceScript()) -            { -            } +    void IsSummonedBy(WorldObject* summonerWO) override +    { +        Unit* summoner = summonerWO->ToUnit(); +        if (!summoner) +            return; +        me->SetFacingToObject(summoner); +        DoCast(summoner, SPELL_HARVEST_SOUL_VEHICLE); +        _events.Reset(); +        _events.ScheduleEvent(EVENT_MOVE_TO_LICH_KING, 2s); +        _events.ScheduleEvent(EVENT_TELEPORT, 6s); -            bool CanAIAttack(Unit const* target) const override -            { -                return target->GetEntry() != NPC_THE_LICH_KING; -            } +        // this will let us easily access all creatures of this entry on heroic mode when its time to teleport back +        if (Creature* lichKing = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_THE_LICH_KING))) +            lichKing->AI()->JustSummoned(me); +    } -            void DoAction(int32 action) override -            { -                switch (action) -                { -                    case ACTION_FROSTMOURNE_INTRO: -                        me->setActive(true); -                        me->SetFarVisible(false); -                        if (!IsHeroic()) -                            me->SetHealth(me->GetMaxHealth() / 2); -                        DoCast(me, SPELL_LIGHTS_FAVOR); -                        _events.Reset(); -                        _events.ScheduleEvent(EVENT_FROSTMOURNE_TALK_1, 2s, PHASE_FROSTMOURNE); -                        _events.ScheduleEvent(EVENT_FROSTMOURNE_TALK_2, 11s, PHASE_FROSTMOURNE); -                        if (!IsHeroic()) -                        { -                            _events.ScheduleEvent(EVENT_DESTROY_SOUL, 1min, PHASE_FROSTMOURNE); -                            _events.ScheduleEvent(EVENT_FROSTMOURNE_TALK_3, 25s); -                        } -                        break; -                    case ACTION_TELEPORT_BACK: -                        me->CastSpell(nullptr, SPELL_RESTORE_SOUL, TRIGGERED_NONE); -                        me->DespawnOrUnsummon(3s); -                        break; -                    default: -                        break; -                } -            } +    void DoAction(int32 action) override +    { +        if (action != ACTION_TELEPORT_BACK) +            return; -            void EnterEvadeMode(EvadeReason /*why*/) override +        if (TempSummon* summ = me->ToTempSummon()) +        { +            if (Unit* summoner = summ->GetSummonerUnit())              { -                // no running back home -                if (!me->IsAlive()) -                    return; - -                me->CombatStop(false); -                EngagementOver(); +                DoCast(summoner, SPELL_HARVEST_SOUL_TELEPORT_BACK); +                summoner->RemoveAurasDueToSpell(SPELL_HARVEST_SOULS_TELEPORT);              } +        } -            void DamageTaken(Unit* /*attacker*/, uint32& damage) override -            { -                if (damage >= me->GetHealth()) -                { -                    damage = me->GetHealth() - 1; -                    if (!me->HasAura(SPELL_TERENAS_LOSES_INSIDE) && !IsHeroic()) -                    { -                        me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); -                        DoCast(SPELL_TERENAS_LOSES_INSIDE); -                        _events.ScheduleEvent(EVENT_TELEPORT_BACK, 1s); -                        if (Creature* warden = me->FindNearestCreature(NPC_SPIRIT_WARDEN, 20.0f)) -                        { -                            warden->CastSpell(nullptr, SPELL_DESTROY_SOUL, TRIGGERED_NONE); -                            warden->DespawnOrUnsummon(2s); -                        } - -                        me->DespawnOrUnsummon(2s); -                    } -                } -            } +        if (Creature* lichKing = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_THE_LICH_KING))) +            lichKing->AI()->SummonedCreatureDespawn(me); +        me->DespawnOrUnsummon(); +    } -            void IsSummonedBy(WorldObject* /*summoner*/) override -            { -                _events.Reset(); -                _events.SetPhase(PHASE_OUTRO); -                if (Creature* lichKing = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_THE_LICH_KING))) -                    me->SetFacingToObject(lichKing); +    void UpdateAI(uint32 diff) override +    { +        UpdateVictim(); -                _events.ScheduleEvent(EVENT_OUTRO_TERENAS_TALK_1, 2s, 0, PHASE_OUTRO); -                _events.ScheduleEvent(EVENT_OUTRO_TERENAS_TALK_2, 14s, 0, PHASE_OUTRO); -            } +        _events.Update(diff); -            void UpdateAI(uint32 diff) override +        while (uint32 eventId = _events.ExecuteEvent()) +        { +            switch (eventId)              { -                UpdateVictim(); - -                _events.Update(diff); - -                while (uint32 eventId = _events.ExecuteEvent()) -                { -                    switch (eventId) +                case EVENT_TELEPORT: +                    me->GetMotionMaster()->Clear(); +                    me->GetMotionMaster()->MoveIdle(); +                    if (TempSummon* summ = me->ToTempSummon())                      { -                        case EVENT_FROSTMOURNE_TALK_1: -                            Talk(SAY_TERENAS_INTRO_1); -                            if (IsHeroic()) -                                DoCastAOE(SPELL_RESTORE_SOULS); -                            break; -                        case EVENT_FROSTMOURNE_TALK_2: -                            Talk(SAY_TERENAS_INTRO_2); -                            break; -                        case EVENT_FROSTMOURNE_TALK_3: -                            Talk(SAY_TERENAS_INTRO_3); -                            break; -                        case EVENT_OUTRO_TERENAS_TALK_1: -                            Talk(SAY_TERENAS_OUTRO_1); -                            break; -                        case EVENT_OUTRO_TERENAS_TALK_2: -                            Talk(SAY_TERENAS_OUTRO_2); -                            DoCastAOE(SPELL_MASS_RESURRECTION); -                            if (Creature* lichKing = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_THE_LICH_KING))) +                        if (Unit* summoner = summ->GetSummonerUnit()) +                        { +                            summoner->CastSpell(nullptr, SPELL_HARVEST_SOUL_VISUAL, true); +                            summoner->ExitVehicle(summoner); +                            if (!IsHeroic()) +                                summoner->CastSpell(summoner, SPELL_HARVEST_SOUL_TELEPORT, true); +                            else                              { -                                lichKing->AI()->DoAction(ACTION_FINISH_OUTRO); -                                lichKing->SetImmuneToNPC(false); -                                if (Creature* tirion = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_HIGHLORD_TIRION_FORDRING))) -                                    tirion->AI()->AttackStart(lichKing); +                                summoner->CastSpell(summoner, SPELL_HARVEST_SOULS_TELEPORT, true); +                                summoner->RemoveAurasDueToSpell(HARVEST_SOUL, ObjectGuid::Empty, 0, AURA_REMOVE_BY_EXPIRE);                              } -                            break; -                        case EVENT_DESTROY_SOUL: -                            me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); -                            if (Creature* warden = me->FindNearestCreature(NPC_SPIRIT_WARDEN, 20.0f)) -                                warden->CastSpell(nullptr, SPELL_DESTROY_SOUL, TRIGGERED_NONE); -                            DoCast(SPELL_TERENAS_LOSES_INSIDE); -                            _events.ScheduleEvent(EVENT_TELEPORT_BACK, 1s); -                            break; -                        case EVENT_TELEPORT_BACK: -                            if (Creature* lichKing = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_THE_LICH_KING))) -                                lichKing->AI()->DoAction(ACTION_TELEPORT_BACK); -                            break; -                        default: -                            break; +                        }                      } -                } -                // fighting Spirit Warden -                if (me->IsInCombat()) -                    DoMeleeAttackIfReady(); +                    _events.ScheduleEvent(EVENT_DESPAWN_SELF, 65s); +                    break; +                case EVENT_MOVE_TO_LICH_KING: +                    if (Creature* lichKing = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_THE_LICH_KING))) +                    { +                        if (me->GetExactDist(lichKing) > 10.0f) +                        { +                            Position pos = lichKing->GetNearPosition(float(rand_norm()) * 5.0f  + 7.5f, lichKing->GetAbsoluteAngle(me)); +                            me->GetMotionMaster()->MovePoint(0, pos); +                        } +                    } +                    break; +                case EVENT_DESPAWN_SELF: +                    if (Creature* lichKing = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_THE_LICH_KING))) +                        lichKing->AI()->SummonedCreatureDespawn(me); +                    me->DespawnOrUnsummon(1ms); +                    break; +                default: +                    break;              } - -        private: -            EventMap _events; -            InstanceScript* _instance; -        }; - -        CreatureAI* GetAI(Creature* creature) const override -        { -            return GetIcecrownCitadelAI<npc_terenas_menethilAI>(creature);          } +    } + +private: +    EventMap _events; +    InstanceScript* _instance;  }; -class npc_spirit_warden : public CreatureScript +struct npc_terenas_menethil : public ScriptedAI  { -    public: -        npc_spirit_warden() : CreatureScript("npc_spirit_warden") { } +    npc_terenas_menethil(Creature* creature) : ScriptedAI(creature), _instance(creature->GetInstanceScript()) { } -        struct npc_spirit_wardenAI : public ScriptedAI -        { -            npc_spirit_wardenAI(Creature* creature) : ScriptedAI(creature), -                _instance(creature->GetInstanceScript()) -            { -            } +    bool CanAIAttack(Unit const* target) const override +    { +        return target->GetEntry() != NPC_THE_LICH_KING; +    } -            void Reset() override -            { +    void DoAction(int32 action) override +    { +        switch (action) +        { +            case ACTION_FROSTMOURNE_INTRO: +                me->setActive(true); +                me->SetFarVisible(false); +                if (!IsHeroic()) +                    me->SetHealth(me->GetMaxHealth() / 2); +                DoCastSelf(SPELL_LIGHTS_FAVOR);                  _events.Reset(); -                _events.ScheduleEvent(EVENT_SOUL_RIP, 12s, 15s); -                DoCast(SPELL_DARK_HUNGER); -            } - -            void JustDied(Unit* /*killer*/) override -            { -                if (Creature* terenas = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_TERENAS_MENETHIL))) -                    terenas->AI()->DoAction(ACTION_TELEPORT_BACK); -            } - -            void UpdateAI(uint32 diff) override -            { -                if (!UpdateVictim()) -                    return; - -                _events.Update(diff); - -                while (uint32 eventId = _events.ExecuteEvent()) +                _events.ScheduleEvent(EVENT_FROSTMOURNE_TALK_1, 2s, PHASE_FROSTMOURNE); +                _events.ScheduleEvent(EVENT_FROSTMOURNE_TALK_2, 11s, PHASE_FROSTMOURNE); +                if (!IsHeroic())                  { -                    switch (eventId) -                    { -                        case EVENT_SOUL_RIP: -                            DoCastVictim(SPELL_SOUL_RIP); -                            _events.ScheduleEvent(EVENT_SOUL_RIP, 23s, 27s); -                            break; -                        default: -                            break; -                    } +                    _events.ScheduleEvent(EVENT_DESTROY_SOUL, 1min, PHASE_FROSTMOURNE); +                    _events.ScheduleEvent(EVENT_FROSTMOURNE_TALK_3, 25s);                  } - -                DoMeleeAttackIfReady(); -            } - -        private: -            EventMap _events; -            InstanceScript* _instance; -        }; - -        CreatureAI* GetAI(Creature* creature) const override -        { -            return GetIcecrownCitadelAI<npc_spirit_wardenAI>(creature); +                break; +            case ACTION_TELEPORT_BACK: +                me->CastSpell(nullptr, SPELL_RESTORE_SOUL, TRIGGERED_NONE); +                me->DespawnOrUnsummon(3s); +                break; +            default: +                break;          } -}; +    } -class npc_spirit_bomb : public CreatureScript -{ -    public: -        npc_spirit_bomb() : CreatureScript("npc_spirit_bomb") { } +    void EnterEvadeMode(EvadeReason /*why*/) override +    { +        // no running back home +        if (!me->IsAlive()) +            return; -        struct npc_spirit_bombAI : public CreatureAI -        { -            npc_spirit_bombAI(Creature* creature) : CreatureAI(creature) -            { -            } +        me->CombatStop(false); +        EngagementOver(); +    } -            void IsSummonedBy(WorldObject* /*summoner*/) override -            { -                float destX, destY, destZ; -                me->GetPosition(destX, destY); -                destZ = 1055.0f;    // approximation, gets more precise later -                me->UpdateGroundPositionZ(destX, destY, destZ); -                me->GetMotionMaster()->MovePoint(POINT_GROUND, destX, destY, destZ); -            } - -            void MovementInform(uint32 type, uint32 point) override -            { -                if (type != POINT_MOTION_TYPE || point != POINT_GROUND) -                    return; - -                _events.ScheduleEvent(EVENT_BOMB_EXPLOSION, 3s); -            } - -            void AttackStart(Unit* /*victim*/) override -            { -            } - -            void UpdateAI(uint32 diff) override +    void DamageTaken(Unit* /*attacker*/, uint32& damage) override +    { +        if (damage >= me->GetHealth()) +        { +            damage = me->GetHealth() - 1; +            if (!me->HasAura(SPELL_TERENAS_LOSES_INSIDE) && !IsHeroic())              { -                UpdateVictim(); - -                _events.Update(diff); - -                if (_events.ExecuteEvent() == EVENT_BOMB_EXPLOSION) +                me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); +                DoCast(SPELL_TERENAS_LOSES_INSIDE); +                _events.ScheduleEvent(EVENT_TELEPORT_BACK, 1s); +                if (Creature* warden = me->FindNearestCreature(NPC_SPIRIT_WARDEN, 20.0f))                  { -                    me->RemoveAllAuras(); -                    DoCastAOE(SPELL_EXPLOSION); -                    me->DespawnOrUnsummon(1s); +                    warden->CastSpell(nullptr, SPELL_DESTROY_SOUL, TRIGGERED_NONE); +                    warden->DespawnOrUnsummon(2s);                  } -            } -        private: -            EventMap _events; -        }; - -        CreatureAI* GetAI(Creature* creature) const override -        { -            return GetIcecrownCitadelAI<npc_spirit_bombAI>(creature); +                me->DespawnOrUnsummon(2s); +            }          } -}; +    } -class npc_broken_frostmourne : public CreatureScript -{ -    public: -        npc_broken_frostmourne() : CreatureScript("npc_broken_frostmourne") { } +    void IsSummonedBy(WorldObject* /*summoner*/) override +    { +        _events.Reset(); +        _events.SetPhase(PHASE_OUTRO); +        if (Creature* lichKing = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_THE_LICH_KING))) +            me->SetFacingToObject(lichKing); -        struct npc_broken_frostmourneAI : public CreatureAI -        { -            npc_broken_frostmourneAI(Creature* creature) : CreatureAI(creature) -            { -            } +        _events.ScheduleEvent(EVENT_OUTRO_TERENAS_TALK_1, 2s, 0, PHASE_OUTRO); +        _events.ScheduleEvent(EVENT_OUTRO_TERENAS_TALK_2, 14s, 0, PHASE_OUTRO); +    } -            void Reset() override -            { -                _events.Reset(); -            } +    void UpdateAI(uint32 diff) override +    { +        UpdateVictim(); -            void IsSummonedBy(WorldObject* /*summoner*/) override -            { -                _events.SetPhase(PHASE_OUTRO); -                _events.ScheduleEvent(EVENT_OUTRO_KNOCK_BACK, 3s, 0, PHASE_OUTRO); -            } +        _events.Update(diff); -            void DoAction(int32 action) override -            { -                if (action == ACTION_SUMMON_TERENAS) -                    _events.ScheduleEvent(EVENT_OUTRO_SUMMON_TERENAS, 6s, 0, PHASE_OUTRO); -            } - -            void EnterEvadeMode(EvadeReason /*why*/) override -            { -            } - -            void UpdateAI(uint32 diff) override +        while (uint32 eventId = _events.ExecuteEvent()) +        { +            switch (eventId)              { -                UpdateVictim(); - -                _events.Update(diff); - -                while (uint32 eventId = _events.ExecuteEvent()) -                { -                    switch (eventId) +                case EVENT_FROSTMOURNE_TALK_1: +                    Talk(SAY_TERENAS_INTRO_1); +                    if (IsHeroic()) +                        DoCastAOE(SPELL_RESTORE_SOULS); +                    break; +                case EVENT_FROSTMOURNE_TALK_2: +                    Talk(SAY_TERENAS_INTRO_2); +                    break; +                case EVENT_FROSTMOURNE_TALK_3: +                    Talk(SAY_TERENAS_INTRO_3); +                    break; +                case EVENT_OUTRO_TERENAS_TALK_1: +                    Talk(SAY_TERENAS_OUTRO_1); +                    break; +                case EVENT_OUTRO_TERENAS_TALK_2: +                    Talk(SAY_TERENAS_OUTRO_2); +                    DoCastAOE(SPELL_MASS_RESURRECTION); +                    if (Creature* lichKing = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_THE_LICH_KING)))                      { -                        case EVENT_OUTRO_KNOCK_BACK: -                            DoCastAOE(SPELL_BROKEN_FROSTMOURNE_KNOCK); -                            break; -                        case EVENT_OUTRO_SUMMON_TERENAS: -                            DoCastAOE(SPELL_SUMMON_TERENAS); -                            break; -                        default: -                            break; +                        lichKing->AI()->DoAction(ACTION_FINISH_OUTRO); +                        lichKing->SetImmuneToNPC(false); +                        if (Creature* tirion = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_HIGHLORD_TIRION_FORDRING))) +                            tirion->AI()->AttackStart(lichKing);                      } -                } - -                // no melee attacks +                    break; +                case EVENT_DESTROY_SOUL: +                    me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); +                    if (Creature* warden = me->FindNearestCreature(NPC_SPIRIT_WARDEN, 20.0f)) +                        warden->CastSpell(nullptr, SPELL_DESTROY_SOUL, TRIGGERED_NONE); +                    DoCast(SPELL_TERENAS_LOSES_INSIDE); +                    _events.ScheduleEvent(EVENT_TELEPORT_BACK, 1s); +                    break; +                case EVENT_TELEPORT_BACK: +                    if (Creature* lichKing = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_THE_LICH_KING))) +                        lichKing->AI()->DoAction(ACTION_TELEPORT_BACK); +                    break; +                default: +                    break;              } +        } -        private: -            EventMap _events; -        }; +        // fighting Spirit Warden +        if (me->IsInCombat()) +            DoMeleeAttackIfReady(); +    } -        CreatureAI* GetAI(Creature* creature) const override -        { -            return GetIcecrownCitadelAI<npc_broken_frostmourneAI>(creature); -        } +private: +    EventMap _events; +    InstanceScript* _instance;  }; -class spell_the_lich_king_infest : public SpellScriptLoader +struct npc_spirit_warden : public ScriptedAI  { -    public: -        spell_the_lich_king_infest() :  SpellScriptLoader("spell_the_lich_king_infest") { } +    npc_spirit_warden(Creature* creature) : ScriptedAI(creature), _instance(creature->GetInstanceScript()) { } -        class spell_the_lich_king_infest_AuraScript : public AuraScript -        { -            PrepareAuraScript(spell_the_lich_king_infest_AuraScript); +    void Reset() override +    { +        _events.Reset(); +        _events.ScheduleEvent(EVENT_SOUL_RIP, 12s, 15s); +        DoCast(SPELL_DARK_HUNGER); +    } -            void OnPeriodic(AuraEffect const* /*aurEff*/) -            { -                if (GetUnitOwner()->HealthAbovePct(90)) -                { -                    PreventDefaultAction(); -                    Remove(AURA_REMOVE_BY_ENEMY_SPELL); -                } -            } +    void JustDied(Unit* /*killer*/) override +    { +        if (Creature* terenas = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_TERENAS_MENETHIL))) +            terenas->AI()->DoAction(ACTION_TELEPORT_BACK); +    } -            void OnUpdate(AuraEffect* aurEff) -            { -                // multiply, starting from 2nd tick -                if (aurEff->GetTickNumber() == 1) -                    return; +    void UpdateAI(uint32 diff) override +    { +        if (!UpdateVictim()) +            return; -                aurEff->SetAmount(int32(aurEff->GetAmount() * 1.15f)); -            } +        _events.Update(diff); -            void Register() override +        while (uint32 eventId = _events.ExecuteEvent()) +        { +            switch (eventId)              { -                OnEffectPeriodic += AuraEffectPeriodicFn(spell_the_lich_king_infest_AuraScript::OnPeriodic, EFFECT_0, SPELL_AURA_PERIODIC_DAMAGE); -                OnEffectUpdatePeriodic += AuraEffectUpdatePeriodicFn(spell_the_lich_king_infest_AuraScript::OnUpdate, EFFECT_0, SPELL_AURA_PERIODIC_DAMAGE); +                case EVENT_SOUL_RIP: +                    DoCastVictim(SPELL_SOUL_RIP); +                    _events.ScheduleEvent(EVENT_SOUL_RIP, 23s, 27s); +                    break; +                default: +                    break;              } -        }; - -        AuraScript* GetAuraScript() const override -        { -            return new spell_the_lich_king_infest_AuraScript();          } + +        DoMeleeAttackIfReady(); +    } + +private: +    EventMap _events; +    InstanceScript* _instance;  }; -class spell_the_lich_king_necrotic_plague : public SpellScriptLoader +struct npc_spirit_bomb : public CreatureAI  { -    public: -        spell_the_lich_king_necrotic_plague() :  SpellScriptLoader("spell_the_lich_king_necrotic_plague") { } +    npc_spirit_bomb(Creature* creature) : CreatureAI(creature) { } -        class spell_the_lich_king_necrotic_plague_AuraScript : public AuraScript -        { -            PrepareAuraScript(spell_the_lich_king_necrotic_plague_AuraScript); +    void IsSummonedBy(WorldObject* /*summoner*/) override +    { +        float destX, destY, destZ; +        me->GetPosition(destX, destY); +        destZ = 1055.0f;    // approximation, gets more precise later +        me->UpdateGroundPositionZ(destX, destY, destZ); +        me->GetMotionMaster()->MovePoint(POINT_GROUND, destX, destY, destZ); +    } -            bool Validate(SpellInfo const* /*spell*/) override -            { -                return ValidateSpellInfo({ SPELL_NECROTIC_PLAGUE_JUMP }); -            } +    void MovementInform(uint32 type, uint32 point) override +    { +        if (type != POINT_MOTION_TYPE || point != POINT_GROUND) +            return; -            void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) -            { -                switch (GetTargetApplication()->GetRemoveMode()) -                { -                    case AURA_REMOVE_BY_ENEMY_SPELL: -                    case AURA_REMOVE_BY_EXPIRE: -                    case AURA_REMOVE_BY_DEATH: -                        break; -                    default: -                        return; -                } +        _events.ScheduleEvent(EVENT_BOMB_EXPLOSION, 3s); +    } -                CastSpellExtraArgs args(GetCasterGUID()); -                args.AddSpellMod(SPELLVALUE_MAX_TARGETS, 1); -                GetTarget()->CastSpell(nullptr, SPELL_NECROTIC_PLAGUE_JUMP, args); -                if (Unit* caster = GetCaster()) -                    caster->CastSpell(caster, SPELL_PLAGUE_SIPHON, true); -            } +    void AttackStart(Unit* /*victim*/) override +    { +    } -            void Register() override -            { -                AfterEffectRemove += AuraEffectRemoveFn(spell_the_lich_king_necrotic_plague_AuraScript::OnRemove, EFFECT_0, SPELL_AURA_PERIODIC_DAMAGE, AURA_EFFECT_HANDLE_REAL); -            } -        }; +    void UpdateAI(uint32 diff) override +    { +        UpdateVictim(); + +        _events.Update(diff); -        AuraScript* GetAuraScript() const override +        if (_events.ExecuteEvent() == EVENT_BOMB_EXPLOSION)          { -            return new spell_the_lich_king_necrotic_plague_AuraScript(); +            me->RemoveAllAuras(); +            DoCastAOE(SPELL_EXPLOSION); +            me->DespawnOrUnsummon(1s);          } +    } + +private: +    EventMap _events;  }; -class spell_the_lich_king_necrotic_plague_jump : public SpellScriptLoader +struct npc_broken_frostmourne : public CreatureAI  { -    public: -        spell_the_lich_king_necrotic_plague_jump() :  SpellScriptLoader("spell_the_lich_king_necrotic_plague_jump") { } +    npc_broken_frostmourne(Creature* creature) : CreatureAI(creature) { } -        class spell_the_lich_king_necrotic_plague_SpellScript : public SpellScript -        { -            PrepareSpellScript(spell_the_lich_king_necrotic_plague_SpellScript); +    void Reset() override +    { +        _events.Reset(); +    } -        public: -            spell_the_lich_king_necrotic_plague_SpellScript() -            { -                _hadAura = false; -            } - -        private: -            void SelectTarget(std::list<WorldObject*>& targets) -            { -                targets.sort(Trinity::ObjectDistanceOrderPred(GetCaster())); -                if (targets.size() < 2) -                    return; +    void IsSummonedBy(WorldObject* /*summoner*/) override +    { +        _events.SetPhase(PHASE_OUTRO); +        _events.ScheduleEvent(EVENT_OUTRO_KNOCK_BACK, 3s, 0, PHASE_OUTRO); +    } -                targets.resize(1); -            } +    void DoAction(int32 action) override +    { +        if (action == ACTION_SUMMON_TERENAS) +            _events.ScheduleEvent(EVENT_OUTRO_SUMMON_TERENAS, 6s, 0, PHASE_OUTRO); +    } -            void CheckAura(SpellMissInfo missInfo) -            { -                if (missInfo != SPELL_MISS_NONE) -                    return; - -                if (GetHitUnit()->HasAura(GetSpellInfo()->Id)) -                    _hadAura = true; -            } +    void EnterEvadeMode(EvadeReason /*why*/) override +    { +    } -            void Register() override -            { -                OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_the_lich_king_necrotic_plague_SpellScript::SelectTarget, EFFECT_0, TARGET_UNIT_SRC_AREA_ENTRY); -                BeforeHit += BeforeSpellHitFn(spell_the_lich_king_necrotic_plague_SpellScript::CheckAura); -            } +    void UpdateAI(uint32 diff) override +    { +        UpdateVictim(); -            bool _hadAura; -        }; +        _events.Update(diff); -        class spell_the_lich_king_necrotic_plague_AuraScript : public AuraScript +        while (uint32 eventId = _events.ExecuteEvent())          { -            PrepareAuraScript(spell_the_lich_king_necrotic_plague_AuraScript); - -        public: -            spell_the_lich_king_necrotic_plague_AuraScript() -            { -                _lastAmount = 0; -            } - -        private: -            void OnApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) -            { -                if (Unit* caster = GetCaster()) -                    if (caster->GetAI()) -                        caster->GetAI()->SetData(DATA_PLAGUE_STACK, GetStackAmount()); -            } - -            void OnRemove(AuraEffect const* aurEff, AuraEffectHandleModes /*mode*/) -            { -                _lastAmount = aurEff->GetAmount(); -                switch (GetTargetApplication()->GetRemoveMode()) -                { -                    case AURA_REMOVE_BY_EXPIRE: -                    case AURA_REMOVE_BY_DEATH: -                        break; -                    default: -                        return; -                } - -                CastSpellExtraArgs args(GetCasterGUID()); -                args.AddSpellMod(SPELLVALUE_AURA_STACK, GetStackAmount() + 1); -                GetTarget()->CastSpell(nullptr, SPELL_NECROTIC_PLAGUE_JUMP, args); -                if (Unit* caster = GetCaster()) -                    caster->CastSpell(caster, SPELL_PLAGUE_SIPHON, true); -            } - -            void OnDispel(AuraEffect const* aurEff, AuraEffectHandleModes /*mode*/) +            switch (eventId)              { -                _lastAmount = aurEff->GetAmount(); -            } - -            void AfterDispel(AuraEffect const* aurEff, AuraEffectHandleModes /*mode*/) -            { -                // this means the stack increased so don't process as if dispelled -                if (aurEff->GetAmount() > _lastAmount) -                    return; - -                CastSpellExtraArgs args(GetCasterGUID()); -                args.AddSpellMod(SPELLVALUE_AURA_STACK, GetStackAmount()); -                args.AddSpellMod(SPELLVALUE_BASE_POINT1, AURA_REMOVE_BY_ENEMY_SPELL); // add as marker (spell has no effect 1) -                GetTarget()->CastSpell(nullptr, SPELL_NECROTIC_PLAGUE_JUMP, args); -                if (Unit* caster = GetCaster()) -                    caster->CastSpell(caster, SPELL_PLAGUE_SIPHON, true); - -                Remove(AURA_REMOVE_BY_ENEMY_SPELL); -            } - -            void Register() override -            { -                OnEffectApply += AuraEffectApplyFn(spell_the_lich_king_necrotic_plague_AuraScript::OnApply, EFFECT_0, SPELL_AURA_PERIODIC_DAMAGE, AURA_EFFECT_HANDLE_REAL_OR_REAPPLY_MASK); -                AfterEffectRemove += AuraEffectRemoveFn(spell_the_lich_king_necrotic_plague_AuraScript::OnRemove, EFFECT_0, SPELL_AURA_PERIODIC_DAMAGE, AURA_EFFECT_HANDLE_REAL); -                AfterEffectRemove += AuraEffectRemoveFn(spell_the_lich_king_necrotic_plague_AuraScript::OnDispel, EFFECT_0, SPELL_AURA_PERIODIC_DAMAGE, AURA_EFFECT_HANDLE_REAPPLY); -                AfterEffectApply += AuraEffectRemoveFn(spell_the_lich_king_necrotic_plague_AuraScript::AfterDispel, EFFECT_0, SPELL_AURA_PERIODIC_DAMAGE, AURA_EFFECT_HANDLE_REAPPLY); +                case EVENT_OUTRO_KNOCK_BACK: +                    DoCastAOE(SPELL_BROKEN_FROSTMOURNE_KNOCK); +                    break; +                case EVENT_OUTRO_SUMMON_TERENAS: +                    DoCastAOE(SPELL_SUMMON_TERENAS); +                    break; +                default: +                    break;              } - -            int32 _lastAmount; -        }; - -        SpellScript* GetSpellScript() const override -        { -            return new spell_the_lich_king_necrotic_plague_SpellScript();          } -        AuraScript* GetAuraScript() const override -        { -            return new spell_the_lich_king_necrotic_plague_AuraScript(); -        } +        // no melee attacks +    } + +private: +    EventMap _events;  }; -class spell_the_lich_king_shadow_trap_visual : public SpellScriptLoader +class spell_the_lich_king_infest : public AuraScript  { -    public: -        spell_the_lich_king_shadow_trap_visual() : SpellScriptLoader("spell_the_lich_king_shadow_trap_visual") { } - -        class spell_the_lich_king_shadow_trap_visual_AuraScript : public AuraScript -        { -            PrepareAuraScript(spell_the_lich_king_shadow_trap_visual_AuraScript); - -            void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) -            { -                if (GetTargetApplication()->GetRemoveMode() == AURA_REMOVE_BY_EXPIRE) -                    GetTarget()->CastSpell(GetTarget(), SPELL_SHADOW_TRAP_AURA, TRIGGERED_NONE); -            } - -            void Register() override -            { -                AfterEffectRemove += AuraEffectRemoveFn(spell_the_lich_king_shadow_trap_visual_AuraScript::OnRemove, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL); -            } -        }; +    PrepareAuraScript(spell_the_lich_king_infest); -        AuraScript* GetAuraScript() const override +    void OnPeriodic(AuraEffect const* /*aurEff*/) +    { +        if (GetUnitOwner()->HealthAbovePct(90))          { -            return new spell_the_lich_king_shadow_trap_visual_AuraScript(); +            PreventDefaultAction(); +            Remove(AURA_REMOVE_BY_ENEMY_SPELL);          } +    } + +    void OnUpdate(AuraEffect* aurEff) +    { +        // multiply, starting from 2nd tick +        if (aurEff->GetTickNumber() == 1) +            return; + +        aurEff->SetAmount(int32(aurEff->GetAmount() * 1.15f)); +    } + +    void Register() override +    { +        OnEffectPeriodic += AuraEffectPeriodicFn(spell_the_lich_king_infest::OnPeriodic, EFFECT_0, SPELL_AURA_PERIODIC_DAMAGE); +        OnEffectUpdatePeriodic += AuraEffectUpdatePeriodicFn(spell_the_lich_king_infest::OnUpdate, EFFECT_0, SPELL_AURA_PERIODIC_DAMAGE); +    }  }; -class spell_the_lich_king_shadow_trap_periodic : public SpellScriptLoader +class spell_the_lich_king_necrotic_plague : public AuraScript  { -    public: -        spell_the_lich_king_shadow_trap_periodic() : SpellScriptLoader("spell_the_lich_king_shadow_trap_periodic") { } - -        class spell_the_lich_king_shadow_trap_periodic_SpellScript : public SpellScript -        { -            PrepareSpellScript(spell_the_lich_king_shadow_trap_periodic_SpellScript); - -            void CheckTargetCount(std::list<WorldObject*>& targets) -            { -                if (targets.empty()) -                    return; - -                GetCaster()->CastSpell(nullptr, SPELL_SHADOW_TRAP_KNOCKBACK, true); -            } +    PrepareAuraScript(spell_the_lich_king_necrotic_plague); + +    bool Validate(SpellInfo const* /*spell*/) override +    { +        return ValidateSpellInfo({ SPELL_NECROTIC_PLAGUE_JUMP }); +    } + +    void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) +    { +        switch (GetTargetApplication()->GetRemoveMode()) +        { +            case AURA_REMOVE_BY_ENEMY_SPELL: +            case AURA_REMOVE_BY_EXPIRE: +            case AURA_REMOVE_BY_DEATH: +                break; +            default: +                return; +        } -            void Register() override -            { -                OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_the_lich_king_shadow_trap_periodic_SpellScript::CheckTargetCount, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY); -            } -        }; +        CastSpellExtraArgs args(GetCasterGUID()); +        args.AddSpellMod(SPELLVALUE_MAX_TARGETS, 1); +        GetTarget()->CastSpell(nullptr, SPELL_NECROTIC_PLAGUE_JUMP, args); +        if (Unit* caster = GetCaster()) +            caster->CastSpell(caster, SPELL_PLAGUE_SIPHON, true); +    } + +    void Register() override +    { +        AfterEffectRemove += AuraEffectRemoveFn(spell_the_lich_king_necrotic_plague::OnRemove, EFFECT_0, SPELL_AURA_PERIODIC_DAMAGE, AURA_EFFECT_HANDLE_REAL); +    } +}; -        SpellScript* GetSpellScript() const override -        { -            return new spell_the_lich_king_shadow_trap_periodic_SpellScript(); -        } +class spell_the_lich_king_necrotic_plague_jump : public SpellScript +{ +    PrepareSpellScript(spell_the_lich_king_necrotic_plague_jump); + +public: +    spell_the_lich_king_necrotic_plague_jump() +    { +        _hadAura = false; +    } + +private: +    void SelectTarget(std::list<WorldObject*>& targets) +    { +        targets.sort(Trinity::ObjectDistanceOrderPred(GetCaster())); +        if (targets.size() < 2) +            return; + +        targets.resize(1); +    } + +    void CheckAura(SpellMissInfo missInfo) +    { +        if (missInfo != SPELL_MISS_NONE) +            return; + +        if (GetHitUnit()->HasAura(GetSpellInfo()->Id)) +            _hadAura = true; +    } + +    void Register() override +    { +        OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_the_lich_king_necrotic_plague_jump::SelectTarget, EFFECT_0, TARGET_UNIT_SRC_AREA_ENTRY); +        BeforeHit += BeforeSpellHitFn(spell_the_lich_king_necrotic_plague_jump::CheckAura); +    } + +    bool _hadAura;  }; -class spell_the_lich_king_quake : public SpellScriptLoader +class spell_the_lich_king_necrotic_plague_jump_aura : public AuraScript  { -    public: -        spell_the_lich_king_quake() : SpellScriptLoader("spell_the_lich_king_quake") { } +    PrepareAuraScript(spell_the_lich_king_necrotic_plague_jump_aura); + +public: +    spell_the_lich_king_necrotic_plague_jump_aura() +    { +        _lastAmount = 0; +    } + +private: +    void OnApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) +    { +        if (Unit* caster = GetCaster()) +            if (caster->GetAI()) +                caster->GetAI()->SetData(DATA_PLAGUE_STACK, GetStackAmount()); +    } + +    void OnRemove(AuraEffect const* aurEff, AuraEffectHandleModes /*mode*/) +    { +        _lastAmount = aurEff->GetAmount(); +        switch (GetTargetApplication()->GetRemoveMode()) +        { +            case AURA_REMOVE_BY_EXPIRE: +            case AURA_REMOVE_BY_DEATH: +                break; +            default: +                return; +        } -        class spell_the_lich_king_quake_SpellScript : public SpellScript -        { -            PrepareSpellScript(spell_the_lich_king_quake_SpellScript); +        CastSpellExtraArgs args(GetCasterGUID()); +        args.AddSpellMod(SPELLVALUE_AURA_STACK, GetStackAmount() + 1); +        GetTarget()->CastSpell(nullptr, SPELL_NECROTIC_PLAGUE_JUMP, args); +        if (Unit* caster = GetCaster()) +            caster->CastSpell(caster, SPELL_PLAGUE_SIPHON, true); +    } + +    void OnDispel(AuraEffect const* aurEff, AuraEffectHandleModes /*mode*/) +    { +        _lastAmount = aurEff->GetAmount(); +    } + +    void AfterDispel(AuraEffect const* aurEff, AuraEffectHandleModes /*mode*/) +    { +        // this means the stack increased so don't process as if dispelled +        if (aurEff->GetAmount() > _lastAmount) +            return; + +        CastSpellExtraArgs args(GetCasterGUID()); +        args.AddSpellMod(SPELLVALUE_AURA_STACK, GetStackAmount()); +        args.AddSpellMod(SPELLVALUE_BASE_POINT1, AURA_REMOVE_BY_ENEMY_SPELL); // add as marker (spell has no effect 1) +        GetTarget()->CastSpell(nullptr, SPELL_NECROTIC_PLAGUE_JUMP, args); +        if (Unit* caster = GetCaster()) +            caster->CastSpell(caster, SPELL_PLAGUE_SIPHON, true); + +        Remove(AURA_REMOVE_BY_ENEMY_SPELL); +    } + +    void Register() override +    { +        OnEffectApply += AuraEffectApplyFn(spell_the_lich_king_necrotic_plague_jump_aura::OnApply, EFFECT_0, SPELL_AURA_PERIODIC_DAMAGE, AURA_EFFECT_HANDLE_REAL_OR_REAPPLY_MASK); +        AfterEffectRemove += AuraEffectRemoveFn(spell_the_lich_king_necrotic_plague_jump_aura::OnRemove, EFFECT_0, SPELL_AURA_PERIODIC_DAMAGE, AURA_EFFECT_HANDLE_REAL); +        AfterEffectRemove += AuraEffectRemoveFn(spell_the_lich_king_necrotic_plague_jump_aura::OnDispel, EFFECT_0, SPELL_AURA_PERIODIC_DAMAGE, AURA_EFFECT_HANDLE_REAPPLY); +        AfterEffectApply += AuraEffectRemoveFn(spell_the_lich_king_necrotic_plague_jump_aura::AfterDispel, EFFECT_0, SPELL_AURA_PERIODIC_DAMAGE, AURA_EFFECT_HANDLE_REAPPLY); +    } + +    int32 _lastAmount; +}; -            bool Load() override -            { -                return GetCaster()->GetInstanceScript() != nullptr; -            } +class spell_the_lich_king_shadow_trap_visual : public AuraScript +{ +    PrepareAuraScript(spell_the_lich_king_shadow_trap_visual); + +    void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) +    { +        if (GetTargetApplication()->GetRemoveMode() == AURA_REMOVE_BY_EXPIRE) +            GetTarget()->CastSpell(GetTarget(), SPELL_SHADOW_TRAP_AURA, TRIGGERED_NONE); +    } + +    void Register() override +    { +        AfterEffectRemove += AuraEffectRemoveFn(spell_the_lich_king_shadow_trap_visual::OnRemove, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL); +    } +}; -            void FilterTargets(std::list<WorldObject*>& targets) -            { -                if (GameObject* platform = ObjectAccessor::GetGameObject(*GetCaster(), GetCaster()->GetInstanceScript()->GetGuidData(DATA_ARTHAS_PLATFORM))) -                    targets.remove_if(HeightDifferenceCheck(platform, 5.0f, false)); -            } +class spell_the_lich_king_shadow_trap_periodic : public SpellScript +{ +    PrepareSpellScript(spell_the_lich_king_shadow_trap_periodic); -            void HandleSendEvent(SpellEffIndex /*effIndex*/) -            { -                if (UnitAI* AI = GetCaster()->GetAI()) -                    AI->DoAction(ACTION_START_ATTACK); -            } +    void CheckTargetCount(std::list<WorldObject*>& targets) +    { +        if (targets.empty()) +            return; -            void Register() override -            { -                OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_the_lich_king_quake_SpellScript::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENTRY); -                OnEffectHit += SpellEffectFn(spell_the_lich_king_quake_SpellScript::HandleSendEvent, EFFECT_1, SPELL_EFFECT_SEND_EVENT); -            } -        }; +        GetCaster()->CastSpell(nullptr, SPELL_SHADOW_TRAP_KNOCKBACK, true); +    } -        SpellScript* GetSpellScript() const override -        { -            return new spell_the_lich_king_quake_SpellScript(); -        } +    void Register() override +    { +        OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_the_lich_king_shadow_trap_periodic::CheckTargetCount, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY); +    }  }; -class spell_the_lich_king_ice_burst_target_search : public SpellScriptLoader +class spell_the_lich_king_quake : public SpellScript  { -    public: -        spell_the_lich_king_ice_burst_target_search() : SpellScriptLoader("spell_the_lich_king_ice_burst_target_search") { } - -        class spell_the_lich_king_ice_burst_target_search_SpellScript : public SpellScript -        { -            PrepareSpellScript(spell_the_lich_king_ice_burst_target_search_SpellScript); - -            bool Validate(SpellInfo const* /*spell*/) override -            { -                return ValidateSpellInfo({ SPELL_ICE_BURST }); -            } +    PrepareSpellScript(spell_the_lich_king_quake); + +    bool Load() override +    { +        return GetCaster()->GetInstanceScript() != nullptr; +    } + +    void FilterTargets(std::list<WorldObject*>& targets) +    { +        if (GameObject* platform = ObjectAccessor::GetGameObject(*GetCaster(), GetCaster()->GetInstanceScript()->GetGuidData(DATA_ARTHAS_PLATFORM))) +            targets.remove_if(HeightDifferenceCheck(platform, 5.0f, false)); +    } + +    void HandleSendEvent(SpellEffIndex /*effIndex*/) +    { +        if (UnitAI* AI = GetCaster()->GetAI()) +            AI->DoAction(ACTION_START_ATTACK); +    } + +    void Register() override +    { +        OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_the_lich_king_quake::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENTRY); +        OnEffectHit += SpellEffectFn(spell_the_lich_king_quake::HandleSendEvent, EFFECT_1, SPELL_EFFECT_SEND_EVENT); +    } +}; -            void CheckTargetCount(std::list<WorldObject*>& unitList) -            { -                if (unitList.empty()) -                    return; +class spell_the_lich_king_ice_burst_target_search : public SpellScript +{ +    PrepareSpellScript(spell_the_lich_king_ice_burst_target_search); -                // if there is at least one affected target cast the explosion -                GetCaster()->CastSpell(GetCaster(), SPELL_ICE_BURST, true); -                if (GetCaster()->GetTypeId() == TYPEID_UNIT) -                { -                    GetCaster()->ToCreature()->SetReactState(REACT_PASSIVE); -                    GetCaster()->AttackStop(); -                    GetCaster()->ToCreature()->DespawnOrUnsummon(500ms); -                } -            } +    bool Validate(SpellInfo const* /*spell*/) override +    { +        return ValidateSpellInfo({ SPELL_ICE_BURST }); +    } -            void Register() override -            { -                OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_the_lich_king_ice_burst_target_search_SpellScript::CheckTargetCount, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY); -            } -        }; +    void CheckTargetCount(std::list<WorldObject*>& unitList) +    { +        if (unitList.empty()) +            return; -        SpellScript* GetSpellScript() const override +        // if there is at least one affected target cast the explosion +        GetCaster()->CastSpell(GetCaster(), SPELL_ICE_BURST, true); +        if (GetCaster()->GetTypeId() == TYPEID_UNIT)          { -            return new spell_the_lich_king_ice_burst_target_search_SpellScript(); +            GetCaster()->ToCreature()->SetReactState(REACT_PASSIVE); +            GetCaster()->AttackStop(); +            GetCaster()->ToCreature()->DespawnOrUnsummon(500ms);          } +    } + +    void Register() override +    { +        OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_the_lich_king_ice_burst_target_search::CheckTargetCount, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY); +    }  }; -class spell_the_lich_king_raging_spirit : public SpellScriptLoader +class spell_the_lich_king_raging_spirit : public SpellScript  { -    public: -        spell_the_lich_king_raging_spirit() : SpellScriptLoader("spell_the_lich_king_raging_spirit") { } - -        class spell_the_lich_king_raging_spirit_SpellScript : public SpellScript -        { -            PrepareSpellScript(spell_the_lich_king_raging_spirit_SpellScript); - -            void HandleScript(SpellEffIndex effIndex) -            { -                PreventHitDefaultEffect(effIndex); -                GetHitUnit()->CastSpell(GetHitUnit(), uint32(GetEffectValue()), true); -            } - -            void Register() override -            { -                OnEffectHitTarget += SpellEffectFn(spell_the_lich_king_raging_spirit_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT); -            } -        }; - -        SpellScript* GetSpellScript() const override -        { -            return new spell_the_lich_king_raging_spirit_SpellScript(); -        } +    PrepareSpellScript(spell_the_lich_king_raging_spirit); + +    void HandleScript(SpellEffIndex effIndex) +    { +        PreventHitDefaultEffect(effIndex); +        GetHitUnit()->CastSpell(GetHitUnit(), uint32(GetEffectValue()), true); +    } + +    void Register() override +    { +        OnEffectHitTarget += SpellEffectFn(spell_the_lich_king_raging_spirit::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT); +    }  };  class ExactDistanceCheck @@ -2483,807 +2258,565 @@ class ExactDistanceCheck          float _dist;  }; -class spell_the_lich_king_defile : public SpellScriptLoader +class spell_the_lich_king_defile : public SpellScript  { -    public: -        spell_the_lich_king_defile() : SpellScriptLoader("spell_the_lich_king_defile") { } - -        class spell_the_lich_king_defile_SpellScript : public SpellScript -        { -            PrepareSpellScript(spell_the_lich_king_defile_SpellScript); - -            void CorrectRange(std::list<WorldObject*>& targets) -            { -                targets.remove_if(ExactDistanceCheck(GetCaster(), 10.0f * GetCaster()->GetObjectScale())); -                targets.remove_if(Trinity::UnitAuraCheck(true, SPELL_HARVEST_SOUL_VALKYR)); -            } - -            void ChangeDamageAndGrow() -            { -                SetHitDamage(int32(GetHitDamage() * GetCaster()->GetObjectScale())); -                // HACK: target player should cast this spell on defile -                // however with current aura handling auras cast by different units -                // cannot stack on the same aura object increasing the stack count -                GetCaster()->CastSpell(GetCaster(), SPELL_DEFILE_GROW, true); -            } - -            void Register() override -            { -                OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_the_lich_king_defile_SpellScript::CorrectRange, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY); -                OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_the_lich_king_defile_SpellScript::CorrectRange, EFFECT_1, TARGET_UNIT_SRC_AREA_ENEMY); -                OnHit += SpellHitFn(spell_the_lich_king_defile_SpellScript::ChangeDamageAndGrow); -            } -        }; - -        SpellScript* GetSpellScript() const override -        { -            return new spell_the_lich_king_defile_SpellScript(); -        } +    PrepareSpellScript(spell_the_lich_king_defile); + +    void CorrectRange(std::list<WorldObject*>& targets) +    { +        targets.remove_if(ExactDistanceCheck(GetCaster(), 10.0f * GetCaster()->GetObjectScale())); +        targets.remove_if(Trinity::UnitAuraCheck(true, SPELL_HARVEST_SOUL_VALKYR)); +    } + +    void ChangeDamageAndGrow() +    { +        SetHitDamage(int32(GetHitDamage() * GetCaster()->GetObjectScale())); +        // HACK: target player should cast this spell on defile +        // however with current aura handling auras cast by different units +        // cannot stack on the same aura object increasing the stack count +        GetCaster()->CastSpell(GetCaster(), SPELL_DEFILE_GROW, true); +    } + +    void Register() override +    { +        OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_the_lich_king_defile::CorrectRange, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY); +        OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_the_lich_king_defile::CorrectRange, EFFECT_1, TARGET_UNIT_SRC_AREA_ENEMY); +        OnHit += SpellHitFn(spell_the_lich_king_defile::ChangeDamageAndGrow); +    }  }; -class spell_the_lich_king_summon_into_air : public SpellScriptLoader +class spell_the_lich_king_summon_into_air : public SpellScript  { -    public: -        spell_the_lich_king_summon_into_air() : SpellScriptLoader("spell_the_lich_king_summon_into_air") { } - -        class spell_the_lich_king_summon_into_air_SpellScript : public SpellScript -        { -            PrepareSpellScript(spell_the_lich_king_summon_into_air_SpellScript); - -            void ModDestHeight(SpellEffIndex effIndex) -            { -                static Position const offset = {0.0f, 0.0f, 15.0f, 0.0f}; -                WorldLocation* dest = const_cast<WorldLocation*>(GetExplTargetDest()); -                dest->RelocateOffset(offset); -                GetHitDest()->RelocateOffset(offset); -                // spirit bombs get higher -                if (GetSpellInfo()->Effects[effIndex].MiscValue == NPC_SPIRIT_BOMB) -                { -                    static Position const offsetExtra = { 0.0f, 0.0f, 5.0f, 0.0f }; -                    dest->RelocateOffset(offsetExtra); -                    GetHitDest()->RelocateOffset(offsetExtra); -                } -            } - -            void Register() override -            { -                OnEffectHit += SpellEffectFn(spell_the_lich_king_summon_into_air_SpellScript::ModDestHeight, EFFECT_0, SPELL_EFFECT_SUMMON); -            } -        }; - -        SpellScript* GetSpellScript() const override -        { -            return new spell_the_lich_king_summon_into_air_SpellScript(); +    PrepareSpellScript(spell_the_lich_king_summon_into_air); + +    void ModDestHeight(SpellEffIndex effIndex) +    { +        static Position const offset = {0.0f, 0.0f, 15.0f, 0.0f}; +        WorldLocation* dest = const_cast<WorldLocation*>(GetExplTargetDest()); +        dest->RelocateOffset(offset); +        GetHitDest()->RelocateOffset(offset); +        // spirit bombs get higher +        if (GetSpellInfo()->Effects[effIndex].MiscValue == NPC_SPIRIT_BOMB) +        { +            static Position const offsetExtra = { 0.0f, 0.0f, 5.0f, 0.0f }; +            dest->RelocateOffset(offsetExtra); +            GetHitDest()->RelocateOffset(offsetExtra);          } +    } + +    void Register() override +    { +        OnEffectHit += SpellEffectFn(spell_the_lich_king_summon_into_air::ModDestHeight, EFFECT_0, SPELL_EFFECT_SUMMON); +    }  }; -class spell_the_lich_king_soul_reaper : public SpellScriptLoader +class spell_the_lich_king_soul_reaper : public AuraScript  { -    public: -        spell_the_lich_king_soul_reaper() :  SpellScriptLoader("spell_the_lich_king_soul_reaper") { } - -        class spell_the_lich_king_soul_reaper_AuraScript : public AuraScript -        { -            PrepareAuraScript(spell_the_lich_king_soul_reaper_AuraScript); - -            bool Validate(SpellInfo const* /*spell*/) override -            { -                return ValidateSpellInfo({ SPELL_SOUL_REAPER_BUFF }); -            } - -            void OnPeriodic(AuraEffect const* /*aurEff*/) -            { -                if (Unit* caster = GetCaster()) -                    GetTarget()->CastSpell(caster, SPELL_SOUL_REAPER_BUFF, true); -            } - -            void Register() override -            { -                OnEffectPeriodic += AuraEffectPeriodicFn(spell_the_lich_king_soul_reaper_AuraScript::OnPeriodic, EFFECT_1, SPELL_AURA_PERIODIC_DAMAGE); -            } -        }; - -        AuraScript* GetAuraScript() const override -        { -            return new spell_the_lich_king_soul_reaper_AuraScript(); -        } +    PrepareAuraScript(spell_the_lich_king_soul_reaper); + +    bool Validate(SpellInfo const* /*spell*/) override +    { +        return ValidateSpellInfo({ SPELL_SOUL_REAPER_BUFF }); +    } + +    void OnPeriodic(AuraEffect const* /*aurEff*/) +    { +        if (Unit* caster = GetCaster()) +            GetTarget()->CastSpell(caster, SPELL_SOUL_REAPER_BUFF, true); +    } + +    void Register() override +    { +        OnEffectPeriodic += AuraEffectPeriodicFn(spell_the_lich_king_soul_reaper::OnPeriodic, EFFECT_1, SPELL_AURA_PERIODIC_DAMAGE); +    }  }; -class spell_the_lich_king_valkyr_target_search : public SpellScriptLoader +class spell_the_lich_king_valkyr_target_search : public SpellScript  { -    public: -        spell_the_lich_king_valkyr_target_search() : SpellScriptLoader("spell_the_lich_king_valkyr_target_search") { } - -        class spell_the_lich_king_valkyr_target_search_SpellScript : public SpellScript -        { -            PrepareSpellScript(spell_the_lich_king_valkyr_target_search_SpellScript); - -            bool Validate(SpellInfo const* /*spell*/) override -            { -                return ValidateSpellInfo({ SPELL_CHARGE }); -            } - -            void SelectTarget(std::list<WorldObject*>& targets) -            { -                if (targets.empty()) -                    return; - -                targets.remove_if(Trinity::UnitAuraCheck(true, GetSpellInfo()->Id)); -                if (targets.empty()) -                    return; - -                _target = Trinity::Containers::SelectRandomContainerElement(targets); -                targets.clear(); -                targets.push_back(_target); -                GetCaster()->GetAI()->SetGUID(_target->GetGUID()); -            } - -            void ReplaceTarget(std::list<WorldObject*>& targets) -            { -                targets.clear(); -                if (_target) -                    targets.push_back(_target); -            } - -            void HandleScript(SpellEffIndex effIndex) -            { -                PreventHitDefaultEffect(effIndex); -                GetCaster()->CastSpell(GetHitUnit(), SPELL_CHARGE, true); -            } - -            void Register() override -            { -                OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_the_lich_king_valkyr_target_search_SpellScript::SelectTarget, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY); -                OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_the_lich_king_valkyr_target_search_SpellScript::ReplaceTarget, EFFECT_1, TARGET_UNIT_SRC_AREA_ENEMY); -                OnEffectHitTarget += SpellEffectFn(spell_the_lich_king_valkyr_target_search_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT); -            } - -            WorldObject* _target = nullptr; -        }; - -        SpellScript* GetSpellScript() const override -        { -            return new spell_the_lich_king_valkyr_target_search_SpellScript(); -        } +    PrepareSpellScript(spell_the_lich_king_valkyr_target_search); + +    bool Validate(SpellInfo const* /*spell*/) override +    { +        return ValidateSpellInfo({ SPELL_CHARGE }); +    } + +    void SelectTarget(std::list<WorldObject*>& targets) +    { +        if (targets.empty()) +            return; + +        targets.remove_if(Trinity::UnitAuraCheck(true, GetSpellInfo()->Id)); +        if (targets.empty()) +            return; + +        _target = Trinity::Containers::SelectRandomContainerElement(targets); +        targets.clear(); +        targets.push_back(_target); +        GetCaster()->GetAI()->SetGUID(_target->GetGUID()); +    } + +    void ReplaceTarget(std::list<WorldObject*>& targets) +    { +        targets.clear(); +        if (_target) +            targets.push_back(_target); +    } + +    void HandleScript(SpellEffIndex effIndex) +    { +        PreventHitDefaultEffect(effIndex); +        GetCaster()->CastSpell(GetHitUnit(), SPELL_CHARGE, true); +    } + +    void Register() override +    { +        OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_the_lich_king_valkyr_target_search::SelectTarget, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY); +        OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_the_lich_king_valkyr_target_search::ReplaceTarget, EFFECT_1, TARGET_UNIT_SRC_AREA_ENEMY); +        OnEffectHitTarget += SpellEffectFn(spell_the_lich_king_valkyr_target_search::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT); +    } + +    WorldObject* _target = nullptr;  }; -class spell_the_lich_king_cast_back_to_caster : public SpellScriptLoader +class spell_the_lich_king_cast_back_to_caster : public SpellScript  { -    public: -        spell_the_lich_king_cast_back_to_caster() :  SpellScriptLoader("spell_the_lich_king_cast_back_to_caster") { } - -        class spell_the_lich_king_cast_back_to_caster_SpellScript : public SpellScript -        { -            PrepareSpellScript(spell_the_lich_king_cast_back_to_caster_SpellScript); - -            void HandleScript(SpellEffIndex /*effIndex*/) -            { -                GetHitUnit()->CastSpell(GetCaster(), uint32(GetEffectValue()), true); -            } +    PrepareSpellScript(spell_the_lich_king_cast_back_to_caster); -            void Register() override -            { -                OnEffectHitTarget += SpellEffectFn(spell_the_lich_king_cast_back_to_caster_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT); -            } -        }; +    void HandleScript(SpellEffIndex /*effIndex*/) +    { +        GetHitUnit()->CastSpell(GetCaster(), uint32(GetEffectValue()), true); +    } -        SpellScript* GetSpellScript() const override -        { -            return new spell_the_lich_king_cast_back_to_caster_SpellScript(); -        } +    void Register() override +    { +        OnEffectHitTarget += SpellEffectFn(spell_the_lich_king_cast_back_to_caster::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT); +    }  }; -class spell_the_lich_king_life_siphon : public SpellScriptLoader +class spell_the_lich_king_life_siphon : public SpellScript  { -    public: -        spell_the_lich_king_life_siphon() : SpellScriptLoader("spell_the_lich_king_life_siphon") { } - -        class spell_the_lich_king_life_siphon_SpellScript : public SpellScript -        { -            PrepareSpellScript(spell_the_lich_king_life_siphon_SpellScript); - -            bool Validate(SpellInfo const* /*spell*/) override -            { -                return ValidateSpellInfo({ SPELL_LIFE_SIPHON_HEAL }); -            } - -            void TriggerHeal() -            { -                CastSpellExtraArgs args(TRIGGERED_FULL_MASK); -                args.AddSpellBP0(GetHitDamage() * 10); -                GetHitUnit()->CastSpell(GetCaster(), SPELL_LIFE_SIPHON_HEAL, args); -            } - -            void Register() override -            { -                AfterHit += SpellHitFn(spell_the_lich_king_life_siphon_SpellScript::TriggerHeal); -            } -        }; - -        SpellScript* GetSpellScript() const override -        { -            return new spell_the_lich_king_life_siphon_SpellScript(); -        } +    PrepareSpellScript(spell_the_lich_king_life_siphon); + +    bool Validate(SpellInfo const* /*spell*/) override +    { +        return ValidateSpellInfo({ SPELL_LIFE_SIPHON_HEAL }); +    } + +    void TriggerHeal() +    { +        CastSpellExtraArgs args(TRIGGERED_FULL_MASK); +        args.AddSpellBP0(GetHitDamage() * 10); +        GetHitUnit()->CastSpell(GetCaster(), SPELL_LIFE_SIPHON_HEAL, args); +    } + +    void Register() override +    { +        AfterHit += SpellHitFn(spell_the_lich_king_life_siphon::TriggerHeal); +    }  }; -class spell_the_lich_king_vile_spirits : public SpellScriptLoader +class spell_the_lich_king_vile_spirits : public AuraScript  { -    public: -        spell_the_lich_king_vile_spirits() : SpellScriptLoader("spell_the_lich_king_vile_spirits") { } - -        class spell_the_lich_king_vile_spirits_AuraScript : public AuraScript -        { -            PrepareAuraScript(spell_the_lich_king_vile_spirits_AuraScript); - -        public: -            spell_the_lich_king_vile_spirits_AuraScript() -            { -                _is25Man = false; -            } - -        private: -            bool Load() override -            { -                _is25Man = GetUnitOwner()->GetMap()->Is25ManRaid(); -                return true; -            } - -            void OnPeriodic(AuraEffect const* aurEff) -            { -                if (_is25Man || ((aurEff->GetTickNumber() - 1) % 5)) -                    GetTarget()->CastSpell(nullptr, GetSpellInfo()->Effects[aurEff->GetEffIndex()].TriggerSpell, { aurEff, GetCasterGUID() }); -            } - -            void Register() override -            { -                OnEffectPeriodic += AuraEffectPeriodicFn(spell_the_lich_king_vile_spirits_AuraScript::OnPeriodic, EFFECT_0, SPELL_AURA_PERIODIC_DUMMY); -            } - -            bool _is25Man; -        }; - -        AuraScript* GetAuraScript() const override -        { -            return new spell_the_lich_king_vile_spirits_AuraScript(); -        } +    PrepareAuraScript(spell_the_lich_king_vile_spirits); + +public: +    spell_the_lich_king_vile_spirits() +    { +        _is25Man = false; +    } + +private: +    bool Load() override +    { +        _is25Man = GetUnitOwner()->GetMap()->Is25ManRaid(); +        return true; +    } + +    void OnPeriodic(AuraEffect const* aurEff) +    { +        if (_is25Man || ((aurEff->GetTickNumber() - 1) % 5)) +            GetTarget()->CastSpell(nullptr, GetSpellInfo()->Effects[aurEff->GetEffIndex()].TriggerSpell, { aurEff, GetCasterGUID() }); +    } + +    void Register() override +    { +        OnEffectPeriodic += AuraEffectPeriodicFn(spell_the_lich_king_vile_spirits::OnPeriodic, EFFECT_0, SPELL_AURA_PERIODIC_DUMMY); +    } + +    bool _is25Man;  }; -class spell_the_lich_king_vile_spirits_visual : public SpellScriptLoader +class spell_the_lich_king_vile_spirits_visual : public SpellScript  { -    public: -        spell_the_lich_king_vile_spirits_visual() : SpellScriptLoader("spell_the_lich_king_vile_spirits_visual") { } - -        class spell_the_lich_king_vile_spirits_visual_SpellScript : public SpellScript -        { -            PrepareSpellScript(spell_the_lich_king_vile_spirits_visual_SpellScript); - -            void ModDestHeight(SpellEffIndex /*effIndex*/) -            { -                Position offset = {0.0f, 0.0f, 15.0f, 0.0f}; -                const_cast<WorldLocation*>(GetExplTargetDest())->RelocateOffset(offset); -            } - -            void Register() override -            { -                OnEffectLaunch += SpellEffectFn(spell_the_lich_king_vile_spirits_visual_SpellScript::ModDestHeight, EFFECT_0, SPELL_EFFECT_DUMMY); -            } -        }; - -        SpellScript* GetSpellScript() const override -        { -            return new spell_the_lich_king_vile_spirits_visual_SpellScript(); -        } +    PrepareSpellScript(spell_the_lich_king_vile_spirits_visual); + +    void ModDestHeight(SpellEffIndex /*effIndex*/) +    { +        Position offset = {0.0f, 0.0f, 15.0f, 0.0f}; +        const_cast<WorldLocation*>(GetExplTargetDest())->RelocateOffset(offset); +    } + +    void Register() override +    { +        OnEffectLaunch += SpellEffectFn(spell_the_lich_king_vile_spirits_visual::ModDestHeight, EFFECT_0, SPELL_EFFECT_DUMMY); +    }  }; -class spell_the_lich_king_vile_spirit_move_target_search : public SpellScriptLoader +class spell_the_lich_king_vile_spirit_move_target_search : public SpellScript  { -    public: -        spell_the_lich_king_vile_spirit_move_target_search() : SpellScriptLoader("spell_the_lich_king_vile_spirit_move_target_search") { } - -        class spell_the_lich_king_vile_spirit_move_target_search_SpellScript : public SpellScript -        { -            PrepareSpellScript(spell_the_lich_king_vile_spirit_move_target_search_SpellScript); - -        public: -            spell_the_lich_king_vile_spirit_move_target_search_SpellScript() -            { -                _target = nullptr; -            } - -        private: -            bool Load() override -            { -                return GetCaster()->GetTypeId() == TYPEID_UNIT; -            } - -            void SelectTarget(std::list<WorldObject*>& targets) -            { -                if (targets.empty()) -                    return; - -                _target = Trinity::Containers::SelectRandomContainerElement(targets); -            } - -            void HandleScript(SpellEffIndex effIndex) -            { -                PreventHitDefaultEffect(effIndex); -                // for this spell, all units are in target map, however it should select one to attack -                if (GetHitUnit() != _target) -                    return; - -                GetCaster()->ToCreature()->AI()->AttackStart(GetHitUnit()); -                GetCaster()->GetThreatManager().AddThreat(GetHitUnit(), 100000.0f); -            } - -            void Register() override -            { -                OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_the_lich_king_vile_spirit_move_target_search_SpellScript::SelectTarget, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY); -                OnEffectHitTarget += SpellEffectFn(spell_the_lich_king_vile_spirit_move_target_search_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT); -            } - -            WorldObject* _target; -        }; - -        SpellScript* GetSpellScript() const override -        { -            return new spell_the_lich_king_vile_spirit_move_target_search_SpellScript(); -        } +    PrepareSpellScript(spell_the_lich_king_vile_spirit_move_target_search); + +public: +    spell_the_lich_king_vile_spirit_move_target_search() +    { +        _target = nullptr; +    } + +private: +    bool Load() override +    { +        return GetCaster()->GetTypeId() == TYPEID_UNIT; +    } + +    void SelectTarget(std::list<WorldObject*>& targets) +    { +        if (targets.empty()) +            return; + +        _target = Trinity::Containers::SelectRandomContainerElement(targets); +    } + +    void HandleScript(SpellEffIndex effIndex) +    { +        PreventHitDefaultEffect(effIndex); +        // for this spell, all units are in target map, however it should select one to attack +        if (GetHitUnit() != _target) +            return; + +        GetCaster()->ToCreature()->AI()->AttackStart(GetHitUnit()); +        GetCaster()->GetThreatManager().AddThreat(GetHitUnit(), 100000.0f); +    } + +    void Register() override +    { +        OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_the_lich_king_vile_spirit_move_target_search::SelectTarget, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY); +        OnEffectHitTarget += SpellEffectFn(spell_the_lich_king_vile_spirit_move_target_search::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT); +    } + +    WorldObject* _target;  }; -class spell_the_lich_king_vile_spirit_damage_target_search : public SpellScriptLoader +class spell_the_lich_king_vile_spirit_damage_target_search : public SpellScript  { -    public: -        spell_the_lich_king_vile_spirit_damage_target_search() : SpellScriptLoader("spell_the_lich_king_vile_spirit_damage_target_search") { } - -        class spell_the_lich_king_vile_spirit_damage_target_search_SpellScript : public SpellScript -        { -            PrepareSpellScript(spell_the_lich_king_vile_spirit_damage_target_search_SpellScript); - -            bool Load() override -            { -                return GetCaster()->GetTypeId() == TYPEID_UNIT; -            } - -            void CheckTargetCount(std::list<WorldObject*>& targets) -            { -                if (targets.empty()) -                    return; - -                // this spell has SPELL_AURA_BLOCK_SPELL_FAMILY so every next cast of this -                // searcher spell will be blocked -                if (TempSummon* summon = GetCaster()->ToTempSummon()) -                    if (Unit* summoner = summon->GetSummonerUnit()) -                        summoner->GetAI()->SetData(DATA_VILE, 1); -                GetCaster()->CastSpell(nullptr, SPELL_SPIRIT_BURST, true); -                GetCaster()->ToCreature()->DespawnOrUnsummon(3s); -                GetCaster()->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); -            } - -            void Register() override -            { -                OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_the_lich_king_vile_spirit_damage_target_search_SpellScript::CheckTargetCount, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY); -            } -        }; - -        SpellScript* GetSpellScript() const override -        { -            return new spell_the_lich_king_vile_spirit_damage_target_search_SpellScript(); -        } +    PrepareSpellScript(spell_the_lich_king_vile_spirit_damage_target_search); + +    bool Load() override +    { +        return GetCaster()->GetTypeId() == TYPEID_UNIT; +    } + +    void CheckTargetCount(std::list<WorldObject*>& targets) +    { +        if (targets.empty()) +            return; + +        // this spell has SPELL_AURA_BLOCK_SPELL_FAMILY so every next cast of this +        // searcher spell will be blocked +        if (TempSummon* summon = GetCaster()->ToTempSummon()) +            if (Unit* summoner = summon->GetSummonerUnit()) +                summoner->GetAI()->SetData(DATA_VILE, 1); +        GetCaster()->CastSpell(nullptr, SPELL_SPIRIT_BURST, true); +        GetCaster()->ToCreature()->DespawnOrUnsummon(3s); +        GetCaster()->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); +    } + +    void Register() override +    { +        OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_the_lich_king_vile_spirit_damage_target_search::CheckTargetCount, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY); +    }  }; -class spell_the_lich_king_harvest_soul : public SpellScriptLoader +class spell_the_lich_king_harvest_soul : public AuraScript  { -    public: -        spell_the_lich_king_harvest_soul() : SpellScriptLoader("spell_the_lich_king_harvest_soul") { } - -        class spell_the_lich_king_harvest_soul_AuraScript : public AuraScript -        { -            PrepareAuraScript(spell_the_lich_king_harvest_soul_AuraScript); - -            bool Load() override -            { -                return GetOwner()->GetInstanceScript() != nullptr; -            } - -            void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) -            { -                // m_originalCaster to allow stacking from different casters, meh -                if (GetTargetApplication()->GetRemoveMode() == AURA_REMOVE_BY_DEATH) -                    GetTarget()->CastSpell(nullptr, SPELL_HARVESTED_SOUL, GetTarget()->GetInstanceScript()->GetGuidData(DATA_THE_LICH_KING)); -            } - -            void Register() override -            { -                AfterEffectRemove += AuraEffectRemoveFn(spell_the_lich_king_harvest_soul_AuraScript::OnRemove, EFFECT_0, SPELL_AURA_PERIODIC_DAMAGE, AURA_EFFECT_HANDLE_REAL); -            } -        }; - -        AuraScript* GetAuraScript() const override -        { -            return new spell_the_lich_king_harvest_soul_AuraScript(); -        } +    PrepareAuraScript(spell_the_lich_king_harvest_soul); + +    bool Load() override +    { +        return GetOwner()->GetInstanceScript() != nullptr; +    } + +    void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) +    { +        // m_originalCaster to allow stacking from different casters, meh +        if (GetTargetApplication()->GetRemoveMode() == AURA_REMOVE_BY_DEATH) +            GetTarget()->CastSpell(nullptr, SPELL_HARVESTED_SOUL, GetTarget()->GetInstanceScript()->GetGuidData(DATA_THE_LICH_KING)); +    } + +    void Register() override +    { +        AfterEffectRemove += AuraEffectRemoveFn(spell_the_lich_king_harvest_soul::OnRemove, EFFECT_0, SPELL_AURA_PERIODIC_DAMAGE, AURA_EFFECT_HANDLE_REAL); +    }  }; -class spell_the_lich_king_lights_favor : public SpellScriptLoader +class spell_the_lich_king_lights_favor : public AuraScript  { -    public: -        spell_the_lich_king_lights_favor() : SpellScriptLoader("spell_the_lich_king_lights_favor") { } - -        class spell_the_lich_king_lights_favor_AuraScript : public AuraScript -        { -            PrepareAuraScript(spell_the_lich_king_lights_favor_AuraScript); - -            void OnPeriodic(AuraEffect const* /*aurEff*/) -            { -                if (Unit* caster = GetCaster()) -                    if (AuraEffect* effect = GetAura()->GetEffect(EFFECT_1)) -                        effect->RecalculateAmount(caster); -            } - -            void CalculateBonus(AuraEffect const* /*aurEff*/, int32& amount, bool& canBeRecalculated) -            { -                canBeRecalculated = true; -                amount = 0; -                if (Unit* caster = GetCaster()) -                    amount = int32(caster->GetHealthPct()); -            } - -            void Register() override -            { -                OnEffectPeriodic += AuraEffectPeriodicFn(spell_the_lich_king_lights_favor_AuraScript::OnPeriodic, EFFECT_0, SPELL_AURA_PERIODIC_HEAL); -                DoEffectCalcAmount += AuraEffectCalcAmountFn(spell_the_lich_king_lights_favor_AuraScript::CalculateBonus, EFFECT_1, SPELL_AURA_MOD_DAMAGE_PERCENT_DONE); -            } -        }; - -        AuraScript* GetAuraScript() const override -        { -            return new spell_the_lich_king_lights_favor_AuraScript(); -        } +    PrepareAuraScript(spell_the_lich_king_lights_favor); + +    void OnPeriodic(AuraEffect const* /*aurEff*/) +    { +        if (Unit* caster = GetCaster()) +            if (AuraEffect* effect = GetAura()->GetEffect(EFFECT_1)) +                effect->RecalculateAmount(caster); +    } + +    void CalculateBonus(AuraEffect const* /*aurEff*/, int32& amount, bool& canBeRecalculated) +    { +        canBeRecalculated = true; +        amount = 0; +        if (Unit* caster = GetCaster()) +            amount = int32(caster->GetHealthPct()); +    } + +    void Register() override +    { +        OnEffectPeriodic += AuraEffectPeriodicFn(spell_the_lich_king_lights_favor::OnPeriodic, EFFECT_0, SPELL_AURA_PERIODIC_HEAL); +        DoEffectCalcAmount += AuraEffectCalcAmountFn(spell_the_lich_king_lights_favor::CalculateBonus, EFFECT_1, SPELL_AURA_MOD_DAMAGE_PERCENT_DONE); +    }  }; -class spell_the_lich_king_soul_rip : public SpellScriptLoader +class spell_the_lich_king_soul_rip : public AuraScript  { -    public: -        spell_the_lich_king_soul_rip() : SpellScriptLoader("spell_the_lich_king_soul_rip") { } - -        class spell_the_lich_king_soul_rip_AuraScript : public AuraScript -        { -            PrepareAuraScript(spell_the_lich_king_soul_rip_AuraScript); - -            void OnPeriodic(AuraEffect const* aurEff) -            { -                PreventDefaultAction(); -                // shouldn't be needed, this is channeled -                if (Unit* caster = GetCaster()) -                { -                    CastSpellExtraArgs args(aurEff); -                    args.OriginalCaster = GetCasterGUID(); -                    args.AddSpellBP0(5000 * aurEff->GetTickNumber()); -                    caster->CastSpell(GetTarget(), SPELL_SOUL_RIP_DAMAGE, args); -                } -            } - -            void Register() override -            { -                OnEffectPeriodic += AuraEffectPeriodicFn(spell_the_lich_king_soul_rip_AuraScript::OnPeriodic, EFFECT_0, SPELL_AURA_PERIODIC_DUMMY); -            } -        }; - -        AuraScript* GetAuraScript() const override -        { -            return new spell_the_lich_king_soul_rip_AuraScript(); +    PrepareAuraScript(spell_the_lich_king_soul_rip); + +    void OnPeriodic(AuraEffect const* aurEff) +    { +        PreventDefaultAction(); +        // shouldn't be needed, this is channeled +        if (Unit* caster = GetCaster()) +        { +            CastSpellExtraArgs args(aurEff); +            args.OriginalCaster = GetCasterGUID(); +            args.AddSpellBP0(5000 * aurEff->GetTickNumber()); +            caster->CastSpell(GetTarget(), SPELL_SOUL_RIP_DAMAGE, args);          } +    } + +    void Register() override +    { +        OnEffectPeriodic += AuraEffectPeriodicFn(spell_the_lich_king_soul_rip::OnPeriodic, EFFECT_0, SPELL_AURA_PERIODIC_DUMMY); +    }  }; -class spell_the_lich_king_restore_soul : public SpellScriptLoader +class spell_the_lich_king_restore_soul : public SpellScript  { -    public: -        spell_the_lich_king_restore_soul() : SpellScriptLoader("spell_the_lich_king_restore_soul") { } - -        class spell_the_lich_king_restore_soul_SpellScript : public SpellScript -        { -            PrepareSpellScript(spell_the_lich_king_restore_soul_SpellScript); - -        public: -            spell_the_lich_king_restore_soul_SpellScript() -            { -                _instance = nullptr; -            } - -        private: -            bool Load() override -            { -                _instance = GetCaster()->GetInstanceScript(); -                return _instance != nullptr; -            } - -            void HandleScript(SpellEffIndex /*effIndex*/) -            { -                if (Creature* lichKing = ObjectAccessor::GetCreature(*GetCaster(), _instance->GetGuidData(DATA_THE_LICH_KING))) -                    lichKing->AI()->DoAction(ACTION_TELEPORT_BACK); -                if (Creature* spawner = GetCaster()->FindNearestCreature(NPC_WORLD_TRIGGER_INFINITE_AOI, 50.0f)) -                    spawner->RemoveAllAuras(); - -                std::list<Creature*> spirits; -                GetCaster()->GetCreatureListWithEntryInGrid(spirits, NPC_WICKED_SPIRIT, 200.0f); -                for (std::list<Creature*>::iterator itr = spirits.begin(); itr != spirits.end(); ++itr) -                { -                    (*itr)->m_Events.KillAllEvents(true); -                    (*itr)->SetReactState(REACT_PASSIVE); -                    (*itr)->AI()->EnterEvadeMode(); -                } -            } +    PrepareSpellScript(spell_the_lich_king_restore_soul); + +public: +    spell_the_lich_king_restore_soul() +    { +        _instance = nullptr; +    } + +private: +    bool Load() override +    { +        _instance = GetCaster()->GetInstanceScript(); +        return _instance != nullptr; +    } + +    void HandleScript(SpellEffIndex /*effIndex*/) +    { +        if (Creature* lichKing = ObjectAccessor::GetCreature(*GetCaster(), _instance->GetGuidData(DATA_THE_LICH_KING))) +            lichKing->AI()->DoAction(ACTION_TELEPORT_BACK); +        if (Creature* spawner = GetCaster()->FindNearestCreature(NPC_WORLD_TRIGGER_INFINITE_AOI, 50.0f)) +            spawner->RemoveAllAuras(); + +        std::list<Creature*> spirits; +        GetCaster()->GetCreatureListWithEntryInGrid(spirits, NPC_WICKED_SPIRIT, 200.0f); +        for (std::list<Creature*>::iterator itr = spirits.begin(); itr != spirits.end(); ++itr) +        { +            (*itr)->m_Events.KillAllEvents(true); +            (*itr)->SetReactState(REACT_PASSIVE); +            (*itr)->AI()->EnterEvadeMode(); +        } +    } -            void RemoveAura(SpellMissInfo missInfo) -            { -                if (missInfo != SPELL_MISS_NONE) -                    return; +    void RemoveAura(SpellMissInfo missInfo) +    { +        if (missInfo != SPELL_MISS_NONE) +            return; -                if (Unit* target = GetHitUnit()) -                    target->RemoveAurasDueToSpell(target->GetMap()->IsHeroic() ? SPELL_HARVEST_SOULS_TELEPORT : SPELL_HARVEST_SOUL_TELEPORT); -            } +        if (Unit* target = GetHitUnit()) +            target->RemoveAurasDueToSpell(target->GetMap()->IsHeroic() ? SPELL_HARVEST_SOULS_TELEPORT : SPELL_HARVEST_SOUL_TELEPORT); +    } -            void Register() override -            { -                OnEffectHit += SpellEffectFn(spell_the_lich_king_restore_soul_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_APPLY_AURA); -                BeforeHit += BeforeSpellHitFn(spell_the_lich_king_restore_soul_SpellScript::RemoveAura); -            } +    void Register() override +    { +        OnEffectHit += SpellEffectFn(spell_the_lich_king_restore_soul::HandleScript, EFFECT_0, SPELL_EFFECT_APPLY_AURA); +        BeforeHit += BeforeSpellHitFn(spell_the_lich_king_restore_soul::RemoveAura); +    } -            InstanceScript* _instance; -        }; - -        SpellScript* GetSpellScript() const override -        { -            return new spell_the_lich_king_restore_soul_SpellScript(); -        } +    InstanceScript* _instance;  }; -class spell_the_lich_king_dark_hunger : public SpellScriptLoader +class spell_the_lich_king_dark_hunger : public AuraScript  { -    public: -        spell_the_lich_king_dark_hunger() : SpellScriptLoader("spell_the_lich_king_dark_hunger") { } - -        class spell_the_lich_king_dark_hunger_AuraScript : public AuraScript -        { -            PrepareAuraScript(spell_the_lich_king_dark_hunger_AuraScript); - -            bool Validate(SpellInfo const* /*spellInfo*/) override -            { -                return ValidateSpellInfo({ SPELL_DARK_HUNGER_HEAL }); -            } - -            void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) -            { -                PreventDefaultAction(); -                DamageInfo* damageInfo = eventInfo.GetDamageInfo(); -                if (!damageInfo || !damageInfo->GetDamage()) -                    return; - -                CastSpellExtraArgs args(aurEff); -                args.AddSpellBP0(damageInfo->GetDamage() / 2); -                GetTarget()->CastSpell(GetTarget(), SPELL_DARK_HUNGER_HEAL, args); -            } - -            void Register() override -            { -                OnEffectProc += AuraEffectProcFn(spell_the_lich_king_dark_hunger_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); -            } -        }; - -        AuraScript* GetAuraScript() const override -        { -            return new spell_the_lich_king_dark_hunger_AuraScript(); -        } +    PrepareAuraScript(spell_the_lich_king_dark_hunger); + +    bool Validate(SpellInfo const* /*spellInfo*/) override +    { +        return ValidateSpellInfo({ SPELL_DARK_HUNGER_HEAL }); +    } + +    void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) +    { +        PreventDefaultAction(); +        DamageInfo* damageInfo = eventInfo.GetDamageInfo(); +        if (!damageInfo || !damageInfo->GetDamage()) +            return; + +        CastSpellExtraArgs args(aurEff); +        args.AddSpellBP0(damageInfo->GetDamage() / 2); +        GetTarget()->CastSpell(GetTarget(), SPELL_DARK_HUNGER_HEAL, args); +    } + +    void Register() override +    { +        OnEffectProc += AuraEffectProcFn(spell_the_lich_king_dark_hunger::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); +    }  }; -class spell_the_lich_king_in_frostmourne_room : public SpellScriptLoader +class spell_the_lich_king_in_frostmourne_room : public AuraScript  { -    public: -        spell_the_lich_king_in_frostmourne_room() : SpellScriptLoader("spell_the_lich_king_in_frostmourne_room") { } - -        class spell_the_lich_king_in_frostmourne_room_AuraScript : public AuraScript -        { -            PrepareAuraScript(spell_the_lich_king_in_frostmourne_room_AuraScript); - -            bool Load() override -            { -                return GetOwner()->GetInstanceScript() != nullptr; -            } - -            void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) -            { -                // m_originalCaster to allow stacking from different casters, meh -                if (GetTargetApplication()->GetRemoveMode() == AURA_REMOVE_BY_DEATH) -                    GetTarget()->CastSpell(nullptr, SPELL_HARVESTED_SOUL, GetTarget()->GetInstanceScript()->GetGuidData(DATA_THE_LICH_KING)); -            } - -            void Register() override -            { -                AfterEffectRemove += AuraEffectRemoveFn(spell_the_lich_king_in_frostmourne_room_AuraScript::OnRemove, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL); -            } -        }; - -        AuraScript* GetAuraScript() const override -        { -            return new spell_the_lich_king_in_frostmourne_room_AuraScript(); -        } +    PrepareAuraScript(spell_the_lich_king_in_frostmourne_room); + +    bool Load() override +    { +        return GetOwner()->GetInstanceScript() != nullptr; +    } + +    void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) +    { +        // m_originalCaster to allow stacking from different casters, meh +        if (GetTargetApplication()->GetRemoveMode() == AURA_REMOVE_BY_DEATH) +            GetTarget()->CastSpell(nullptr, SPELL_HARVESTED_SOUL, GetTarget()->GetInstanceScript()->GetGuidData(DATA_THE_LICH_KING)); +    } + +    void Register() override +    { +        AfterEffectRemove += AuraEffectRemoveFn(spell_the_lich_king_in_frostmourne_room::OnRemove, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL); +    }  }; -class spell_the_lich_king_summon_spirit_bomb : public SpellScriptLoader +class spell_the_lich_king_summon_spirit_bomb : public SpellScript  { -    public: -        spell_the_lich_king_summon_spirit_bomb() : SpellScriptLoader("spell_the_lich_king_summon_spirit_bomb") { } - -        class spell_the_lich_king_summon_spirit_bomb_SpellScript : public SpellScript -        { -            PrepareSpellScript(spell_the_lich_king_summon_spirit_bomb_SpellScript); - -            void HandleScript(SpellEffIndex effIndex) -            { -                PreventHitDefaultEffect(effIndex); -                GetHitUnit()->CastSpell(nullptr, uint32(GetEffectValue()), true); -            } - -            void Register() override -            { -                OnEffectHitTarget += SpellEffectFn(spell_the_lich_king_summon_spirit_bomb_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT); -            } -        }; - -        SpellScript* GetSpellScript() const override -        { -            return new spell_the_lich_king_summon_spirit_bomb_SpellScript(); -        } +    PrepareSpellScript(spell_the_lich_king_summon_spirit_bomb); + +    void HandleScript(SpellEffIndex effIndex) +    { +        PreventHitDefaultEffect(effIndex); +        GetHitUnit()->CastSpell(nullptr, uint32(GetEffectValue()), true); +    } + +    void Register() override +    { +        OnEffectHitTarget += SpellEffectFn(spell_the_lich_king_summon_spirit_bomb::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT); +    }  }; -class spell_the_lich_king_trigger_vile_spirit : public SpellScriptLoader +class spell_the_lich_king_trigger_vile_spirit : public SpellScript  { -    public: -        spell_the_lich_king_trigger_vile_spirit() : SpellScriptLoader("spell_the_lich_king_trigger_vile_spirit") { } +    PrepareSpellScript(spell_the_lich_king_trigger_vile_spirit); -        class spell_the_lich_king_trigger_vile_spirit_SpellScript : public SpellScript -        { -            PrepareSpellScript(spell_the_lich_king_trigger_vile_spirit_SpellScript); - -            void ActivateSpirit() -            { -                Creature* target = GetHitCreature(); -                if (!target) -                    return; - -                VileSpiritActivateEvent(target).Execute(0, 0); -            } +    void ActivateSpirit() +    { +        Creature* target = GetHitCreature(); +        if (!target) +            return; -            void Register() override -            { -                OnHit += SpellHitFn(spell_the_lich_king_trigger_vile_spirit_SpellScript::ActivateSpirit); -            } -        }; +        VileSpiritActivateEvent(target).Execute(0, 0); +    } -        SpellScript* GetSpellScript() const override -        { -            return new spell_the_lich_king_trigger_vile_spirit_SpellScript(); -        } +    void Register() override +    { +        OnHit += SpellHitFn(spell_the_lich_king_trigger_vile_spirit::ActivateSpirit); +    }  }; -class spell_the_lich_king_jump : public SpellScriptLoader +class spell_the_lich_king_jump : public SpellScript  { -    public: -        spell_the_lich_king_jump() : SpellScriptLoader("spell_the_lich_king_jump") { } - -        class spell_the_lich_king_jump_SpellScript : public SpellScript -        { -            PrepareSpellScript(spell_the_lich_king_jump_SpellScript); - -            void HandleScript(SpellEffIndex effIndex) -            { -                PreventHitDefaultEffect(effIndex); -                GetHitUnit()->RemoveAurasDueToSpell(SPELL_RAISE_DEAD); -                GetHitUnit()->CastSpell(nullptr, SPELL_JUMP_2, true); -                if (Creature* creature = GetHitCreature()) -                    creature->AI()->DoAction(ACTION_BREAK_FROSTMOURNE); -            } - -            void Register() override -            { -                OnEffectHitTarget += SpellEffectFn(spell_the_lich_king_jump_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT); -            } -        }; - -        SpellScript* GetSpellScript() const override -        { -            return new spell_the_lich_king_jump_SpellScript(); -        } +    PrepareSpellScript(spell_the_lich_king_jump); + +    void HandleScript(SpellEffIndex effIndex) +    { +        PreventHitDefaultEffect(effIndex); +        GetHitUnit()->RemoveAurasDueToSpell(SPELL_RAISE_DEAD); +        GetHitUnit()->CastSpell(nullptr, SPELL_JUMP_2, true); +        if (Creature* creature = GetHitCreature()) +            creature->AI()->DoAction(ACTION_BREAK_FROSTMOURNE); +    } + +    void Register() override +    { +        OnEffectHitTarget += SpellEffectFn(spell_the_lich_king_jump::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT); +    }  }; -class spell_the_lich_king_jump_remove_aura : public SpellScriptLoader +class spell_the_lich_king_jump_remove_aura : public SpellScript  { -    public: -        spell_the_lich_king_jump_remove_aura() : SpellScriptLoader("spell_the_lich_king_jump_remove_aura") { } - -        class spell_the_lich_king_jump_SpellScript : public SpellScript -        { -            PrepareSpellScript(spell_the_lich_king_jump_SpellScript); - -            void HandleScript(SpellEffIndex effIndex) -            { -                PreventHitDefaultEffect(effIndex); -                GetHitUnit()->RemoveAurasDueToSpell(uint32(GetEffectValue())); -            } - -            void Register() override -            { -                OnEffectHitTarget += SpellEffectFn(spell_the_lich_king_jump_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT); -            } -        }; - -        SpellScript* GetSpellScript() const override -        { -            return new spell_the_lich_king_jump_SpellScript(); -        } +    PrepareSpellScript(spell_the_lich_king_jump_remove_aura); + +    void HandleScript(SpellEffIndex effIndex) +    { +        PreventHitDefaultEffect(effIndex); +        GetHitUnit()->RemoveAurasDueToSpell(uint32(GetEffectValue())); +    } + +    void Register() override +    { +        OnEffectHitTarget += SpellEffectFn(spell_the_lich_king_jump_remove_aura::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT); +    }  }; -class spell_the_lich_king_play_movie : public SpellScriptLoader +class spell_the_lich_king_play_movie : public SpellScript  { -    public: -        spell_the_lich_king_play_movie() : SpellScriptLoader("spell_the_lich_king_play_movie") { } - -        class spell_the_lich_king_play_movie_SpellScript : public SpellScript -        { -            PrepareSpellScript(spell_the_lich_king_play_movie_SpellScript); - -            bool Validate(SpellInfo const* /*spell*/) override -            { -                if (!sMovieStore.LookupEntry(MOVIE_FALL_OF_THE_LICH_KING)) -                    return false; -                return true; -            } +    PrepareSpellScript(spell_the_lich_king_play_movie); -            void HandleScript(SpellEffIndex effIndex) -            { -                PreventHitDefaultEffect(effIndex); -                if (Player* player = GetHitPlayer()) -                    player->SendMovieStart(MOVIE_FALL_OF_THE_LICH_KING); -            } - -            void Register() override -            { -                OnEffectHitTarget += SpellEffectFn(spell_the_lich_king_play_movie_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT); -            } -        }; - -        SpellScript* GetSpellScript() const override -        { -            return new spell_the_lich_king_play_movie_SpellScript(); -        } +    bool Validate(SpellInfo const* /*spell*/) override +    { +        if (!sMovieStore.LookupEntry(MOVIE_FALL_OF_THE_LICH_KING)) +            return false; +        return true; +    } + +    void HandleScript(SpellEffIndex effIndex) +    { +        PreventHitDefaultEffect(effIndex); +        if (Player* player = GetHitPlayer()) +            player->SendMovieStart(MOVIE_FALL_OF_THE_LICH_KING); +    } + +    void Register() override +    { +        OnEffectHitTarget += SpellEffectFn(spell_the_lich_king_play_movie::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT); +    }  }; -class spell_the_lich_king_harvest_souls_teleport : public SpellScriptLoader +class spell_the_lich_king_harvest_souls_teleport : public SpellScript  { -    public: -        spell_the_lich_king_harvest_souls_teleport() : SpellScriptLoader("spell_the_lich_king_harvest_souls_teleport") { } - -        class spell_the_lich_king_harvest_souls_teleport_SpellScript : public SpellScript -        { -            PrepareSpellScript(spell_the_lich_king_harvest_souls_teleport_SpellScript); - -            void RelocateTransportOffset(SpellEffIndex /*effIndex*/) -            { -                float randCoordX = frand(-18.0f, 18.0f); -                float randCoordY = frand(-18.0f, 18.0f); -                GetHitDest()->RelocateOffset({ randCoordX, randCoordY, 0.0f, 0.0f }); -            } - -            void Register() override -            { -                OnEffectHitTarget += SpellEffectFn(spell_the_lich_king_harvest_souls_teleport_SpellScript::RelocateTransportOffset, EFFECT_1, SPELL_EFFECT_TELEPORT_UNITS); -            } -        }; - -        SpellScript* GetSpellScript() const override -        { -            return new spell_the_lich_king_harvest_souls_teleport_SpellScript(); -        } +    PrepareSpellScript(spell_the_lich_king_harvest_souls_teleport); + +    void RelocateTransportOffset(SpellEffIndex /*effIndex*/) +    { +        float randCoordX = frand(-18.0f, 18.0f); +        float randCoordY = frand(-18.0f, 18.0f); +        GetHitDest()->RelocateOffset({ randCoordX, randCoordY, 0.0f, 0.0f }); +    } + +    void Register() override +    { +        OnEffectHitTarget += SpellEffectFn(spell_the_lich_king_harvest_souls_teleport::RelocateTransportOffset, EFFECT_1, SPELL_EFFECT_TELEPORT_UNITS); +    }  };  class achievement_been_waiting_long_time : public AchievementCriteriaScript @@ -3316,47 +2849,52 @@ class achievement_neck_deep_in_vile : public AchievementCriteriaScript  void AddSC_boss_the_lich_king()  { -    new boss_the_lich_king(); -    new npc_tirion_fordring_tft(); -    new npc_shambling_horror_icc(); -    new npc_raging_spirit(); -    new npc_valkyr_shadowguard(); -    new npc_strangulate_vehicle(); -    new npc_terenas_menethil(); -    new npc_spirit_warden(); -    new npc_spirit_bomb(); -    new npc_broken_frostmourne(); -    new spell_the_lich_king_infest(); -    new spell_the_lich_king_necrotic_plague(); -    new spell_the_lich_king_necrotic_plague_jump(); -    new spell_the_lich_king_shadow_trap_visual(); -    new spell_the_lich_king_shadow_trap_periodic(); -    new spell_the_lich_king_quake(); -    new spell_the_lich_king_ice_burst_target_search(); -    new spell_the_lich_king_raging_spirit(); -    new spell_the_lich_king_defile(); -    new spell_the_lich_king_summon_into_air(); -    new spell_the_lich_king_soul_reaper(); -    new spell_the_lich_king_valkyr_target_search(); -    new spell_the_lich_king_cast_back_to_caster(); -    new spell_the_lich_king_life_siphon(); -    new spell_the_lich_king_vile_spirits(); -    new spell_the_lich_king_vile_spirits_visual(); -    new spell_the_lich_king_vile_spirit_move_target_search(); -    new spell_the_lich_king_vile_spirit_damage_target_search(); -    new spell_the_lich_king_harvest_soul(); -    new spell_the_lich_king_lights_favor(); -    new spell_the_lich_king_soul_rip(); -    new spell_the_lich_king_restore_soul(); -    new spell_the_lich_king_dark_hunger(); -    new spell_the_lich_king_in_frostmourne_room(); -    new spell_the_lich_king_summon_spirit_bomb(); -    new spell_the_lich_king_trigger_vile_spirit(); -    new spell_the_lich_king_jump(); -    new spell_the_lich_king_jump_remove_aura(); +    // Creatures +    RegisterIcecrownCitadelCreatureAI(boss_the_lich_king); +    RegisterIcecrownCitadelCreatureAI(npc_tirion_fordring_tft); +    RegisterIcecrownCitadelCreatureAI(npc_shambling_horror_icc); +    RegisterIcecrownCitadelCreatureAI(npc_raging_spirit); +    RegisterIcecrownCitadelCreatureAI(npc_valkyr_shadowguard); +    RegisterIcecrownCitadelCreatureAI(npc_strangulate_vehicle); +    RegisterIcecrownCitadelCreatureAI(npc_terenas_menethil); +    RegisterIcecrownCitadelCreatureAI(npc_spirit_warden); +    RegisterIcecrownCitadelCreatureAI(npc_spirit_bomb); +    RegisterIcecrownCitadelCreatureAI(npc_broken_frostmourne); + +    // Spells +    RegisterSpellScript(spell_the_lich_king_infest); +    RegisterSpellScript(spell_the_lich_king_necrotic_plague); +    RegisterSpellAndAuraScriptPair(spell_the_lich_king_necrotic_plague_jump, spell_the_lich_king_necrotic_plague_jump_aura); +    RegisterSpellScript(spell_the_lich_king_shadow_trap_visual); +    RegisterSpellScript(spell_the_lich_king_shadow_trap_periodic); +    RegisterSpellScript(spell_the_lich_king_quake); +    RegisterSpellScript(spell_the_lich_king_ice_burst_target_search); +    RegisterSpellScript(spell_the_lich_king_raging_spirit); +    RegisterSpellScript(spell_the_lich_king_defile); +    RegisterSpellScript(spell_the_lich_king_summon_into_air); +    RegisterSpellScript(spell_the_lich_king_soul_reaper); +    RegisterSpellScript(spell_the_lich_king_valkyr_target_search); +    RegisterSpellScript(spell_the_lich_king_cast_back_to_caster); +    RegisterSpellScript(spell_the_lich_king_life_siphon); +    RegisterSpellScript(spell_the_lich_king_vile_spirits); +    RegisterSpellScript(spell_the_lich_king_vile_spirits_visual); +    RegisterSpellScript(spell_the_lich_king_vile_spirit_move_target_search); +    RegisterSpellScript(spell_the_lich_king_vile_spirit_damage_target_search); +    RegisterSpellScript(spell_the_lich_king_harvest_soul); +    RegisterSpellScript(spell_the_lich_king_lights_favor); +    RegisterSpellScript(spell_the_lich_king_soul_rip); +    RegisterSpellScript(spell_the_lich_king_restore_soul); +    RegisterSpellScript(spell_the_lich_king_dark_hunger); +    RegisterSpellScript(spell_the_lich_king_in_frostmourne_room); +    RegisterSpellScript(spell_the_lich_king_summon_spirit_bomb); +    RegisterSpellScript(spell_the_lich_king_trigger_vile_spirit); +    RegisterSpellScript(spell_the_lich_king_jump); +    RegisterSpellScript(spell_the_lich_king_jump_remove_aura);      new spell_trigger_spell_from_caster("spell_the_lich_king_mass_resurrection", SPELL_MASS_RESURRECTION_REAL); -    new spell_the_lich_king_play_movie(); -    new spell_the_lich_king_harvest_souls_teleport(); +    RegisterSpellScript(spell_the_lich_king_play_movie); +    RegisterSpellScript(spell_the_lich_king_harvest_souls_teleport); + +    // Achievements      new achievement_been_waiting_long_time();      new achievement_neck_deep_in_vile();  }  | 
