diff options
| author | Keader <keader.android@gmail.com> | 2016-12-13 10:55:22 -0200 | 
|---|---|---|
| committer | DoctorKraft <DoctorKraft@users.noreply.github.com> | 2018-03-12 16:39:40 +0100 | 
| commit | 0449d3a83657436a3379c62d11259f3c83b4a431 (patch) | |
| tree | 3306d234fe7fc73ee61e3faebb5b734c2acecf69 /src/server/scripts | |
| parent | e560374b8bab633981727cbfddb66bc2303e9bdb (diff) | |
Core/Scripts: Reliquary of Souls Rewrite
(cherry picked from commit 02f18419f58dc952cd209c97f641269bea6bd1fc)
Update boss_reliquary_of_souls.cpp
(cherry picked from commit ff6c48732da63bfac6987203b94f343cbca74fb7)
Core/Scripts: Fixed Reliquary of Souls Boundary (#18470)
Followup 02f18419f58dc952cd209c97f641269bea6bd1fc
(cherry picked from commit 4582cfcecdf65b44222cf84e9a9fdc5b717191ec)
Diffstat (limited to 'src/server/scripts')
5 files changed, 749 insertions, 501 deletions
diff --git a/src/server/scripts/Outland/BlackTemple/black_temple.cpp b/src/server/scripts/Outland/BlackTemple/black_temple.cpp index e63cf46a1d0..c364cfa925d 100644 --- a/src/server/scripts/Outland/BlackTemple/black_temple.cpp +++ b/src/server/scripts/Outland/BlackTemple/black_temple.cpp @@ -19,28 +19,39 @@  #include "black_temple.h"  #include "ObjectAccessor.h"  #include "ScriptedCreature.h" +#include "SpellScript.h" +#include "SpellAuraEffects.h"  enum Spells  {      // Wrathbone Flayer -    SPELL_CLEAVE                     = 15496, -    SPELL_IGNORED                    = 39544, -    SPELL_SUMMON_CHANNEL             = 40094 +    SPELL_CLEAVE                = 15496, +    SPELL_IGNORED               = 39544, +    SPELL_SUMMON_CHANNEL        = 40094, + +    // Angered Soul Fragment +    SPELL_GREATER_INVISIBILITY  = 41253, +    SPELL_ANGER                 = 41986  };  enum Creatures  { -    NPC_BLOOD_MAGE                   = 22945, -    NPC_DEATHSHAPER                  = 22882 +    NPC_BLOOD_MAGE               = 22945, +    NPC_DEATHSHAPER              = 22882  };  enum Events  {      // Wrathbone Flayer -    EVENT_GET_CHANNELERS             = 1, -    EVENT_SET_CHANNELERS             = 2, -    EVENT_CLEAVE                     = 3, -    EVENT_IGNORED                    = 4, +    EVENT_GET_CHANNELERS = 1, +    EVENT_SET_CHANNELERS, +    EVENT_CLEAVE, +    EVENT_IGNORED +}; + +enum Misc +{ +    GROUP_OUT_OF_COMBAT = 1  };  // ######################################################## @@ -179,7 +190,102 @@ public:      }  }; +class npc_angered_soul_fragment : public CreatureScript +{ +public: +    npc_angered_soul_fragment() : CreatureScript("npc_angered_soul_fragment") { } + +    struct npc_angered_soul_fragmentAI : public ScriptedAI +    { +        npc_angered_soul_fragmentAI(Creature* creature) : ScriptedAI(creature) { } + +        void Reset() override +        { +            _scheduler.CancelAll(); + +            _scheduler.Schedule(Seconds(1), GROUP_OUT_OF_COMBAT, [this](TaskContext invi) +            { +                DoCastSelf(SPELL_GREATER_INVISIBILITY); + +                /* Workaround - On Retail creature appear and "vanish" again periodically, but i cant find packets +                with UPDATE_AURA on sniffs about it */ +                _scheduler.Schedule(Seconds(5), Seconds(10), GROUP_OUT_OF_COMBAT, [this](TaskContext /*context*/) +                { +                    me->RemoveAurasDueToSpell(SPELL_GREATER_INVISIBILITY); +                }); + +                invi.Repeat(Seconds(15), Seconds(25)); +            }); +        } + +        void EnterCombat(Unit* /*who*/) override +        { +            me->RemoveAurasDueToSpell(SPELL_GREATER_INVISIBILITY); + +            _scheduler.CancelGroup(GROUP_OUT_OF_COMBAT); +            _scheduler.Schedule(Seconds(1), [this](TaskContext anger) +            { +                Unit* target = me->GetVictim(); +                if (target && me->IsWithinMeleeRange(target)) +                    DoCastSelf(SPELL_ANGER); +                else +                    anger.Repeat(Seconds(1)); +            }); +        } + +        void UpdateAI(uint32 diff) override +        { +            _scheduler.Update(diff); + +            if (!UpdateVictim()) +                return; + +            if (me->HasUnitState(UNIT_STATE_CASTING)) +                return; + +            DoMeleeAttackIfReady(); +        } + +    private: +        TaskScheduler _scheduler; +    }; + +    CreatureAI* GetAI(Creature* creature) const override +    { +        return GetBlackTempleAI<npc_angered_soul_fragmentAI>(creature); +    } +}; + +class spell_soul_fragment_anger : public SpellScriptLoader +{ +    public: +        spell_soul_fragment_anger() : SpellScriptLoader("spell_soul_fragment_anger") { } + +        class spell_soul_fragment_anger_SpellScript : public SpellScript +        { +            PrepareSpellScript(spell_soul_fragment_anger_SpellScript); + +            void HandleKill() +            { +                if (Creature* caster = GetCaster()->ToCreature()) +                    caster->DespawnOrUnsummon(Milliseconds(200)); +            } + +            void Register() override +            { +                AfterCast += SpellCastFn(spell_soul_fragment_anger_SpellScript::HandleKill); +            } +        }; + +        SpellScript* GetSpellScript() const override +        { +            return new spell_soul_fragment_anger_SpellScript(); +        } +}; +  void AddSC_black_temple()  {      new npc_wrathbone_flayer(); +    new npc_angered_soul_fragment(); +    new spell_soul_fragment_anger();  } diff --git a/src/server/scripts/Outland/BlackTemple/black_temple.h b/src/server/scripts/Outland/BlackTemple/black_temple.h index 01ee93ffa1f..05bd99e61df 100644 --- a/src/server/scripts/Outland/BlackTemple/black_temple.h +++ b/src/server/scripts/Outland/BlackTemple/black_temple.h @@ -49,8 +49,13 @@ enum BTDataTypes      DATA_BLOOD_ELF_COUNCIL_VOICE    = 15,      DATA_GO_ILLIDAN_GATE            = 16, +      DATA_BLACK_TEMPLE_TRIGGER       = 17, -    DATA_GO_DEN_OF_MORTAL_DOOR      = 18 +    DATA_GO_DEN_OF_MORTAL_DOOR      = 18, + +    DATA_ESSENCE_OF_SUFFERING       = 19, +    DATA_ESSENCE_OF_DESIRE          = 20, +    DATA_ESSENCE_OF_ANGER           = 21  };  enum TriggerEmotes @@ -81,7 +86,9 @@ enum BTCreatureIds      NPC_AKAMA                       = 23089, // This is the Akama that starts the Illidan encounter.      NPC_AKAMA_SHADE                 = 23191, // This is the Akama that starts the Shade of Akama encounter.      NPC_SUPREMUS_VOLCANO            = 23085, -    NPC_BLACK_TEMPLE_TRIGGER        = 22984 +    NPC_BLACK_TEMPLE_TRIGGER        = 22984, +    NPC_RELIQUARY_WORLD_TRIGGER     = 23472, +    NPC_ENSLAVED_SOUL               = 23469  };  enum BTGameObjectIds diff --git a/src/server/scripts/Outland/BlackTemple/boss_reliquary_of_souls.cpp b/src/server/scripts/Outland/BlackTemple/boss_reliquary_of_souls.cpp index d239cb4f65a..84627de47f5 100644 --- a/src/server/scripts/Outland/BlackTemple/boss_reliquary_of_souls.cpp +++ b/src/server/scripts/Outland/BlackTemple/boss_reliquary_of_souls.cpp @@ -1,6 +1,5 @@  /*   * Copyright (C) 2008-2018 TrinityCore <https://www.trinitycore.org/> - * Copyright (C) 2006-2009 ScriptDev2 <https://scriptdev2.svn.sourceforge.net/>   *   * This program is free software; you can redistribute it and/or modify it   * under the terms of the GNU General Public License as published by the @@ -16,13 +15,6 @@   * with this program. If not, see <http://www.gnu.org/licenses/>.   */ -/* ScriptData -SDName: Boss_Reliquary_of_Souls -SD%Complete: 90 -SDComment: -SDCategory: Black Temple -EndScriptData */ -  #include "ScriptMgr.h"  #include "black_temple.h"  #include "MotionMaster.h" @@ -31,102 +23,119 @@ EndScriptData */  #include "Spell.h"  #include "SpellInfo.h"  #include "TemporarySummon.h" +#include "SpellScript.h" +#include "SpellAuraEffects.h" +#include "Player.h" -enum ReliquaryOfSouls +enum Says  { -    //Sound'n'speech -    //Suffering -    SUFF_SAY_FREED                  = 0, -    SUFF_SAY_AGGRO                  = 1, -    SUFF_SAY_SLAY                   = 2, -    SUFF_SAY_RECAP                  = 3, -    SUFF_SAY_AFTER                  = 4, -    SUFF_EMOTE_ENRAGE               = 5, - -    //Desire -    DESI_SAY_FREED                  = 0, -    DESI_SAY_SLAY                   = 1, -    DESI_SAY_SPEC                   = 2, -    DESI_SAY_RECAP                  = 3, -    DESI_SAY_AFTER                  = 4, - -    //Anger -    ANGER_SAY_FREED                 = 0, -    ANGER_SAY_SLAY                  = 1, -    ANGER_SAY_SPEC                  = 2, -    ANGER_SAY_BEFORE                = 3, -    ANGER_SAY_DEATH                 = 4, - -    //Spells -    AURA_OF_SUFFERING               = 41292, -    AURA_OF_SUFFERING_ARMOR         = 42017, // linked aura, need core support -    ESSENCE_OF_SUFFERING_PASSIVE    = 41296, // periodic trigger 41294 -    ESSENCE_OF_SUFFERING_PASSIVE2   = 41623, -    SPELL_FIXATE_TARGET             = 41294, // dummy, select target -    SPELL_FIXATE_TAUNT              = 41295, // force taunt -    SPELL_ENRAGE                    = 41305, -    SPELL_SOUL_DRAIN                = 41303, - -    AURA_OF_DESIRE                  = 41350, -    AURA_OF_DESIRE_DAMAGE           = 41352, -    SPELL_RUNE_SHIELD               = 41431, -    SPELL_DEADEN                    = 41410, -    SPELL_SOUL_SHOCK                = 41426, - -    AURA_OF_ANGER                   = 41337, -    SPELL_SELF_SEETHE               = 41364, // force cast 41520 -    SPELL_ENEMY_SEETHE              = 41520, -    SPELL_SOUL_SCREAM               = 41545, -    SPELL_SPITE_TARGET              = 41376, // cast 41377 after 6 sec -    SPELL_SPITE_DAMAGE              = 41377, - -    ENSLAVED_SOUL_PASSIVE           = 41535, -    SPELL_SOUL_RELEASE              = 41542, -    SPELL_SUBMERGE                  = 37550, //dropout 'head' - -    CREATURE_ENSLAVED_SOUL          = 23469, -    NUMBER_ENSLAVED_SOUL            = 8 +    // Essence of Suffering +    SUFF_SAY_AGRO       = 0, +    SUFF_SAY_SLAY       = 1, +    SUFF_SAY_ENRAGE     = 2, +    SUFF_SAY_RECAP      = 3, +    //SUFF_SAY_AFTER    = 4, +    SUFF_EMOTE_ENRAGE   = 5, + +    // Essence of Desire +    DESI_SAY_FREED      = 0, +    DESI_SAY_SLAY       = 1, +    DESI_SAY_SPEC       = 2, +    DESI_SAY_RECAP      = 3, +    //DESI_SAY_AFTER    = 4, + +    // Essence of Anger +    ANGER_SAY_FREED     = 0, +    ANGER_SAY_FREED_2   = 1, +    ANGER_SAY_SEETHE    = 2, +    ANGER_EMOTE_SEETHE  = 3, +    //ANGER_SAY_SPEC    = 4, +    ANGER_SAY_SPITE     = 5, +    //ANGER_SAY_DEATH   = 6  }; -Position const Coords[]= +enum Spells  { -    {450.4f, 212.3f}, -    {542.1f, 212.3f}, -    {542.1f, 168.3f}, -    {542.1f, 137.4f}, -    {450.4f, 137.4f}, -    {450.4f, 168.3f} +    // Reliquary +    SPELL_SUMMON_ESSENCE_OF_SUFFERING   = 41488, +    SPELL_SUBMERGE_VISUAL               = 28819, +    SPELL_SUMMON_ESSENCE_OF_DESIRE      = 41493, +    SPELL_SUMMON_ESSENCE_OF_ANGER       = 41496, + +    // Essence of Suffering +    SPELL_AURA_OF_SUFFERING             = 41292, +    SPELL_SOUL_DRAIN                    = 41303, +    SPELL_FRENZY                        = 41305, + +    // Essence of Desire +    SPELL_AURA_OF_DESIRE                = 41350, +    SPELL_SPIRIT_SHOCK                  = 41426, +    SPELL_RUNE_SHIELD                   = 41431, +    SPELL_DEADEN                        = 41410, +    SPELL_AURA_OF_DESIRE_DAMAGE         = 41352, + +    // Essence of Anger +    SPELL_AURA_OF_ANGER                 = 41337, +    SPELL_SOUL_SCREAM                   = 41545, +    SPELL_SPITE                         = 41376, +    SPELL_SPITE_DAMAGE                  = 41377, +    SPELL_SEETHE                        = 41364, + +    // Enslaved Soul +    SPELL_ENSLAVED_SOUL_PASSIVE         = 41535, +    SPELL_SOUL_RELEASE                  = 41542, + +    // World Trigger +    SUMMON_ENSLAVED_SOUL                = 41538  }; -class npc_enslaved_soul : public CreatureScript +enum Misc  { -public: -    npc_enslaved_soul() : CreatureScript("npc_enslaved_soul") { } +    RELIQUARY_DESPAWN_WAYPOINT = 0, +    ACTION_ESSENCE_OF_SUFFERING_DEAD, +    ACTION_ESSENCE_OF_DESIRE_DEAD, +    ACTION_KILL_SELF, +    ANGER_SOUND_ID_DEATH       = 11401 +}; -    CreatureAI* GetAI(Creature* creature) const override -    { -        return GetBlackTempleAI<npc_enslaved_soulAI>(creature); -    } +enum Phases +{ +    PHASE_ESSENCE_OF_SUFFERING = 1, +    PHASE_ESSENCE_OF_DESIRE, +    PHASE_ESSENCE_OF_ANGER +}; -    struct npc_enslaved_soulAI : public ScriptedAI -    { -        npc_enslaved_soulAI(Creature* creature) : ScriptedAI(creature) { } +enum Events +{ +    EVENT_SUBMERGE = 1, +    EVENT_SUMMON_ESSENCE, +    EVENT_DESPAWN, +    EVENT_SOUL_DRAIN, +    EVENT_FRENZY, +    EVENT_SPIRIT_SHOCK, +    EVENT_RUNE_SHIELD, +    EVENT_DEADEN, +    EVENT_SOUL_SCREAM, +    EVENT_SPITE, +    EVENT_CHECK_TANKER, +    EVENT_START_CHECK_TANKER, +    EVENT_FREED_2 +}; -        ObjectGuid ReliquaryGUID; +Position const DespawnPoint = { 497.4939f, 183.2081f, 94.53341f }; -        void Reset() override -        { -            ReliquaryGUID.Clear(); -        } +class EnslavedSoulEvent : public BasicEvent +{ +    public: explicit EnslavedSoulEvent(Creature* owner) : _owner(owner) { } -        void EnterCombat(Unit* /*who*/) override +        bool Execute(uint64 /*time*/, uint32 /*diff*/) override          { -            DoCast(me, ENSLAVED_SOUL_PASSIVE, true); -            DoZoneInCombat(); +            _owner->CastSpell(_owner, SUMMON_ENSLAVED_SOUL, true); +            return true;          } -        void JustDied(Unit* /*killer*/) override; -    }; +    private: +        Creature* _owner;  };  class boss_reliquary_of_souls : public CreatureScript @@ -134,288 +143,200 @@ class boss_reliquary_of_souls : public CreatureScript  public:      boss_reliquary_of_souls() : CreatureScript("boss_reliquary_of_souls") { } -    CreatureAI* GetAI(Creature* creature) const override -    { -        return GetBlackTempleAI<boss_reliquary_of_soulsAI>(creature); -    } -      struct boss_reliquary_of_soulsAI : public BossAI      { -        boss_reliquary_of_soulsAI(Creature* creature) : BossAI(creature, DATA_RELIQUARY_OF_SOULS) +        boss_reliquary_of_soulsAI(Creature* creature) : BossAI(creature, DATA_RELIQUARY_OF_SOULS), _inCombat(false)          { -            Initialize(); -            Counter = 0; -            Timer = 0; -            SoulCount = 0; -            SoulDeathCount = 0; +            creature->m_SightDistance = 70.0f;          } -        void Initialize() -        { -            Phase = 0; -        } - -        ObjectGuid EssenceGUID; - -        uint32 Phase; -        uint32 Counter; -        uint32 Timer; - -        uint32 SoulCount; -        uint32 SoulDeathCount; -          void Reset() override          {              _Reset(); +            me->SetReactState(REACT_PASSIVE); +            _inCombat = false; +            events.SetPhase(PHASE_ESSENCE_OF_SUFFERING); +        } -            if (!EssenceGUID.IsEmpty()) +        void MoveInLineOfSight(Unit* who) override +        { +            if (!_inCombat && who->GetTypeId() == TYPEID_PLAYER && !who->ToPlayer()->IsGameMaster() && CanAIAttack(who))              { -                if (Creature* essence = ObjectAccessor::GetCreature(*me, EssenceGUID)) -                    essence->DespawnOrUnsummon(); - -                EssenceGUID.Clear(); +                _inCombat = true; +                DoZoneInCombat(); +                me->SetByteValue(UNIT_FIELD_BYTES_1, UNIT_BYTES_1_OFFSET_STAND_STATE, UNIT_STAND_STATE_STAND); +                events.ScheduleEvent(EVENT_SUBMERGE, Seconds(10));              } +        } -            Initialize(); - -            me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); -            me->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_ONESHOT_NONE); -            me->RemoveAurasDueToSpell(SPELL_SUBMERGE); +        uint32 GetSummonSpell() +        { +            if (events.IsInPhase(PHASE_ESSENCE_OF_SUFFERING)) +                return SPELL_SUMMON_ESSENCE_OF_SUFFERING; +            else if (events.IsInPhase(PHASE_ESSENCE_OF_DESIRE)) +                return SPELL_SUMMON_ESSENCE_OF_DESIRE; +            else if (events.IsInPhase(PHASE_ESSENCE_OF_ANGER)) +                return SPELL_SUMMON_ESSENCE_OF_ANGER; +            else //Should never happen +                return 0;          } -        void MoveInLineOfSight(Unit* who) override +        void DoAction(int32 actionId) override          { -            if (!who) -                return; +            switch (actionId) +            { +                case ACTION_ESSENCE_OF_SUFFERING_DEAD: +                    me->RemoveAurasDueToSpell(SPELL_SUBMERGE_VISUAL); +                    events.SetPhase(PHASE_ESSENCE_OF_DESIRE); +                    HandleSpirits(); +                    events.ScheduleEvent(EVENT_SUBMERGE, Seconds(40)); +                    break; +                case ACTION_ESSENCE_OF_DESIRE_DEAD: +                    me->RemoveAurasDueToSpell(SPELL_SUBMERGE_VISUAL); +                    events.SetPhase(PHASE_ESSENCE_OF_ANGER); +                    HandleSpirits(); +                    events.ScheduleEvent(EVENT_SUBMERGE, Seconds(40)); +                    break; +                case ACTION_KILL_SELF: +                    me->KillSelf(); +                    break; +            } +        } -            if (me->IsInCombat()) -                return; +        void HandleSpirits() +        { +            std::vector<Creature*> _worldTriggerList; +            me->GetCreatureListWithEntryInGrid(_worldTriggerList, NPC_RELIQUARY_WORLD_TRIGGER, 70.0f); -            if (who->GetTypeId() != TYPEID_PLAYER) +            if (_worldTriggerList.empty())                  return; -            if (me->GetDistance(who) > 50.0f) -                return; +            //Get random creatures +            Trinity::Containers::RandomShuffle(_worldTriggerList); +            _worldTriggerList.resize(21); -            AttackStartNoMove(who); +            for (uint8 i = 0; i < 21; i++) +            { +                Creature* wTrigger = _worldTriggerList[i]; +                if (i < 3) +                    wTrigger->m_Events.AddEvent(new EnslavedSoulEvent(wTrigger), wTrigger->m_Events.CalculateTime(4000)); +                else if (i < 6) +                    wTrigger->m_Events.AddEvent(new EnslavedSoulEvent(wTrigger), wTrigger->m_Events.CalculateTime(8000)); +                else if (i < 9) +                    wTrigger->m_Events.AddEvent(new EnslavedSoulEvent(wTrigger), wTrigger->m_Events.CalculateTime(12000)); +                else if (i < 12) +                    wTrigger->m_Events.AddEvent(new EnslavedSoulEvent(wTrigger), wTrigger->m_Events.CalculateTime(16000)); +                else if (i < 15) +                    wTrigger->m_Events.AddEvent(new EnslavedSoulEvent(wTrigger), wTrigger->m_Events.CalculateTime(20000)); +                else if (i < 18) +                    wTrigger->m_Events.AddEvent(new EnslavedSoulEvent(wTrigger), wTrigger->m_Events.CalculateTime(24000)); +                else +                    wTrigger->m_Events.AddEvent(new EnslavedSoulEvent(wTrigger), wTrigger->m_Events.CalculateTime(28000)); +            }          } -        void EnterCombat(Unit* who) override +        void KillAssyncEvents()          { -            me->AddThreat(who, 10000.0f); -            _EnterCombat(); +            std::vector<Creature*> _worldTriggerList; +            me->GetCreatureListWithEntryInGrid(_worldTriggerList, NPC_RELIQUARY_WORLD_TRIGGER, 70.0f); + +            if (_worldTriggerList.empty()) +                return; -            Phase = 1; -            Counter = 0; -            Timer = 0; +            for (Creature* trigger : _worldTriggerList) +                trigger->m_Events.KillAllEvents(true);          } -        bool SummonSoul() +        void EnterEvadeMode(EvadeReason /*why*/) override          { -            Position const& pos = Trinity::Containers::SelectRandomContainerElement(Coords); -            Creature* Soul = me->SummonCreature(CREATURE_ENSLAVED_SOUL, pos.GetPositionX(), pos.GetPositionY(), me->GetPositionZ(), me->GetOrientation(), TEMPSUMMON_CORPSE_DESPAWN, 0); -            if (!Soul) -                return false; - -            if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0)) -            { -                ENSURE_AI(npc_enslaved_soul::npc_enslaved_soulAI, Soul->AI())->ReliquaryGUID = me->GetGUID(); -                Soul->AI()->AttackStart(target); -            } else EnterEvadeMode(); -            return true; +            events.Reset(); +            summons.DespawnAll(); +            KillAssyncEvents(); +            _DespawnAtEvade();          } -        void MergeThreatList(Creature* target) +        void JustDied(Unit* /*killer*/) override          { -            if (!target) -                return; - -            ThreatContainer::StorageType threatlist = target->getThreatManager().getThreatList(); -            for (ThreatContainer::StorageType::const_iterator itr = threatlist.begin(); itr != threatlist.end(); ++itr) -            { -                Unit* unit = ObjectAccessor::GetUnit(*me, (*itr)->getUnitGuid()); -                if (unit) -                { -                    DoModifyThreatPercent(unit, -100); -                    float threat = target->getThreatManager().getThreat(unit); -                    me->AddThreat(unit, threat);       // This makes it so that the unit has the same amount of threat in Reliquary's threatlist as in the target creature's (One of the Essences). -                } -            } +            events.Reset(); +            instance->SetBossState(DATA_RELIQUARY_OF_SOULS, DONE);          }          void UpdateAI(uint32 diff) override          { -            if (!Phase) +            if (!UpdateVictim())                  return; -            if (me->getThreatManager().getThreatList().empty()) // Reset if event is begun and we don't have a threatlist -            { -                EnterEvadeMode(); +            if (me->HasUnitState(UNIT_STATE_CASTING))                  return; -            } -            Creature* Essence = NULL; -            if (!EssenceGUID.IsEmpty()) -            { -                Essence = ObjectAccessor::GetCreature(*me, EssenceGUID); -                if (!Essence) -                { -                    EnterEvadeMode(); -                    return; -                } -            } +            events.Update(diff); -            if (Timer <= diff) +            while (uint32 eventId = events.ExecuteEvent())              { -                switch (Counter) +                switch (eventId)                  { -                case 0: -                    me->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_STATE_READY2H);  // I R ANNNGRRRY! -                    DoStartNoMovement(me); -                    Timer = 3000; -                    break; -                case 1: -                    Timer = 2800; -                    me->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_ONESHOT_SUBMERGE);  // Release the cube -                    DoCast(me, SPELL_SUBMERGE); -                    DoStartNoMovement(me); -                    break; -                case 2: -                    Timer = 5000; -                    if (Creature* Summon = DoSpawnCreature(23417+Phase, 0, 0, 0, 0, TEMPSUMMON_DEAD_DESPAWN, 0)) -                    { -                        me->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_STATE_SUBMERGED);  // Ribs: open -                        Summon->AI()->AttackStart(SelectTarget(SELECT_TARGET_TOPAGGRO, 0)); -                        EssenceGUID = Summon->GetGUID(); -                        DoStartNoMovement(me); -                    } else EnterEvadeMode(); -                    break; -                case 3: -                    Timer = 1000; -                    if (Phase == 3) -                    { -                        if (Essence && !Essence->IsAlive()) -                            DoCast(me, 7, true); -                        else return; -                    } -                    else +                    case EVENT_SUBMERGE: +                        DoCastSelf(SPELL_SUBMERGE_VISUAL, true); +                        events.ScheduleEvent(EVENT_SUMMON_ESSENCE, Seconds(3)); +                        break; +                    case EVENT_SUMMON_ESSENCE:                      { -                        if (Essence && Essence->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE)) -                        { -                            MergeThreatList(Essence); -                            Essence->RemoveAllAuras(); -                            Essence->DeleteThreatList(); -                            Essence->GetMotionMaster()->MoveFollow(me, 0.0f, 0.0f); -                        } else return; -                    } -                    break; -                case 4: -                    Timer = 1500; -                    if (Essence) -                    { -                        if (Essence->IsWithinDistInMap(me, 10)) -                        { -                            Essence->SetUInt32Value(UNIT_NPC_EMOTESTATE, 374); //rotate and disappear -                            Timer = 2000; -                            me->RemoveAurasDueToSpell(SPELL_SUBMERGE); -                        } -                        else -                        { -                            MergeThreatList(Essence); -                            Essence->RemoveAllAuras(); -                            Essence->DeleteThreatList(); -                            Essence->GetMotionMaster()->MoveFollow(me, 0, 0); -                            return; -                        } -                    } -                    break; -                case 5: -                    if (Essence) -                    { -                        if (Phase == 1) -                            Essence->AI()->Talk(SUFF_SAY_AFTER); -                        else -                            Essence->AI()->Talk(DESI_SAY_AFTER); - -                        Essence->DespawnOrUnsummon(); +                        EntryCheckPredicate pred(NPC_ENSLAVED_SOUL); +                        summons.DoAction(ACTION_KILL_SELF, pred); +                        DoCastSelf(GetSummonSpell()); +                        break;                      } +                    default: +                        break; +                } -                    me->SetUInt32Value(UNIT_NPC_EMOTESTATE, 0); -                    EssenceGUID.Clear(); -                    SoulCount = 0; -                    SoulDeathCount = 0; -                    Timer = 3000; -                    break; -                case 6: -                    if (SoulCount < NUMBER_ENSLAVED_SOUL) -                    { -                        if (SummonSoul()) -                            ++SoulCount; -                        Timer = 500; -                        return; -                    } -                    break; -                case 7: -                    if (SoulDeathCount >= SoulCount) -                    { -                        Counter = 1; -                        ++Phase; -                        Timer = 5000; -                    } +                if (me->HasUnitState(UNIT_STATE_CASTING))                      return; -                default: -                    break; -                } -                ++Counter; -            } else Timer -= diff; +            }          } -    }; -}; -void npc_enslaved_soul::npc_enslaved_soulAI::JustDied(Unit* /*killer*/) -{ -    if (!ReliquaryGUID.IsEmpty()) -        if (Creature* Reliquary = (ObjectAccessor::GetCreature((*me), ReliquaryGUID))) -            ++(ENSURE_AI(boss_reliquary_of_souls::boss_reliquary_of_soulsAI, Reliquary->AI())->SoulDeathCount); +    private: +        bool _inCombat; +    }; -    DoCast(me, SPELL_SOUL_RELEASE, true); -} +    CreatureAI* GetAI(Creature* creature) const override +    { +        return GetBlackTempleAI<boss_reliquary_of_soulsAI>(creature); +    } +};  class boss_essence_of_suffering : public CreatureScript  {  public:      boss_essence_of_suffering() : CreatureScript("boss_essence_of_suffering") { } -    CreatureAI* GetAI(Creature* creature) const override +    struct boss_essence_of_sufferingAI : public BossAI      { -        return GetBlackTempleAI<boss_essence_of_sufferingAI>(creature); -    } - -    struct boss_essence_of_sufferingAI : public ScriptedAI -    { -        boss_essence_of_sufferingAI(Creature* creature) : ScriptedAI(creature) +        boss_essence_of_sufferingAI(Creature* creature) : BossAI(creature, DATA_ESSENCE_OF_SUFFERING), _dead(false)          { -            Initialize(); +            SetBoundary(instance->GetBossBoundary(DATA_RELIQUARY_OF_SOULS));          } -        void Initialize() +        void Reset() override          { -            AggroYellTimer = 5000; -            FixateTimer = 8000; -            EnrageTimer = 30000; -            SoulDrainTimer = 45000; -            AuraTimer = 5000; +            DoCastAOE(SPELL_AURA_OF_SUFFERING, true); +            events.Reset(); +            _dead = false;          } -        uint32 AggroYellTimer; -        uint32 FixateTimer; -        uint32 EnrageTimer; -        uint32 SoulDrainTimer; -        uint32 AuraTimer; - -        void Reset() override +        void MovementInform(uint32 motionType, uint32 pointId) override          { -            Initialize(); +            if (motionType != POINT_MOTION_TYPE) +                return; + +            if (pointId == RELIQUARY_DESPAWN_WAYPOINT) +            { +                if (Creature* reliquary = instance->GetCreature(DATA_RELIQUARY_OF_SOULS)) +                    reliquary->AI()->DoAction(ACTION_ESSENCE_OF_SUFFERING_DEAD); + +                DoCastSelf(SPELL_SUBMERGE_VISUAL, true); +                me->DespawnOrUnsummon(Seconds(2)); +            }          }          void DamageTaken(Unit* /*done_by*/, uint32 &damage) override @@ -423,89 +344,81 @@ public:              if (damage >= me->GetHealth())              {                  damage = 0; -                me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); -                Talk(SUFF_SAY_RECAP); -                me->SetReactState(REACT_PASSIVE); +                if (!_dead) +                { +                    _dead = true; +                    Talk(SUFF_SAY_RECAP); +                    me->AttackStop(); +                    me->SetReactState(REACT_PASSIVE); +                    me->GetMotionMaster()->MovePoint(RELIQUARY_DESPAWN_WAYPOINT, DespawnPoint); +                }              }          }          void EnterCombat(Unit* /*who*/) override          { -            if (!me->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE)) -            { -                Talk(SUFF_SAY_FREED); -                DoZoneInCombat(); -                DoCast(me, AURA_OF_SUFFERING, true); // linked aura need core support -                DoCast(me, ESSENCE_OF_SUFFERING_PASSIVE, true); -                DoCast(me, ESSENCE_OF_SUFFERING_PASSIVE2, true); -            } +            me->SetCombatPulseDelay(5); +            me->setActive(true); +            DoZoneInCombat(); + +            events.ScheduleEvent(EVENT_SOUL_DRAIN, Seconds(20)); +            events.ScheduleEvent(EVENT_FRENZY, Seconds(45)); +            Talk(SUFF_SAY_AGRO);          } -        void KilledUnit(Unit* /*victim*/) override +        void KilledUnit(Unit* victim) override          { -            Talk(SUFF_SAY_SLAY); +            if (victim->GetTypeId() == TYPEID_PLAYER) +                Talk(SUFF_SAY_SLAY);          } -        void CastFixate() +        void EnterEvadeMode(EvadeReason /*why*/) override          { -            ThreatContainer::StorageType const &threatlist = me->getThreatManager().getThreatList(); -            if (threatlist.empty()) -                return; // No point continuing if empty threatlist. -            std::list<Unit*> targets; -            ThreatContainer::StorageType::const_iterator itr = threatlist.begin(); -            for (; itr != threatlist.end(); ++itr) -            { -                Unit* unit = ObjectAccessor::GetUnit(*me, (*itr)->getUnitGuid()); -                if (unit && unit->IsAlive() && (unit->GetTypeId() == TYPEID_PLAYER)) // Only alive players -                    targets.push_back(unit); -            } -            if (targets.empty()) -                return; // No targets added for some reason. No point continuing. -            targets.sort(Trinity::ObjectDistanceOrderPred(me)); // Sort players by distance. -            targets.resize(1); // Only need closest target. -            Unit* target = targets.front(); // Get the first target. -            if (target) -                target->CastSpell(me, SPELL_FIXATE_TAUNT, true); -            DoResetThreat(); -            me->AddThreat(target, 1000000); +            if (Creature* reliquary = instance->GetCreature(DATA_RELIQUARY_OF_SOULS)) +                reliquary->AI()->EnterEvadeMode(EVADE_REASON_OTHER);          }          void UpdateAI(uint32 diff) override          { -            if (me->IsInCombat()) -            { -                //Supposed to be cast on nearest target -                if (FixateTimer <= diff) -                { -                    CastFixate(); -                    FixateTimer = 5000; -                    if (!(rand32() % 16)) -                    { -                        Talk(SUFF_SAY_AGGRO); -                    } -                } else FixateTimer -= diff; -            } - -            //Return since we have no target              if (!UpdateVictim())                  return; -            if (EnrageTimer <= diff) -            { -                DoCast(me, SPELL_ENRAGE); -                EnrageTimer = 60000; -                Talk(SUFF_EMOTE_ENRAGE); -            } else EnrageTimer -= diff; +            if (me->HasUnitState(UNIT_STATE_CASTING)) +                return; -            if (SoulDrainTimer <= diff) +            events.Update(diff); + +            while (uint32 eventId = events.ExecuteEvent())              { -                DoCast(SelectTarget(SELECT_TARGET_RANDOM, 0), SPELL_SOUL_DRAIN); -                SoulDrainTimer = 60000; -            } else SoulDrainTimer -= diff; +                switch (eventId) +                { +                    case EVENT_SOUL_DRAIN: +                        me->CastCustomSpell(SPELL_SOUL_DRAIN, SPELLVALUE_MAX_TARGETS, 5, me); +                        events.Repeat(Seconds(30), Seconds(35)); +                        break; +                    case EVENT_FRENZY: +                        Talk(SUFF_SAY_ENRAGE); +                        DoCastSelf(SPELL_FRENZY); +                        events.Repeat(Seconds(45), Seconds(50)); +                        break; +                    default: +                        break; +                } + +                if (me->HasUnitState(UNIT_STATE_CASTING)) +                    return; +            }              DoMeleeAttackIfReady();          } +    private: +        bool _dead;      }; + +    CreatureAI* GetAI(Creature* creature) const override +    { +        return GetBlackTempleAI<boss_essence_of_sufferingAI>(creature); +    }  };  class boss_essence_of_desire : public CreatureScript @@ -513,74 +426,73 @@ class boss_essence_of_desire : public CreatureScript  public:      boss_essence_of_desire() : CreatureScript("boss_essence_of_desire") { } -    CreatureAI* GetAI(Creature* creature) const override +    struct boss_essence_of_desireAI : public BossAI      { -        return GetBlackTempleAI<boss_essence_of_desireAI>(creature); -    } - -    struct boss_essence_of_desireAI : public ScriptedAI -    { -        boss_essence_of_desireAI(Creature* creature) : ScriptedAI(creature) +        boss_essence_of_desireAI(Creature* creature) : BossAI(creature, DATA_ESSENCE_OF_DESIRE), _dead(false)          { -            Initialize(); +            SetBoundary(instance->GetBossBoundary(DATA_RELIQUARY_OF_SOULS));          } -        void Initialize() +        void Reset() override          { -            RuneShieldTimer = 60000; -            DeadenTimer = 30000; -            SoulShockTimer = 5000; +            DoCastSelf(SPELL_AURA_OF_DESIRE, true); +            events.Reset(); +            _dead = false;          } -        uint32 RuneShieldTimer; -        uint32 DeadenTimer; -        uint32 SoulShockTimer; - -        void Reset() override +        void EnterCombat(Unit* /*who*/) override          { -            Initialize(); -            me->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_MOD_CONFUSE, true); +            events.ScheduleEvent(EVENT_SPIRIT_SHOCK, Seconds(11)); +            events.ScheduleEvent(EVENT_RUNE_SHIELD, Seconds(16)); +            events.ScheduleEvent(EVENT_DEADEN, Seconds(31)); + +            me->SetCombatPulseDelay(5); +            me->setActive(true); +            DoZoneInCombat(); +            Talk(DESI_SAY_FREED);          } -        void DamageTaken(Unit* done_by, uint32 &damage) override +        void MovementInform(uint32 motionType, uint32 pointId) override          { -            if (done_by == me) +            if (motionType != POINT_MOTION_TYPE)                  return; -            if (damage >= me->GetHealth()) -            { -                damage = 0; -                me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); -                Talk(SUFF_SAY_RECAP); -                me->SetReactState(REACT_PASSIVE); -            } -            else +            if (pointId == RELIQUARY_DESPAWN_WAYPOINT)              { -                int32 bp0 = damage / 2; -                me->CastCustomSpell(done_by, AURA_OF_DESIRE_DAMAGE, &bp0, NULL, NULL, true); +                if (Creature* reliquary = instance->GetCreature(DATA_RELIQUARY_OF_SOULS)) +                    reliquary->AI()->DoAction(ACTION_ESSENCE_OF_DESIRE_DEAD); + +                DoCastSelf(SPELL_SUBMERGE_VISUAL, true); +                me->DespawnOrUnsummon(Seconds(2));              }          } -        void SpellHit(Unit* /*caster*/, const SpellInfo* spell) override +        void DamageTaken(Unit* /*done_by*/, uint32 &damage) override          { -            if (me->GetCurrentSpell(CURRENT_GENERIC_SPELL)) -                for (SpellEffectInfo const* effect : spell->GetEffectsForDifficulty(GetDifficulty())) -                    if (effect->Effect == SPELL_EFFECT_INTERRUPT_CAST) -                        if (me->GetCurrentSpell(CURRENT_GENERIC_SPELL)->m_spellInfo->Id == SPELL_SOUL_SHOCK -                            || me->GetCurrentSpell(CURRENT_GENERIC_SPELL)->m_spellInfo->Id == SPELL_DEADEN) -                            me->InterruptSpell(CURRENT_GENERIC_SPELL, false); +            if (damage >= me->GetHealth()) +            { +                damage = 0; +                if (!_dead) +                { +                    _dead = true; +                    Talk(DESI_SAY_RECAP); +                    me->AttackStop(); +                    me->SetReactState(REACT_PASSIVE); +                    me->GetMotionMaster()->MovePoint(RELIQUARY_DESPAWN_WAYPOINT, DespawnPoint); +                } +            }          } -        void EnterCombat(Unit* /*who*/) override +        void KilledUnit(Unit* victim) override          { -            Talk(DESI_SAY_FREED); -            DoZoneInCombat(); -            DoCast(me, AURA_OF_DESIRE, true); +            if (victim->GetTypeId() == TYPEID_PLAYER) +                Talk(DESI_SAY_SLAY);          } -        void KilledUnit(Unit* /*victim*/) override +        void EnterEvadeMode(EvadeReason /*why*/) override          { -            Talk(DESI_SAY_SLAY); +            if (Creature* reliquary = instance->GetCreature(DATA_RELIQUARY_OF_SOULS)) +                reliquary->AI()->EnterEvadeMode(EVADE_REASON_OTHER);          }          void UpdateAI(uint32 diff) override @@ -588,35 +500,46 @@ public:              if (!UpdateVictim())                  return; -            if (RuneShieldTimer <= diff) -            { -                me->InterruptNonMeleeSpells(false); -                DoCast(me, SPELL_RUNE_SHIELD, true); -                SoulShockTimer += 2000; -                DeadenTimer += 2000; -                RuneShieldTimer = 60000; -            } else RuneShieldTimer -= diff; - -            if (SoulShockTimer <= diff) -            { -                DoCastVictim(SPELL_SOUL_SHOCK); -                SoulShockTimer = 5000; -            } else SoulShockTimer -= diff; +            if (me->HasUnitState(UNIT_STATE_CASTING)) +                return; + +            events.Update(diff); -            if (DeadenTimer <= diff) +            while (uint32 eventId = events.ExecuteEvent())              { -                me->InterruptNonMeleeSpells(false); -                DoCastVictim(SPELL_DEADEN); -                DeadenTimer = urand(25000, 35000); -                if (!(rand32() % 2)) +                switch (eventId)                  { -                    Talk(DESI_SAY_SPEC); +                    case EVENT_SPIRIT_SHOCK: +                        DoCastVictim(SPELL_SPIRIT_SHOCK); +                        events.Repeat(Seconds(10), Seconds(15)); +                        break; +                    case EVENT_RUNE_SHIELD: +                        DoCastSelf(SPELL_RUNE_SHIELD); +                        events.Repeat(Seconds(16)); +                        break; +                    case EVENT_DEADEN: +                        Talk(DESI_SAY_SPEC); +                        DoCastVictim(SPELL_DEADEN); +                        events.Repeat(Seconds(31)); +                        break; +                    default: +                        break;                  } -            } else DeadenTimer -= diff; + +                if (me->HasUnitState(UNIT_STATE_CASTING)) +                    return; +            }              DoMeleeAttackIfReady();          } +    private: +        bool _dead;      }; + +    CreatureAI* GetAI(Creature* creature) const override +    { +        return GetBlackTempleAI<boss_essence_of_desireAI>(creature); +    }  };  class boss_essence_of_anger : public CreatureScript @@ -624,103 +547,309 @@ class boss_essence_of_anger : public CreatureScript  public:      boss_essence_of_anger() : CreatureScript("boss_essence_of_anger") { } -    CreatureAI* GetAI(Creature* creature) const override +    struct boss_essence_of_angerAI : public BossAI      { -        return GetBlackTempleAI<boss_essence_of_angerAI>(creature); -    } +        boss_essence_of_angerAI(Creature* creature) :BossAI(creature, DATA_ESSENCE_OF_ANGER) +        { +            SetBoundary(instance->GetBossBoundary(DATA_RELIQUARY_OF_SOULS)); +        } -    struct boss_essence_of_angerAI : public ScriptedAI -    { -        boss_essence_of_angerAI(Creature* creature) : ScriptedAI(creature) +        void Reset() override +        { +            events.Reset(); +            _targetGUID.Clear(); +            DoCastSelf(SPELL_AURA_OF_ANGER); +        } + +        void EnterCombat(Unit* /*who*/) override +        { +            Talk(ANGER_SAY_FREED); + +            events.ScheduleEvent(EVENT_START_CHECK_TANKER, Seconds(5)); +            events.ScheduleEvent(EVENT_SOUL_SCREAM, Seconds(11)); +            events.ScheduleEvent(EVENT_SPITE, Seconds(20)); +            events.ScheduleEvent(EVENT_FREED_2, Seconds(1), Minutes(3)); + +            me->SetCombatPulseDelay(5); +            me->setActive(true); +            DoZoneInCombat(); +        } + +        void JustDied(Unit* /*killer*/) override          { -            Initialize(); +            DoPlaySoundToSet(me, ANGER_SOUND_ID_DEATH); +            if (Creature* reliquary = instance->GetCreature(DATA_RELIQUARY_OF_SOULS)) +                reliquary->AI()->DoAction(ACTION_KILL_SELF);          } -        void Initialize() +        void UpdateAI(uint32 diff) override          { -            AggroTargetGUID.Clear(); +            if (!UpdateVictim()) +                return; + +            if (me->HasUnitState(UNIT_STATE_CASTING)) +                return; + +            events.Update(diff); + +            while (uint32 eventId = events.ExecuteEvent()) +            { +                switch (eventId) +                { +                    case EVENT_CHECK_TANKER: +                    { +                        Unit* target = me->GetVictim(); +                        if (!_targetGUID || !target) +                            return; + +                        if (target->GetGUID() != _targetGUID) +                        { +                            Talk(ANGER_SAY_SEETHE); +                            Talk(ANGER_EMOTE_SEETHE, me); +                            _targetGUID = target->GetGUID(); +                            DoCastSelf(SPELL_SEETHE, true); +                        } +                        break; +                    } +                    case EVENT_SOUL_SCREAM: +                        DoCastSelf(SPELL_SOUL_SCREAM); +                        events.Repeat(Seconds(11)); +                        break; +                    case EVENT_SPITE: +                        Talk(ANGER_SAY_SPITE); +                        me->CastCustomSpell(SPELL_SPITE, SPELLVALUE_MAX_TARGETS, 3, me); +                        events.Repeat(Seconds(20)); +                        break; +                    case EVENT_START_CHECK_TANKER: +                        if (Unit* target = me->GetVictim()) +                        { +                            _targetGUID = target->GetGUID(); +                            events.ScheduleEvent(EVENT_CHECK_TANKER, Seconds(1)); +                        } +                        else +                            events.Repeat(Seconds(1)); +                        break; +                    case EVENT_FREED_2: +                        Talk(ANGER_SAY_FREED_2); +                        break; +                    default: +                        break; +                } -            CheckTankTimer = 5000; -            SoulScreamTimer = 10000; -            SpiteTimer = 30000; +                if (me->HasUnitState(UNIT_STATE_CASTING)) +                    return; +            } -            CheckedAggro = false; +            DoMeleeAttackIfReady();          } -        ObjectGuid AggroTargetGUID; +        void EnterEvadeMode(EvadeReason /*why*/) override +        { +            if (Creature* reliquary = instance->GetCreature(DATA_RELIQUARY_OF_SOULS)) +                reliquary->AI()->EnterEvadeMode(EVADE_REASON_OTHER); +        } -        uint32 CheckTankTimer; -        uint32 SoulScreamTimer; -        uint32 SpiteTimer; +    private: +        ObjectGuid _targetGUID; +    }; -        bool CheckedAggro; +    CreatureAI* GetAI(Creature* creature) const override +    { +        return GetBlackTempleAI<boss_essence_of_angerAI>(creature); +    } +}; + +class npc_enslaved_soul : public CreatureScript +{ +public: +    npc_enslaved_soul() : CreatureScript("npc_enslaved_soul") { } + +    struct npc_enslaved_soulAI : public ScriptedAI +    { +        npc_enslaved_soulAI(Creature* creature) : ScriptedAI(creature), _instance(creature->GetInstanceScript()) { }          void Reset() override          { -            Initialize(); +            me->SetReactState(REACT_PASSIVE); +            if (Creature* reliquary = _instance->GetCreature(DATA_RELIQUARY_OF_SOULS)) +                reliquary->AI()->JustSummoned(me); + +            DoCastSelf(SPELL_ENSLAVED_SOUL_PASSIVE, true); + +            _scheduler.Schedule(Seconds(3), [this](TaskContext /*context*/) +            { +                me->SetReactState(REACT_AGGRESSIVE); +                me->SetInCombatWithZone(); +            });          } -        void EnterCombat(Unit* /*who*/) override +        void DoAction(int32 actionId) override          { -            Talk(ANGER_SAY_FREED); +            if (actionId == ACTION_KILL_SELF) +                me->KillSelf(); +        } -            DoZoneInCombat(); -            DoCast(me, AURA_OF_ANGER, true); +        void UpdateAI(uint32 diff) override +        { +            if (!UpdateVictim()) +                return; + +            _scheduler.Update(diff); + +            DoMeleeAttackIfReady();          }          void JustDied(Unit* /*killer*/) override          { -            Talk(ANGER_SAY_DEATH); +            DoCastSelf(SPELL_SOUL_RELEASE, true);          } -        void KilledUnit(Unit* /*victim*/) override +    private: +        InstanceScript* _instance; +        TaskScheduler _scheduler; +    }; + +    CreatureAI* GetAI(Creature* creature) const override +    { +        return GetBlackTempleAI<npc_enslaved_soulAI>(creature); +    } +}; + +class spell_reliquary_of_souls_aura_of_desire : public SpellScriptLoader +{ +    public: +        spell_reliquary_of_souls_aura_of_desire() : SpellScriptLoader("spell_reliquary_of_souls_aura_of_desire") { } + +        class spell_reliquary_of_souls_aura_of_desire_AuraScript : public AuraScript          { -            Talk(ANGER_SAY_SLAY); +            PrepareAuraScript(spell_reliquary_of_souls_aura_of_desire_AuraScript); + +            bool Validate(SpellInfo const* /*spellInfo*/) override +            { +                return ValidateSpellInfo({ SPELL_AURA_OF_DESIRE_DAMAGE }); +            } + +            void OnProcSpell(AuraEffect const* aurEff, ProcEventInfo& eventInfo) +            { +                PreventDefaultAction(); +                DamageInfo* damageInfo = eventInfo.GetDamageInfo(); +                if (!damageInfo || !damageInfo->GetDamage()) +                    return; + +                Unit* caster = eventInfo.GetActor(); +                int32 bp = damageInfo->GetDamage() / 2; +                caster->CastCustomSpell(SPELL_AURA_OF_DESIRE_DAMAGE, SPELLVALUE_BASE_POINT0, bp, caster, true, nullptr, aurEff); +            } + +            void UpdateAmount(AuraEffect const* /*effect*/) +            { +                if (AuraEffect* effect = GetAura()->GetEffect(EFFECT_1)) +                    effect->ChangeAmount(effect->GetAmount() - 5); +            } + +            void Register() override +            { +                OnEffectProc += AuraEffectProcFn(spell_reliquary_of_souls_aura_of_desire_AuraScript::OnProcSpell, EFFECT_0, SPELL_AURA_MOD_HEALING_PCT); +                OnEffectPeriodic += AuraEffectPeriodicFn(spell_reliquary_of_souls_aura_of_desire_AuraScript::UpdateAmount, EFFECT_2, SPELL_AURA_PERIODIC_TRIGGER_SPELL); +            } +        }; + +        AuraScript* GetAuraScript() const override +        { +            return new spell_reliquary_of_souls_aura_of_desire_AuraScript();          } +}; -        void UpdateAI(uint32 diff) override +class spell_reliquary_of_souls_submerge : public SpellScriptLoader +{ +    public: +        spell_reliquary_of_souls_submerge() : SpellScriptLoader("spell_reliquary_of_souls_submerge") { } + +        class spell_reliquary_of_souls_submerge_AuraScript : public AuraScript          { -            //Return since we have no target -            if (!UpdateVictim() || !me->GetVictim()) -                return; +            PrepareAuraScript(spell_reliquary_of_souls_submerge_AuraScript); -            if (!CheckedAggro) +            void OnApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)              { -                AggroTargetGUID = me->EnsureVictim()->GetGUID(); -                CheckedAggro = true; +                GetTarget()->SetByteValue(UNIT_FIELD_BYTES_1, UNIT_BYTES_1_OFFSET_STAND_STATE, UNIT_STAND_STATE_SUBMERGED);              } -            if (CheckTankTimer <= diff) +            void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)              { -                if (me->EnsureVictim()->GetGUID() != AggroTargetGUID) -                { -                    Talk(ANGER_SAY_BEFORE); -                    DoCast(me, SPELL_SELF_SEETHE, true); -                    AggroTargetGUID = me->EnsureVictim()->GetGUID(); -                } -                CheckTankTimer = 2000; -            } else CheckTankTimer -= diff; +                GetTarget()->SetByteValue(UNIT_FIELD_BYTES_1, UNIT_BYTES_1_OFFSET_STAND_STATE, UNIT_STAND_STATE_STAND); +            } -            if (SoulScreamTimer <= diff) + +            void Register() override              { -                DoCastVictim(SPELL_SOUL_SCREAM); -                SoulScreamTimer = urand(9000, 11000); -                if (!(rand32() % 3)) -                { -                    Talk(ANGER_SAY_SPEC); -                } -            } else SoulScreamTimer -= diff; +                AfterEffectApply += AuraEffectApplyFn(spell_reliquary_of_souls_submerge_AuraScript::OnApply, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL); +                AfterEffectRemove += AuraEffectRemoveFn(spell_reliquary_of_souls_submerge_AuraScript::OnRemove, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL); +            } +        }; -            if (SpiteTimer <= diff) +        AuraScript* GetAuraScript() const override +        { +            return new spell_reliquary_of_souls_submerge_AuraScript(); +        } +}; + +class spell_reliquary_of_souls_spite : public SpellScriptLoader +{ +    public: +        spell_reliquary_of_souls_spite() : SpellScriptLoader("spell_reliquary_of_souls_spite") { } + +        class spell_reliquary_of_souls_spite_AuraScript : public AuraScript +        { +            PrepareAuraScript(spell_reliquary_of_souls_spite_AuraScript); + +            bool Validate(SpellInfo const* /*spellInfo*/) override              { -                DoCast(me, SPELL_SPITE_TARGET); -                SpiteTimer = 30000; -                Talk(ANGER_SAY_SPEC); -            } else SpiteTimer -= diff; +                return ValidateSpellInfo({ SPELL_SPITE_DAMAGE }); +            } -            DoMeleeAttackIfReady(); +            void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) +            { +                if (Unit* caster = GetCaster()) +                    caster->CastSpell(GetTarget(), SPELL_SPITE_DAMAGE, true); +            } + +            void Register() override +            { +                AfterEffectRemove += AuraEffectRemoveFn(spell_reliquary_of_souls_spite_AuraScript::OnRemove, EFFECT_0, SPELL_AURA_DAMAGE_IMMUNITY, AURA_EFFECT_HANDLE_REAL); +            } +        }; + +        AuraScript* GetAuraScript() const +        { +            return new spell_reliquary_of_souls_spite_AuraScript(); +        } +}; + +class spell_reliquary_of_souls_frenzy : public SpellScriptLoader +{ +    public: +        spell_reliquary_of_souls_frenzy() : SpellScriptLoader("spell_reliquary_of_souls_frenzy") { } + +        class spell_reliquary_of_souls_frenzy_SpellScript : public SpellScript +        { +            PrepareSpellScript(spell_reliquary_of_souls_frenzy_SpellScript); + +            void HandleAfterCast() +            { +                if (Creature* caster = GetCaster()->ToCreature()) +                    caster->AI()->Talk(SUFF_EMOTE_ENRAGE, caster); +            } + +            void Register() override +            { +                AfterCast += SpellCastFn(spell_reliquary_of_souls_frenzy_SpellScript::HandleAfterCast); +            } +        }; + +        SpellScript* GetSpellScript() const override +        { +            return new spell_reliquary_of_souls_frenzy_SpellScript();          } -    };  };  void AddSC_boss_reliquary_of_souls() @@ -730,4 +859,8 @@ void AddSC_boss_reliquary_of_souls()      new boss_essence_of_desire();      new boss_essence_of_anger();      new npc_enslaved_soul(); +    new spell_reliquary_of_souls_aura_of_desire(); +    new spell_reliquary_of_souls_submerge(); +    new spell_reliquary_of_souls_spite(); +    new spell_reliquary_of_souls_frenzy();  } diff --git a/src/server/scripts/Outland/BlackTemple/boss_teron_gorefiend.cpp b/src/server/scripts/Outland/BlackTemple/boss_teron_gorefiend.cpp index cf14398d6c6..f36475dbc33 100644 --- a/src/server/scripts/Outland/BlackTemple/boss_teron_gorefiend.cpp +++ b/src/server/scripts/Outland/BlackTemple/boss_teron_gorefiend.cpp @@ -345,6 +345,7 @@ public:                      me->AddThreat(target, 1000000.0f);                      targetGUID = target->GetGUID();                  } +                // He should target Vengeful Spirits only if has no other player available                  else if (Unit* target = teron->AI()->SelectTarget(SELECT_TARGET_RANDOM, 0))                  {                      DoResetThreat(); diff --git a/src/server/scripts/Outland/BlackTemple/instance_black_temple.cpp b/src/server/scripts/Outland/BlackTemple/instance_black_temple.cpp index 9a81bd77f31..e2dcc71114e 100644 --- a/src/server/scripts/Outland/BlackTemple/instance_black_temple.cpp +++ b/src/server/scripts/Outland/BlackTemple/instance_black_temple.cpp @@ -49,7 +49,8 @@ BossBoundaryData const boundaries =      { DATA_TERON_GOREFIEND,       new RectangleBoundary(512.5f, 613.3f, 373.2f, 432.0f)      },      { DATA_TERON_GOREFIEND,       new ZRangeBoundary(179.5f, 223.6f)                         },      { DATA_GURTOGG_BLOODBOIL,     new RectangleBoundary(720.5f, 864.5f, 159.3f, 316.0f)      }, -    { DATA_RELIQUARY_OF_SOULS,    new RectangleBoundary(435.9f, 558.8f, 113.3f, 229.6f)      }, +    { DATA_RELIQUARY_OF_SOULS,    new RectangleBoundary(435.9f, 660.3f, 21.2f, 229.6f)       }, +    { DATA_RELIQUARY_OF_SOULS,    new ZRangeBoundary(81.8f, 148.0f)                          },      { DATA_MOTHER_SHAHRAZ,        new RectangleBoundary(903.4f, 982.1f, 92.4f, 476.7f)       },      { DATA_ILLIDARI_COUNCIL,      new EllipseBoundary(Position(696.6f, 305.0f), 70.0 , 85.0) },      { DATA_ILLIDAN_STORMRAGE,     new EllipseBoundary(Position(694.8f, 309.0f), 70.0 , 85.0) }  | 
