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 | |
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)
6 files changed, 806 insertions, 501 deletions
diff --git a/sql/updates/world/master/2018_03_12_07_world_2016_12_13_00_world.sql b/sql/updates/world/master/2018_03_12_07_world_2016_12_13_00_world.sql new file mode 100644 index 00000000000..31bd4951ce2 --- /dev/null +++ b/sql/updates/world/master/2018_03_12_07_world_2016_12_13_00_world.sql @@ -0,0 +1,57 @@ +UPDATE `creature_template` SET `AIName`='' WHERE `entry`=23472; + +-- Condition for spell Fixate +DELETE FROM `conditions` WHERE `SourceTypeOrReferenceId`=13 AND `SourceEntry`=41295; +INSERT INTO `conditions` (`SourceTypeOrReferenceId`, `SourceGroup`, `SourceEntry`, `SourceId`, `ElseGroup`, `ConditionTypeOrReference`, `ConditionTarget`, `ConditionValue1`, `ConditionValue2`, `ConditionValue3`, `NegativeCondition`, `ErrorType`, `ErrorTextId`, `ScriptName`, `Comment`) VALUES +(13,1,41295,0,0,31,0,3,23418,0,0,0,0,'','Effect_0 hits Essence of Suffering'); + +DELETE FROM `creature_template_addon` WHERE `entry`=23418; +INSERT INTO `creature_template_addon` (`entry`, `path_id`, `mount`, `bytes1`, `bytes2`, `emote`, `auras`) VALUES +(23418, 0, 0, 0, 1, 0,'41296 41623'); + +DELETE FROM `spell_script_names` WHERE `ScriptName` IN('spell_reliquary_of_souls_aura_of_desire','spell_reliquary_of_souls_submerge','spell_reliquary_of_souls_spite','spell_soul_fragment_anger','spell_reliquary_of_souls_frenzy'); +INSERT INTO `spell_script_names` (`spell_id`, `ScriptName`) VALUES +(41350,'spell_reliquary_of_souls_aura_of_desire'), +(28819,'spell_reliquary_of_souls_submerge'), +(41376,'spell_reliquary_of_souls_spite'), +(41986,'spell_soul_fragment_anger'), +(41305,'spell_reliquary_of_souls_frenzy'); + +DELETE FROM `spell_linked_spell` WHERE `spell_trigger`=-41376 AND`spell_effect`=41377 AND`type`=0; + +UPDATE `creature_template` SET `modelid1`=11686, `modelid2`=1126, `flags_extra`=0, `ScriptName`='npc_angered_soul_fragment' WHERE `entry`=23398; + +DELETE FROM `spell_proc` WHERE `SpellId`=41350; +INSERT INTO `spell_proc` (`SpellId`, `SchoolMask`, `SpellFamilyName`, `SpellFamilyMask0`, `SpellFamilyMask1`, `SpellFamilyMask2`, `ProcFlags`, `SpellTypeMask`, `SpellPhaseMask`, `HitMask`, `AttributesMask`, `ProcsPerMinute`, `Chance`, `Cooldown`, `Charges`) VALUES +(41350, 0, 0, 0x00000000, 0x00000000, 0x00000000, 0, 0x1, 0x2, 0x0, 0x2, 0, 0, 0, 0); + +DELETE FROM `creature_text` WHERE `CreatureID`=23418; +INSERT INTO `creature_text` (`CreatureID`,`GroupID`,`ID`,`Text`,`Type`,`Language`,`Probability`,`Emote`,`Duration`,`Sound`,`BroadcastTextId`,`TextRange`,`Comment`) VALUES +(23418,0,0,'Pain and suffering are all that await you!',14,0,100,0,0,11415,21759,0,'SUFF_SAY_AGRO'), +(23418,1,0,'Don\'t leave me alone!',14,0,100,0,0,11416,21760,0,'SUFF_SAY_SLAY'), +(23418,1,1,'Look at what you made me do!',14,0,100,0,0,11417,21761,0,'SUFF_SAY_SLAY2'), +(23418,1,2,'I didn\'t ask for this!',14,0,100,0,0,11418,21762,0,'SUFF_SAY_SLAY3'), +(23418,2,0,'The pain is only beginning...',14,0,100,0,0,11419,21763,0,'SUFF_SAY_ENRAGE'), +(23418,3,0,'I don\'t want to go back!',14,0,100,0,0,11420,21764,0,'SUFF_SAY_RECAP'), +(23418,4,0,'Now what do I do?',14,0,100,0,0,11421,21765,0,'SUFF_SAY_AFTER'), +(23418,5,0,'%s becomes enraged!',41,0,100,0,0,0,24144,0,'SUFF_EMOTE_ENRAGE'); + +DELETE FROM `creature_text` WHERE `CreatureID`=23419; +INSERT INTO `creature_text` (`CreatureID`,`GroupID`,`ID`,`Text`,`Type`,`Language`,`Probability`,`Emote`,`Duration`,`Sound`,`BroadcastTextId`,`TextRange`,`Comment`) VALUES +(23419,0,0,'You can have anything you desire... for a price.',14,0,100,0,0,11408,21752,0,'DESI_SAY_FREED'), +(23419,1,0,'Fulfillment is at hand.',14,0,100,0,0,11409,21753,0,'DESI_SAY_SLAY1'), +(23419,1,1,'Yes, you\'ll stay with us now...',14,0,100,0,0,11410,21754,0,'DESI_SAY_SLAY2'), +(23419,1,2,'Your reach exceeds your grasp.',14,0,100,0,0,11412,21756,0,'DESI_SAY_SLAY3'), +(23419,2,0,'Be careful what you wish for.',14,0,100,0,0,11411,21755,0,'DESI_SAY_SPEC'), +(23419,3,0,'I won\'t be far!',14,0,100,0,0,11414,21758,0,'DESI_SAY_RECAP'), +(23419,4,0,'I\'ll be waiting.',14,0,100,0,0,11413,21757,0,'DESI_SAY_AFTER'); + +DELETE FROM `creature_text` WHERE `CreatureID`=23420; +INSERT INTO `creature_text` (`CreatureID`,`GroupID`,`ID`,`Text`,`Type`,`Language`,`Probability`,`Emote`,`Duration`,`Sound`,`BroadcastTextId`,`TextRange`,`Comment`) VALUES +(23420,0,0,'Beware: I live!',14,0,100,0,0,11399,21746,0,'ANGER_SAY_FREED'), +(23420,1,0,'So... foolish.',14,0,100,0,0,11400,21747,0,'ANGER_SAY_FREED2'), +(23420,2,0,'Enough! No more!',14,0,100,0,0,11402,21748,0,'ANGER_SAY_SEETHE'), +(23420,3,0,'%s seethes in anger!',14,0,100,0,0,0,21878,0,'ANGER_EMOTE_SEETHE'), +(23420,4,0,'On your knees!',14,0,100,0,0,11403,21749,0,'ANGER_SAY_SPEC'), +(23420,5,0,'Beware, coward!',14,0,100,0,0,11405,21751,0,'ANGER_SAY_SPITE'), +(23420,6,0,'I won\'t... be... ignored!',14,0,100,0,0,11404,21750,0,'ANGER_SAY_DEATH'); 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) } |