aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKeader <keader.android@gmail.com>2016-12-13 10:55:22 -0200
committerDoctorKraft <DoctorKraft@users.noreply.github.com>2018-03-12 16:39:40 +0100
commit0449d3a83657436a3379c62d11259f3c83b4a431 (patch)
tree3306d234fe7fc73ee61e3faebb5b734c2acecf69
parente560374b8bab633981727cbfddb66bc2303e9bdb (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)
-rw-r--r--sql/updates/world/master/2018_03_12_07_world_2016_12_13_00_world.sql57
-rw-r--r--src/server/scripts/Outland/BlackTemple/black_temple.cpp124
-rw-r--r--src/server/scripts/Outland/BlackTemple/black_temple.h11
-rw-r--r--src/server/scripts/Outland/BlackTemple/boss_reliquary_of_souls.cpp1111
-rw-r--r--src/server/scripts/Outland/BlackTemple/boss_teron_gorefiend.cpp1
-rw-r--r--src/server/scripts/Outland/BlackTemple/instance_black_temple.cpp3
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) }