diff --git a/src/server/scripts/Northrend/Naxxramas/boss_anubrekhan.cpp b/src/server/scripts/Northrend/Naxxramas/boss_anubrekhan.cpp
index 23f09541b..a312ea1d7 100644
--- a/src/server/scripts/Northrend/Naxxramas/boss_anubrekhan.cpp
+++ b/src/server/scripts/Northrend/Naxxramas/boss_anubrekhan.cpp
@@ -15,16 +15,161 @@
* with this program. If not, see .
*/
-#include "boss_anubrekhan.h"
#include "CreatureScript.h"
#include "ScriptedCreature.h"
#include "naxxramas.h"
+enum Says
+{
+ SAY_AGGRO = 0,
+ SAY_GREET = 1,
+ SAY_SLAY = 2,
+ EMOTE_LOCUST = 3
+};
-using namespace Anubrekhan;
+enum GuardSays
+{
+ EMOTE_SPAWN = 1,
+ EMOTE_SCARAB = 2
+};
-// no custom changes has been made for mod-playerbot other then placing
-// the impl in a header file
+enum Spells
+{
+ SPELL_IMPALE = 28783,
+ SPELL_LOCUST_SWARM = 28785,
+ SPELL_SUMMON_CORPSE_SCRABS_5 = 29105,
+ SPELL_SUMMON_CORPSE_SCRABS_10 = 28864,
+ SPELL_BERSERK = 26662
+};
+
+enum Misc
+{
+ NPC_CORPSE_SCARAB = 16698,
+ NPC_CRYPT_GUARD = 16573,
+
+ ACHIEV_TIMED_START_EVENT = 9891
+};
+
+class boss_anubrekhan : public CreatureScript
+{
+public:
+ boss_anubrekhan() : CreatureScript("boss_anubrekhan") { }
+
+ CreatureAI* GetAI(Creature* pCreature) const override
+ {
+ return GetNaxxramasAI(pCreature);
+ }
+
+ struct boss_anubrekhanAI : public BossAI
+ {
+ boss_anubrekhanAI(Creature* c) : BossAI(c, BOSS_ANUB)
+ {
+ sayGreet = false;
+ }
+
+ void SummonCryptGuards()
+ {
+ if (Is25ManRaid())
+ {
+ me->SummonCreature(NPC_CRYPT_GUARD, 3299.732f, -3502.489f, 287.077f, 2.378f, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 60000);
+ me->SummonCreature(NPC_CRYPT_GUARD, 3299.086f, -3450.929f, 287.077f, 3.999f, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 60000);
+ }
+ }
+
+ void Reset() override
+ {
+ BossAI::Reset();
+ SummonCryptGuards();
+ me->m_Events.KillAllEvents(false);
+ }
+
+ void JustSummoned(Creature* cr) override
+ {
+ if (me->IsInCombat())
+ {
+ cr->SetInCombatWithZone();
+ if (cr->GetEntry() == NPC_CRYPT_GUARD)
+ cr->AI()->Talk(EMOTE_SPAWN, me);
+ }
+ summons.Summon(cr);
+ }
+
+ void SummonedCreatureDies(Creature* cr, Unit*) override
+ {
+ if (cr->GetEntry() == NPC_CRYPT_GUARD)
+ {
+ cr->CastSpell(cr, SPELL_SUMMON_CORPSE_SCRABS_10, true, nullptr, nullptr, me->GetGUID());
+ cr->AI()->Talk(EMOTE_SCARAB);
+ }
+ }
+
+ void JustDied(Unit* killer) override
+ {
+ BossAI::JustDied(killer);
+ instance->DoStartTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, ACHIEV_TIMED_START_EVENT);
+ }
+
+ void KilledUnit(Unit* victim) override
+ {
+ if (!victim->IsPlayer())
+ return;
+
+ Talk(SAY_SLAY);
+ victim->CastSpell(victim, SPELL_SUMMON_CORPSE_SCRABS_5, true, nullptr, nullptr, me->GetGUID());
+ instance->StorePersistentData(PERSISTENT_DATA_IMMORTAL_FAIL, 1);
+ }
+
+ void JustEngagedWith(Unit* who) override
+ {
+ BossAI::JustEngagedWith(who);
+ me->CallForHelp(30.0f);
+ Talk(SAY_AGGRO);
+
+ if (!summons.HasEntry(NPC_CRYPT_GUARD))
+ SummonCryptGuards();
+ if (!Is25ManRaid())
+ {
+ me->m_Events.AddEventAtOffset([&]
+ {
+ me->SummonCreature(NPC_CRYPT_GUARD, 3331.217f, -3476.607f, 287.074f, 3.269f, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 60000);
+ }, Milliseconds(urand(15000, 20000)));
+ }
+
+ ScheduleTimedEvent(15s, [&] {
+ DoCastRandomTarget(SPELL_IMPALE);
+ }, 20s);
+
+ ScheduleTimedEvent(70s, 2min, [&] {
+ Talk(EMOTE_LOCUST);
+ DoCastSelf(SPELL_LOCUST_SWARM);
+
+ me->m_Events.AddEventAtOffset([&]
+ {
+ me->SummonCreature(NPC_CRYPT_GUARD, 3331.217f, -3476.607f, 287.074f, 3.269f, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 60000);
+ }, 3s);
+
+ }, 90s);
+
+ me->m_Events.AddEventAtOffset([&]
+ {
+ DoCastSelf(SPELL_BERSERK, true);
+ }, 10min);
+ }
+
+ void MoveInLineOfSight(Unit* who) override
+ {
+ if (!sayGreet && who->IsPlayer())
+ {
+ Talk(SAY_GREET);
+ sayGreet = true;
+ }
+ ScriptedAI::MoveInLineOfSight(who);
+ }
+
+ private:
+ bool sayGreet;
+ };
+};
void AddSC_boss_anubrekhan()
{
diff --git a/src/server/scripts/Northrend/Naxxramas/boss_anubrekhan.h b/src/server/scripts/Northrend/Naxxramas/boss_anubrekhan.h
deleted file mode 100644
index ef8d96c0c..000000000
--- a/src/server/scripts/Northrend/Naxxramas/boss_anubrekhan.h
+++ /dev/null
@@ -1,165 +0,0 @@
-#ifndef BOSS_ANUBREKHAN_H_
-#define BOSS_ANUBREKHAN_H_
-
-#include "ScriptMgr.h"
-#include "ScriptedCreature.h"
-#include "SpellInfo.h"
-#include "naxxramas.h"
-
-namespace Anubrekhan {
-
-enum Says
-{
- SAY_AGGRO = 0,
- SAY_GREET = 1,
- SAY_SLAY = 2,
- EMOTE_LOCUST = 3
-};
-
-enum GuardSays
-{
- EMOTE_SPAWN = 1,
- EMOTE_SCARAB = 2
-};
-
-enum Spells
-{
- SPELL_IMPALE = 28783,
- SPELL_LOCUST_SWARM = 28785,
- SPELL_SUMMON_CORPSE_SCRABS_5 = 29105,
- SPELL_SUMMON_CORPSE_SCRABS_10 = 28864,
- SPELL_BERSERK = 26662
-};
-
-enum Misc
-{
- NPC_CORPSE_SCARAB = 16698,
- NPC_CRYPT_GUARD = 16573,
-
- ACHIEV_TIMED_START_EVENT = 9891
-};
-
-class boss_anubrekhan : public CreatureScript
-{
-public:
- boss_anubrekhan() : CreatureScript("boss_anubrekhan") { }
-
- CreatureAI* GetAI(Creature* pCreature) const override
- {
- return GetNaxxramasAI(pCreature);
- }
-
- struct boss_anubrekhanAI : public BossAI
- {
- boss_anubrekhanAI(Creature* c) : BossAI(c, BOSS_ANUB)
- {
- sayGreet = false;
- }
-
- void SummonCryptGuards()
- {
- if (Is25ManRaid())
- {
- me->SummonCreature(NPC_CRYPT_GUARD, 3299.732f, -3502.489f, 287.077f, 2.378f, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 60000);
- me->SummonCreature(NPC_CRYPT_GUARD, 3299.086f, -3450.929f, 287.077f, 3.999f, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 60000);
- }
- }
-
- void Reset() override
- {
- BossAI::Reset();
- SummonCryptGuards();
- me->m_Events.KillAllEvents(false);
- }
-
- void JustSummoned(Creature* cr) override
- {
- if (me->IsInCombat())
- {
- cr->SetInCombatWithZone();
- if (cr->GetEntry() == NPC_CRYPT_GUARD)
- cr->AI()->Talk(EMOTE_SPAWN, me);
- }
- summons.Summon(cr);
- }
-
- void SummonedCreatureDies(Creature* cr, Unit*) override
- {
- if (cr->GetEntry() == NPC_CRYPT_GUARD)
- {
- cr->CastSpell(cr, SPELL_SUMMON_CORPSE_SCRABS_10, true, nullptr, nullptr, me->GetGUID());
- cr->AI()->Talk(EMOTE_SCARAB);
- }
- }
-
- void JustDied(Unit* killer) override
- {
- BossAI::JustDied(killer);
- instance->DoStartTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, ACHIEV_TIMED_START_EVENT);
- }
-
- void KilledUnit(Unit* victim) override
- {
- if (!victim->IsPlayer())
- return;
-
- Talk(SAY_SLAY);
- victim->CastSpell(victim, SPELL_SUMMON_CORPSE_SCRABS_5, true, nullptr, nullptr, me->GetGUID());
- instance->StorePersistentData(PERSISTENT_DATA_IMMORTAL_FAIL, 1);
- }
-
- void JustEngagedWith(Unit* who) override
- {
- BossAI::JustEngagedWith(who);
- me->CallForHelp(30.0f);
- Talk(SAY_AGGRO);
-
- if (!summons.HasEntry(NPC_CRYPT_GUARD))
- SummonCryptGuards();
- if (!Is25ManRaid())
- {
- me->m_Events.AddEventAtOffset([&]
- {
- me->SummonCreature(NPC_CRYPT_GUARD, 3331.217f, -3476.607f, 287.074f, 3.269f, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 60000);
- }, Milliseconds(urand(15000, 20000)));
- }
-
- ScheduleTimedEvent(15s, [&] {
- DoCastRandomTarget(SPELL_IMPALE);
- }, 20s);
-
- ScheduleTimedEvent(70s, 2min, [&] {
- Talk(EMOTE_LOCUST);
- DoCastSelf(SPELL_LOCUST_SWARM);
-
- me->m_Events.AddEventAtOffset([&]
- {
- me->SummonCreature(NPC_CRYPT_GUARD, 3331.217f, -3476.607f, 287.074f, 3.269f, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 60000);
- }, 3s);
-
- }, 90s);
-
- me->m_Events.AddEventAtOffset([&]
- {
- DoCastSelf(SPELL_BERSERK, true);
- }, 10min);
- }
-
- void MoveInLineOfSight(Unit* who) override
- {
- if (!sayGreet && who->IsPlayer())
- {
- Talk(SAY_GREET);
- sayGreet = true;
- }
- ScriptedAI::MoveInLineOfSight(who);
- }
-
- private:
- bool sayGreet;
- };
-};
-
-}
-
-#endif
\ No newline at end of file
diff --git a/src/server/scripts/Northrend/Naxxramas/boss_faerlina.h b/src/server/scripts/Northrend/Naxxramas/boss_faerlina.h
deleted file mode 100644
index 545ed7fa9..000000000
--- a/src/server/scripts/Northrend/Naxxramas/boss_faerlina.h
+++ /dev/null
@@ -1,152 +0,0 @@
-#ifndef BOSS_FAERLINA_H_
-#define BOSS_FAERLINA_H_
-
-#include "CreatureScript.h"
-#include "ScriptedCreature.h"
-#include "SpellInfo.h"
-#include "SpellMgr.h"
-#include "naxxramas.h"
-
-namespace Faerlina {
-
-enum Yells
-{
- SAY_GREET = 0,
- SAY_AGGRO = 1,
- SAY_SLAY = 2,
- SAY_DEATH = 3,
- EMOTE_WIDOWS_EMBRACE = 4,
- EMOTE_FRENZY = 5,
- SAY_FRENZY = 6
-};
-
-enum Spells
-{
- SPELL_POISON_BOLT_VOLLEY = 28796,
- SPELL_RAIN_OF_FIRE = 28794,
- SPELL_FRENZY = 28798,
- SPELL_WIDOWS_EMBRACE = 28732,
-};
-
-enum Groups
-{
- GROUP_FRENZY = 1
-};
-
-enum Misc
-{
- NPC_NAXXRAMAS_WORSHIPPER = 16506,
- NPC_NAXXRAMAS_FOLLOWER = 16505
-};
-
-class boss_faerlina : public CreatureScript
-{
-public:
- boss_faerlina() : CreatureScript("boss_faerlina") { }
-
- CreatureAI* GetAI(Creature* pCreature) const override
- {
- return GetNaxxramasAI(pCreature);
- }
-
- struct boss_faerlinaAI : public BossAI
- {
- boss_faerlinaAI(Creature* c) : BossAI(c, BOSS_FAERLINA), _introDone(false) { }
-
- void SummonHelpers()
- {
- me->SummonCreature(NPC_NAXXRAMAS_WORSHIPPER, 3362.66f, -3620.97f, 261.08f, 4.57276f);
- me->SummonCreature(NPC_NAXXRAMAS_WORSHIPPER, 3344.3f, -3618.31f, 261.08f, 4.69494f);
- me->SummonCreature(NPC_NAXXRAMAS_WORSHIPPER, 3356.71f, -3620.05f, 261.08f, 4.57276f);
- me->SummonCreature(NPC_NAXXRAMAS_WORSHIPPER, 3350.26f, -3619.11f, 261.08f, 4.67748f);
- if (Is25ManRaid())
- {
- me->SummonCreature(NPC_NAXXRAMAS_FOLLOWER, 3347.49f, -3617.59f, 261.0f, 4.49f);
- me->SummonCreature(NPC_NAXXRAMAS_FOLLOWER, 3359.64f, -3619.16f, 261.0f, 4.56f);
- }
- }
-
- void Reset() override
- {
- BossAI::Reset();
- summons.DespawnAll();
- SummonHelpers();
- }
-
- void JustEngagedWith(Unit* who) override
- {
- BossAI::JustEngagedWith(who);
- me->CallForHelp(VISIBLE_RANGE);
- summons.DoZoneInCombat();
- Talk(SAY_AGGRO);
-
- ScheduleTimedEvent(7s, 15s, [&]{
- if (!me->HasAura(SPELL_WIDOWS_EMBRACE))
- DoCastVictim(SPELL_POISON_BOLT_VOLLEY);
- }, 7s, 15s);
-
- ScheduleTimedEvent(8s, 18s, [&] {
- DoCastRandomTarget(SPELL_RAIN_OF_FIRE);
- }, 8s, 18s);
-
- scheduler.Schedule(60s, 80s, GROUP_FRENZY, [this](TaskContext context) {
- if (!me->HasAura(SPELL_WIDOWS_EMBRACE))
- {
- Talk(SAY_FRENZY);
- Talk(EMOTE_FRENZY);
- DoCastSelf(SPELL_FRENZY, true);
- context.Repeat(1min);
- }
- else
- context.Repeat(30s);
- });
- }
-
- void MoveInLineOfSight(Unit* who) override
- {
- if (!_introDone && who->IsPlayer())
- {
- Talk(SAY_GREET);
- _introDone = true;
- }
- ScriptedAI::MoveInLineOfSight(who);
- }
-
- void KilledUnit(Unit* who) override
- {
- if (!who->IsPlayer())
- return;
-
- if (!urand(0, 3))
- Talk(SAY_SLAY);
-
- instance->StorePersistentData(PERSISTENT_DATA_IMMORTAL_FAIL, 1);
- }
-
- void JustDied(Unit* killer) override
- {
- BossAI::JustDied(killer);
- Talk(SAY_DEATH);
- }
-
- void SpellHit(Unit* caster, SpellInfo const* spell) override
- {
- if (spell->Id == sSpellMgr->GetSpellIdForDifficulty(SPELL_WIDOWS_EMBRACE, me))
- {
- Talk(EMOTE_WIDOWS_EMBRACE);
- scheduler.RescheduleGroup(GROUP_FRENZY, 1min);
- me->RemoveAurasDueToSpell(SPELL_FRENZY);
- instance->SetData(DATA_FRENZY_REMOVED, 0);
- if (Is25ManRaid())
- caster->KillSelf();
- }
- }
-
- private:
- bool _introDone;
- };
-};
-
-}
-
-#endif
\ No newline at end of file
diff --git a/src/server/scripts/Northrend/Naxxramas/boss_four_horsemen.h b/src/server/scripts/Northrend/Naxxramas/boss_four_horsemen.h
deleted file mode 100644
index bb60b98ef..000000000
--- a/src/server/scripts/Northrend/Naxxramas/boss_four_horsemen.h
+++ /dev/null
@@ -1,381 +0,0 @@
-#ifndef BOSS_FOURHORSEMEN_H_
-#define BOSS_FOURHORSEMEN_H_
-
-#include "CreatureScript.h"
-#include "Player.h"
-#include "ScriptedCreature.h"
-#include "SpellAuraEffects.h"
-#include "SpellScript.h"
-#include "SpellScriptLoader.h"
-#include "SpellInfo.h"
-#include "naxxramas.h"
-
-namespace FourHorsemen {
-
-enum Spells
-{
- SPELL_BERSERK = 26662,
- // Marks
- SPELL_MARK_OF_KORTHAZZ = 28832,
- SPELL_MARK_OF_BLAUMEUX = 28833,
- SPELL_MARK_OF_RIVENDARE = 28834,
- SPELL_MARK_OF_ZELIEK = 28835,
- SPELL_MARK_DAMAGE = 28836,
- // Korth'azz
- SPELL_KORTHAZZ_METEOR = 28884,
- // Blaumeux
- SPELL_BLAUMEUX_SHADOW_BOLT = 57374,
- SPELL_BLAUMEUX_VOID_ZONE = 28863,
- SPELL_BLAUMEUX_UNYIELDING_PAIN = 57381,
- // Zeliek
- SPELL_ZELIEK_HOLY_WRATH = 28883,
- SPELL_ZELIEK_HOLY_BOLT = 57376,
- SPELL_ZELIEK_CONDEMNATION = 57377,
- // Rivendare
- SPELL_RIVENDARE_UNHOLY_SHADOW = 28882,
-};
-
-enum Events
-{
- EVENT_MARK_CAST = 1,
- EVENT_PRIMARY_SPELL = 2,
- EVENT_SECONDARY_SPELL = 3,
- EVENT_BERSERK = 4
-};
-
-enum Misc
-{
- // Movement
- MOVE_PHASE_NONE = 0,
- MOVE_PHASE_STARTED = 1,
- MOVE_PHASE_FINISHED = 2,
- // Horseman
- HORSEMAN_ZELIEK = 0,
- HORSEMAN_BLAUMEUX = 1,
- HORSEMAN_RIVENDARE = 2,
- HORSEMAN_KORTHAZZ = 3
-};
-
-enum FourHorsemen
-{
- SAY_AGGRO = 0,
- SAY_TAUNT = 1,
- SAY_SPECIAL = 2,
- SAY_SLAY = 3,
- SAY_DEATH = 4,
- EMOTE_RAGECAST = 7
-};
-
-// MARKS
-const uint32 TABLE_SPELL_MARK[4] = {SPELL_MARK_OF_ZELIEK, SPELL_MARK_OF_BLAUMEUX, SPELL_MARK_OF_RIVENDARE, SPELL_MARK_OF_KORTHAZZ};
-
-// PRIMARY SPELL
-const uint32 TABLE_SPELL_PRIMARY[4] = {SPELL_ZELIEK_HOLY_BOLT, SPELL_BLAUMEUX_SHADOW_BOLT, SPELL_RIVENDARE_UNHOLY_SHADOW, SPELL_KORTHAZZ_METEOR};
-
-// PUNISH
-const uint32 TABLE_SPELL_PUNISH[4] = {SPELL_ZELIEK_CONDEMNATION, SPELL_BLAUMEUX_UNYIELDING_PAIN, 0, 0};
-
-// SECONDARY SPELL
-const uint32 TABLE_SPELL_SECONDARY[4] = {SPELL_ZELIEK_HOLY_WRATH, SPELL_BLAUMEUX_VOID_ZONE, 0, 0};
-
-const Position WaypointPositions[12] =
-{
- // Thane waypoints
- {2542.3f, -2984.1f, 241.49f, 5.362f},
- {2547.6f, -2999.4f, 241.34f, 5.049f},
- {2542.9f, -3015.0f, 241.35f, 4.654f},
- // Lady waypoints
- {2498.3f, -2961.8f, 241.28f, 3.267f},
- {2487.7f, -2959.2f, 241.28f, 2.890f},
- {2469.4f, -2947.6f, 241.28f, 2.576f},
- // Baron waypoints
- {2553.8f, -2968.4f, 241.33f, 5.757f},
- {2564.3f, -2972.5f, 241.33f, 5.890f},
- {2583.9f, -2971.6f, 241.35f, 0.008f},
- // Sir waypoints
- {2534.5f, -2921.7f, 241.53f, 1.363f},
- {2523.5f, -2902.8f, 241.28f, 2.095f},
- {2517.8f, -2896.6f, 241.28f, 2.315f}
-};
-
-class boss_four_horsemen : public CreatureScript
-{
-public:
- boss_four_horsemen() : CreatureScript("boss_four_horsemen") { }
-
- CreatureAI* GetAI(Creature* pCreature) const override
- {
- return GetNaxxramasAI(pCreature);
- }
-
- struct boss_four_horsemenAI : public BossAI
- {
- explicit boss_four_horsemenAI(Creature* c) : BossAI(c, BOSS_HORSEMAN)
- {
- switch (me->GetEntry())
- {
- case NPC_SIR_ZELIEK:
- horsemanId = HORSEMAN_ZELIEK;
- break;
- case NPC_LADY_BLAUMEUX:
- horsemanId = HORSEMAN_BLAUMEUX;
- break;
- case NPC_BARON_RIVENDARE:
- horsemanId = HORSEMAN_RIVENDARE;
- break;
- case NPC_THANE_KORTHAZZ:
- horsemanId = HORSEMAN_KORTHAZZ;
- break;
- }
- }
-
- EventMap events;
- uint8 currentWaypoint{};
- uint8 movementPhase{};
- uint8 horsemanId;
-
- void MoveToCorner()
- {
- switch (me->GetEntry())
- {
- case NPC_THANE_KORTHAZZ:
- currentWaypoint = 0;
- break;
- case NPC_LADY_BLAUMEUX:
- currentWaypoint = 3;
- break;
- case NPC_BARON_RIVENDARE:
- currentWaypoint = 6;
- break;
- case NPC_SIR_ZELIEK:
- currentWaypoint = 9;
- break;
- }
- me->GetMotionMaster()->MovePoint(currentWaypoint, WaypointPositions[currentWaypoint]);
- }
-
- bool IsInRoom()
- {
- if (me->GetExactDist(2535.1f, -2968.7f, 241.3f) > 100.0f)
- {
- EnterEvadeMode();
- return false;
- }
- return true;
- }
-
- void Reset() override
- {
- BossAI::Reset();
- me->SetPosition(me->GetHomePosition());
- movementPhase = MOVE_PHASE_NONE;
- currentWaypoint = 0;
- me->SetReactState(REACT_AGGRESSIVE);
- events.Reset();
- events.RescheduleEvent(EVENT_MARK_CAST, 24s);
- events.RescheduleEvent(EVENT_BERSERK, 10min);
- if ((me->GetEntry() != NPC_LADY_BLAUMEUX && me->GetEntry() != NPC_SIR_ZELIEK))
- {
- events.RescheduleEvent(EVENT_PRIMARY_SPELL, 10s, 15s);
- }
- else
- {
- events.RescheduleEvent(EVENT_SECONDARY_SPELL, 15s);
- }
- }
-
- void MovementInform(uint32 type, uint32 id) override
- {
- if (type != POINT_MOTION_TYPE)
- return;
-
- // final waypoint
- if (id % 3 == 2)
- {
- movementPhase = MOVE_PHASE_FINISHED;
- me->SetReactState(REACT_AGGRESSIVE);
- me->SetInCombatWithZone();
- if (!UpdateVictim())
- {
- EnterEvadeMode();
- return;
- }
- if (me->GetEntry() == NPC_LADY_BLAUMEUX || me->GetEntry() == NPC_SIR_ZELIEK)
- {
- me->GetMotionMaster()->Clear(false);
- me->GetMotionMaster()->MoveIdle();
- }
- return;
- }
- currentWaypoint = id + 1;
- }
-
- void AttackStart(Unit* who) override
- {
- if (movementPhase == MOVE_PHASE_FINISHED)
- {
- if (me->GetEntry() == NPC_LADY_BLAUMEUX || me->GetEntry() == NPC_SIR_ZELIEK)
- {
- me->Attack(who, false);
- }
- else
- {
- ScriptedAI::AttackStart(who);
- }
- }
- }
-
- void KilledUnit(Unit* who) override
- {
- if (!who->IsPlayer())
- return;
-
- Talk(SAY_SLAY);
- instance->StorePersistentData(PERSISTENT_DATA_IMMORTAL_FAIL, 1);
- }
-
- void JustDied(Unit* killer) override
- {
- BossAI::JustDied(killer);
- Talk(SAY_DEATH);
-
- if (instance->GetBossState(BOSS_HORSEMAN) == DONE)
- if (!me->GetMap()->GetPlayers().IsEmpty())
- if (Player* player = me->GetMap()->GetPlayers().getFirst()->GetSource())
- if (GameObject* chest = player->SummonGameObject(RAID_MODE(GO_HORSEMEN_CHEST_10, GO_HORSEMEN_CHEST_25), 2514.8f, -2944.9f, 245.55f, 5.51f, 0, 0, 0, 0, 0))
- chest->SetLootRecipient(me);
- }
-
- void JustEngagedWith(Unit* who) override
- {
- BossAI::JustEngagedWith(who);
- if (movementPhase == MOVE_PHASE_NONE)
- {
- Talk(SAY_AGGRO);
- me->SetReactState(REACT_PASSIVE);
- movementPhase = MOVE_PHASE_STARTED;
- me->SetSpeed(MOVE_RUN, me->GetSpeedRate(MOVE_RUN), true);
- MoveToCorner();
- }
- }
-
- void UpdateAI(uint32 diff) override
- {
- if (movementPhase == MOVE_PHASE_STARTED && currentWaypoint)
- {
- me->GetMotionMaster()->MovePoint(currentWaypoint, WaypointPositions[currentWaypoint]);
- currentWaypoint = 0;
- }
-
- if (!IsInRoom())
- return;
-
- if (movementPhase < MOVE_PHASE_FINISHED || !UpdateVictim())
- return;
-
- events.Update(diff);
- if (me->HasUnitState(UNIT_STATE_CASTING))
- return;
-
- switch (events.ExecuteEvent())
- {
- case EVENT_MARK_CAST:
- me->CastSpell(me, TABLE_SPELL_MARK[horsemanId], false);
- events.Repeat((me->GetEntry() == NPC_LADY_BLAUMEUX || me->GetEntry() == NPC_SIR_ZELIEK) ? 15s : 12s);
- return;
- case EVENT_BERSERK:
- Talk(SAY_SPECIAL);
- me->CastSpell(me, SPELL_BERSERK, true);
- return;
- case EVENT_PRIMARY_SPELL:
- Talk(SAY_TAUNT);
- me->CastSpell(me->GetVictim(), TABLE_SPELL_PRIMARY[horsemanId], false);
- events.Repeat(15s);
- return;
- case EVENT_SECONDARY_SPELL:
- me->CastSpell(me->GetVictim(), TABLE_SPELL_SECONDARY[horsemanId], false);
- events.Repeat(15s);
- return;
- }
-
- if (me->GetEntry() == NPC_LADY_BLAUMEUX || me->GetEntry() == NPC_SIR_ZELIEK)
- {
- if (Unit* pTarget = me->SelectNearestPlayer(300.0f))
- {
- if (pTarget && me->IsValidAttackTarget(pTarget))
- {
- AttackStart(pTarget);
- }
- }
- if (me->IsWithinDistInMap(me->GetVictim(), 45.0f) && me->IsValidAttackTarget(me->GetVictim()))
- {
- DoCastVictim(TABLE_SPELL_PRIMARY[horsemanId]);
- }
- else if (!me->IsWithinDistInMap(me->GetVictim(), 45.0f) || !me->IsValidAttackTarget(me->GetVictim()))
- {
- DoCastAOE(TABLE_SPELL_PUNISH[horsemanId]);
- Talk(EMOTE_RAGECAST);
- }
- }
- else
- {
- DoMeleeAttackIfReady();
- }
- }
- };
-};
-
-class spell_four_horsemen_mark_aura : public AuraScript
-{
- PrepareAuraScript(spell_four_horsemen_mark_aura);
-
- bool Validate(SpellInfo const* /*spellInfo*/) override
- {
- return ValidateSpellInfo({ SPELL_MARK_DAMAGE });
- }
-
- void OnApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
- {
- if (Unit* caster = GetCaster())
- {
- int32 damage;
- switch (GetStackAmount())
- {
- case 1:
- damage = 0;
- break;
- case 2:
- damage = 500;
- break;
- case 3:
- damage = 1500;
- break;
- case 4:
- damage = 4000;
- break;
- case 5:
- damage = 12500;
- break;
- case 6:
- damage = 20000;
- break;
- default:
- damage = 20000 + 1000 * (GetStackAmount() - 7);
- break;
- }
- if (damage)
- {
- caster->CastCustomSpell(SPELL_MARK_DAMAGE, SPELLVALUE_BASE_POINT0, damage, GetTarget());
- }
- }
- }
-
- void Register() override
- {
- AfterEffectApply += AuraEffectApplyFn(spell_four_horsemen_mark_aura::OnApply, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL_OR_REAPPLY_MASK);
- }
-};
-
-} // namespace FourHorsemen
-
-#endif
\ No newline at end of file
diff --git a/src/server/scripts/Northrend/Naxxramas/boss_gluth.cpp b/src/server/scripts/Northrend/Naxxramas/boss_gluth.cpp
index 8eb03fe59..189b24880 100644
--- a/src/server/scripts/Northrend/Naxxramas/boss_gluth.cpp
+++ b/src/server/scripts/Northrend/Naxxramas/boss_gluth.cpp
@@ -15,7 +15,6 @@
* with this program. If not, see .
*/
-#include "boss_gluth.h"
#include "CreatureScript.h"
#include "Player.h"
#include "ScriptedCreature.h"
@@ -23,11 +22,248 @@
#include "SpellScriptLoader.h"
#include "naxxramas.h"
+enum Spells
+{
+ SPELL_MORTAL_WOUND = 25646,
+ SPELL_ENRAGE = 28371,
+ SPELL_DECIMATE = 28374,
+ SPELL_DECIMATE_DAMAGE = 28375,
+ SPELL_BERSERK = 26662,
+ SPELL_INFECTED_WOUND = 29306,
+ SPELL_CHOW_SEARCHER = 28404
+};
-using namespace Gluth;
+enum Events
+{
+ EVENT_MORTAL_WOUND = 1,
+ EVENT_ENRAGE = 2,
+ EVENT_DECIMATE = 3,
+ EVENT_BERSERK = 4,
+ EVENT_SUMMON_ZOMBIE = 5,
+ EVENT_CAN_EAT_ZOMBIE = 6
+};
-// no custom changes has been made for mod-playerbot other then placing
-// the impl in a header file
+enum Misc
+{
+ NPC_ZOMBIE_CHOW = 16360
+};
+
+enum Emotes
+{
+ EMOTE_SPOTS_ONE = 0,
+ EMOTE_DECIMATE = 1,
+ EMOTE_ENRAGE = 2,
+ EMOTE_DEVOURS_ALL = 3,
+ EMOTE_BERSERK = 4
+};
+
+const Position zombiePos[3] =
+{
+ {3267.9f, -3172.1f, 297.42f, 0.94f},
+ {3253.2f, -3132.3f, 297.42f, 0},
+ {3308.3f, -3185.8f, 297.42f, 1.58f}
+};
+
+class boss_gluth : public CreatureScript
+{
+public:
+ boss_gluth() : CreatureScript("boss_gluth") { }
+
+ CreatureAI* GetAI(Creature* pCreature) const override
+ {
+ return GetNaxxramasAI(pCreature);
+ }
+
+ struct boss_gluthAI : public BossAI
+ {
+ explicit boss_gluthAI(Creature* c) : BossAI(c, BOSS_GLUTH), summons(me)
+ {}
+
+ EventMap events;
+ SummonList summons;
+
+ void Reset() override
+ {
+ BossAI::Reset();
+ me->ApplySpellImmune(SPELL_INFECTED_WOUND, IMMUNITY_ID, SPELL_INFECTED_WOUND, true);
+ events.Reset();
+ summons.DespawnAll();
+ me->SetReactState(REACT_AGGRESSIVE);
+ }
+
+ void MoveInLineOfSight(Unit* who) override
+ {
+ if (!me->GetVictim() || me->GetVictim()->GetEntry() != NPC_ZOMBIE_CHOW)
+ {
+ if (who->GetEntry() == NPC_ZOMBIE_CHOW && me->IsWithinDistInMap(who, 6.5f))
+ {
+ SetGazeOn(who);
+ Talk(EMOTE_SPOTS_ONE);
+ }
+ else
+ {
+ ScriptedAI::MoveInLineOfSight(who);
+ }
+ }
+ }
+
+ void JustEngagedWith(Unit* who) override
+ {
+ BossAI::JustEngagedWith(who);
+ me->SetInCombatWithZone();
+ events.ScheduleEvent(EVENT_MORTAL_WOUND, 10s);
+ events.ScheduleEvent(EVENT_ENRAGE, 22s);
+ events.ScheduleEvent(EVENT_DECIMATE, RAID_MODE(110s, 90s));
+ events.ScheduleEvent(EVENT_BERSERK, 6min);
+ events.ScheduleEvent(EVENT_SUMMON_ZOMBIE, 10s);
+ events.ScheduleEvent(EVENT_CAN_EAT_ZOMBIE, 1s);
+ }
+
+ void JustSummoned(Creature* summon) override
+ {
+ if (summon->GetEntry() == NPC_ZOMBIE_CHOW)
+ {
+ summon->AI()->AttackStart(me);
+ }
+ summons.Summon(summon);
+ }
+
+ void SummonedCreatureDies(Creature* cr, Unit*) override { summons.Despawn(cr); }
+
+ void KilledUnit(Unit* who) override
+ {
+ if (me->IsAlive() && who->GetEntry() == NPC_ZOMBIE_CHOW)
+ me->ModifyHealth(int32(me->GetMaxHealth() * 0.05f));
+
+ if (who->IsPlayer())
+ instance->StorePersistentData(PERSISTENT_DATA_IMMORTAL_FAIL, 1);
+ }
+
+ void JustDied(Unit* killer) override
+ {
+ BossAI::JustDied(killer);
+ summons.DespawnAll();
+ }
+
+ bool SelectPlayerInRoom()
+ {
+ if (me->IsInCombat())
+ return false;
+
+ Map::PlayerList const& pList = me->GetMap()->GetPlayers();
+ for (auto const& itr : pList)
+ {
+ Player* player = itr.GetSource();
+ if (!player || !player->IsAlive())
+ continue;
+
+ if (player->GetPositionZ() > 300.0f || me->GetExactDist(player) > 50.0f)
+ continue;
+
+ AttackStart(player);
+ return true;
+ }
+ return false;
+ }
+
+ void UpdateAI(uint32 diff) override
+ {
+ if (!UpdateVictimWithGaze() && !SelectPlayerInRoom())
+ return;
+
+ events.Update(diff);
+ if (me->HasUnitState(UNIT_STATE_CASTING))
+ return;
+
+ switch (events.ExecuteEvent())
+ {
+ case EVENT_BERSERK:
+ me->CastSpell(me, SPELL_BERSERK, true);
+ break;
+ case EVENT_ENRAGE:
+ Talk(EMOTE_ENRAGE);
+ me->CastSpell(me, SPELL_ENRAGE, true);
+ events.Repeat(22s);
+ break;
+ case EVENT_MORTAL_WOUND:
+ me->CastSpell(me->GetVictim(), SPELL_MORTAL_WOUND, false);
+ events.Repeat(10s);
+ break;
+ case EVENT_DECIMATE:
+ Talk(EMOTE_DECIMATE);
+ me->CastSpell(me, SPELL_DECIMATE, false);
+ events.Repeat(RAID_MODE(110s, 90s));
+ break;
+ case EVENT_SUMMON_ZOMBIE:
+ {
+ uint8 rand = urand(0, 2);
+ for (int32 i = 0; i < RAID_MODE(1, 2); ++i)
+ {
+ // In 10 man raid, normal mode - should spawn only from mid gate
+ // \1 |0 /2 pos
+ // In 25 man raid - should spawn from all 3 gates
+ if (me->GetMap()->GetDifficulty() == RAID_DIFFICULTY_10MAN_NORMAL)
+ {
+ me->SummonCreature(NPC_ZOMBIE_CHOW, zombiePos[0]);
+ }
+ else
+ {
+ me->SummonCreature(NPC_ZOMBIE_CHOW, zombiePos[urand(0, 2)]);
+ }
+ (rand == 2 ? rand = 0 : rand++);
+ }
+ events.Repeat(10s);
+ break;
+ }
+ case EVENT_CAN_EAT_ZOMBIE:
+ events.Repeat(1s);
+ if (me->GetVictim()->GetEntry() == NPC_ZOMBIE_CHOW && me->IsWithinMeleeRange(me->GetVictim()))
+ {
+ me->CastCustomSpell(SPELL_CHOW_SEARCHER, SPELLVALUE_RADIUS_MOD, 20000, me, true);
+ Talk(EMOTE_DEVOURS_ALL);
+ return; // leave it to skip DoMeleeAttackIfReady
+ }
+ break;
+ }
+ DoMeleeAttackIfReady();
+ }
+ };
+};
+
+class spell_gluth_decimate : public SpellScript
+{
+ PrepareSpellScript(spell_gluth_decimate);
+
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ return ValidateSpellInfo({ SPELL_DECIMATE_DAMAGE });
+ }
+
+ void HandleScriptEffect(SpellEffIndex /*effIndex*/)
+ {
+ if (Unit* unitTarget = GetHitUnit())
+ {
+ int32 damage = int32(unitTarget->GetHealth()) - int32(unitTarget->CountPctFromMaxHealth(5));
+ if (damage <= 0)
+ return;
+
+ if (Creature* cTarget = unitTarget->ToCreature())
+ {
+ cTarget->SetWalk(true);
+ cTarget->GetMotionMaster()->MoveFollow(GetCaster(), 0.0f, 0.0f, MOTION_SLOT_CONTROLLED);
+ cTarget->SetReactState(REACT_PASSIVE);
+ Unit::DealDamage(GetCaster(), cTarget, damage);
+ return;
+ }
+ GetCaster()->CastCustomSpell(SPELL_DECIMATE_DAMAGE, SPELLVALUE_BASE_POINT0, damage, unitTarget);
+ }
+ }
+
+ void Register() override
+ {
+ OnEffectHitTarget += SpellEffectFn(spell_gluth_decimate::HandleScriptEffect, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT);
+ }
+};
void AddSC_boss_gluth()
{
diff --git a/src/server/scripts/Northrend/Naxxramas/boss_gluth.h b/src/server/scripts/Northrend/Naxxramas/boss_gluth.h
deleted file mode 100644
index da733719e..000000000
--- a/src/server/scripts/Northrend/Naxxramas/boss_gluth.h
+++ /dev/null
@@ -1,258 +0,0 @@
-#ifndef BOSSGLUTH_H_
-#define BOSSGLUTH_H_
-
-#include "Player.h"
-#include "ScriptMgr.h"
-#include "ScriptedCreature.h"
-#include "SpellScript.h"
-#include "SpellInfo.h"
-#include "naxxramas.h"
-
-namespace Gluth {
-
-enum Spells
-{
- SPELL_MORTAL_WOUND = 25646,
- SPELL_ENRAGE = 28371,
- SPELL_DECIMATE = 28374,
- SPELL_DECIMATE_DAMAGE = 28375,
- SPELL_BERSERK = 26662,
- SPELL_INFECTED_WOUND = 29306,
- SPELL_CHOW_SEARCHER = 28404
-};
-
-enum Events
-{
- EVENT_MORTAL_WOUND = 1,
- EVENT_ENRAGE = 2,
- EVENT_DECIMATE = 3,
- EVENT_BERSERK = 4,
- EVENT_SUMMON_ZOMBIE = 5,
- EVENT_CAN_EAT_ZOMBIE = 6
-};
-
-enum Misc
-{
- NPC_ZOMBIE_CHOW = 16360
-};
-
-enum Emotes
-{
- EMOTE_SPOTS_ONE = 0,
- EMOTE_DECIMATE = 1,
- EMOTE_ENRAGE = 2,
- EMOTE_DEVOURS_ALL = 3,
- EMOTE_BERSERK = 4
-};
-
-const Position zombiePos[3] =
-{
- {3267.9f, -3172.1f, 297.42f, 0.94f},
- {3253.2f, -3132.3f, 297.42f, 0},
- {3308.3f, -3185.8f, 297.42f, 1.58f}
-};
-
-class boss_gluth : public CreatureScript
-{
-public:
- boss_gluth() : CreatureScript("boss_gluth") { }
-
- CreatureAI* GetAI(Creature* pCreature) const override
- {
- return GetNaxxramasAI(pCreature);
- }
-
- struct boss_gluthAI : public BossAI
- {
- explicit boss_gluthAI(Creature* c) : BossAI(c, BOSS_GLUTH), summons(me)
- {}
-
- EventMap events;
- SummonList summons;
-
- void Reset() override
- {
- BossAI::Reset();
- me->ApplySpellImmune(SPELL_INFECTED_WOUND, IMMUNITY_ID, SPELL_INFECTED_WOUND, true);
- events.Reset();
- summons.DespawnAll();
- me->SetReactState(REACT_AGGRESSIVE);
- }
-
- void MoveInLineOfSight(Unit* who) override
- {
- if (!me->GetVictim() || me->GetVictim()->GetEntry() != NPC_ZOMBIE_CHOW)
- {
- if (who->GetEntry() == NPC_ZOMBIE_CHOW && me->IsWithinDistInMap(who, 6.5f))
- {
- SetGazeOn(who);
- Talk(EMOTE_SPOTS_ONE);
- }
- else
- {
- ScriptedAI::MoveInLineOfSight(who);
- }
- }
- }
-
- void JustEngagedWith(Unit* who) override
- {
- BossAI::JustEngagedWith(who);
- me->SetInCombatWithZone();
- events.ScheduleEvent(EVENT_MORTAL_WOUND, 10s);
- events.ScheduleEvent(EVENT_ENRAGE, 22s);
- events.ScheduleEvent(EVENT_DECIMATE, RAID_MODE(110s, 90s));
- events.ScheduleEvent(EVENT_BERSERK, 6min);
- events.ScheduleEvent(EVENT_SUMMON_ZOMBIE, 10s);
- events.ScheduleEvent(EVENT_CAN_EAT_ZOMBIE, 1s);
- }
-
- void JustSummoned(Creature* summon) override
- {
- if (summon->GetEntry() == NPC_ZOMBIE_CHOW)
- {
- summon->AI()->AttackStart(me);
- }
- summons.Summon(summon);
- }
-
- void SummonedCreatureDies(Creature* cr, Unit*) override { summons.Despawn(cr); }
-
- void KilledUnit(Unit* who) override
- {
- if (me->IsAlive() && who->GetEntry() == NPC_ZOMBIE_CHOW)
- me->ModifyHealth(int32(me->GetMaxHealth() * 0.05f));
-
- if (who->IsPlayer())
- instance->StorePersistentData(PERSISTENT_DATA_IMMORTAL_FAIL, 1);
- }
-
- void JustDied(Unit* killer) override
- {
- BossAI::JustDied(killer);
- summons.DespawnAll();
- }
-
- bool SelectPlayerInRoom()
- {
- if (me->IsInCombat())
- return false;
-
- Map::PlayerList const& pList = me->GetMap()->GetPlayers();
- for (auto const& itr : pList)
- {
- Player* player = itr.GetSource();
- if (!player || !player->IsAlive())
- continue;
-
- if (player->GetPositionZ() > 300.0f || me->GetExactDist(player) > 50.0f)
- continue;
-
- AttackStart(player);
- return true;
- }
- return false;
- }
-
- void UpdateAI(uint32 diff) override
- {
- if (!UpdateVictimWithGaze() && !SelectPlayerInRoom())
- return;
-
- events.Update(diff);
- if (me->HasUnitState(UNIT_STATE_CASTING))
- return;
-
- switch (events.ExecuteEvent())
- {
- case EVENT_BERSERK:
- me->CastSpell(me, SPELL_BERSERK, true);
- break;
- case EVENT_ENRAGE:
- Talk(EMOTE_ENRAGE);
- me->CastSpell(me, SPELL_ENRAGE, true);
- events.Repeat(22s);
- break;
- case EVENT_MORTAL_WOUND:
- me->CastSpell(me->GetVictim(), SPELL_MORTAL_WOUND, false);
- events.Repeat(10s);
- break;
- case EVENT_DECIMATE:
- Talk(EMOTE_DECIMATE);
- me->CastSpell(me, SPELL_DECIMATE, false);
- events.Repeat(RAID_MODE(110s, 90s));
- break;
- case EVENT_SUMMON_ZOMBIE:
- {
- uint8 rand = urand(0, 2);
- for (int32 i = 0; i < RAID_MODE(1, 2); ++i)
- {
- // In 10 man raid, normal mode - should spawn only from mid gate
- // \1 |0 /2 pos
- // In 25 man raid - should spawn from all 3 gates
- if (me->GetMap()->GetDifficulty() == RAID_DIFFICULTY_10MAN_NORMAL)
- {
- me->SummonCreature(NPC_ZOMBIE_CHOW, zombiePos[0]);
- }
- else
- {
- me->SummonCreature(NPC_ZOMBIE_CHOW, zombiePos[urand(0, 2)]);
- }
- (rand == 2 ? rand = 0 : rand++);
- }
- events.Repeat(10s);
- break;
- }
- case EVENT_CAN_EAT_ZOMBIE:
- events.Repeat(1s);
- if (me->GetVictim()->GetEntry() == NPC_ZOMBIE_CHOW && me->IsWithinMeleeRange(me->GetVictim()))
- {
- me->CastCustomSpell(SPELL_CHOW_SEARCHER, SPELLVALUE_RADIUS_MOD, 20000, me, true);
- Talk(EMOTE_DEVOURS_ALL);
- return; // leave it to skip DoMeleeAttackIfReady
- }
- break;
- }
- DoMeleeAttackIfReady();
- }
- };
-};
-
-class spell_gluth_decimate : public SpellScript
-{
- PrepareSpellScript(spell_gluth_decimate);
-
- bool Validate(SpellInfo const* /*spellInfo*/) override
- {
- return ValidateSpellInfo({ SPELL_DECIMATE_DAMAGE });
- }
-
- void HandleScriptEffect(SpellEffIndex /*effIndex*/)
- {
- if (Unit* unitTarget = GetHitUnit())
- {
- int32 damage = int32(unitTarget->GetHealth()) - int32(unitTarget->CountPctFromMaxHealth(5));
- if (damage <= 0)
- return;
-
- if (Creature* cTarget = unitTarget->ToCreature())
- {
- cTarget->SetWalk(true);
- cTarget->GetMotionMaster()->MoveFollow(GetCaster(), 0.0f, 0.0f, MOTION_SLOT_CONTROLLED);
- cTarget->SetReactState(REACT_PASSIVE);
- Unit::DealDamage(GetCaster(), cTarget, damage);
- return;
- }
- GetCaster()->CastCustomSpell(SPELL_DECIMATE_DAMAGE, SPELLVALUE_BASE_POINT0, damage, unitTarget);
- }
- }
-
- void Register() override
- {
- OnEffectHitTarget += SpellEffectFn(spell_gluth_decimate::HandleScriptEffect, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT);
- }
-};
-
-}
-
-#endif
\ No newline at end of file
diff --git a/src/server/scripts/Northrend/Naxxramas/boss_gothik.cpp b/src/server/scripts/Northrend/Naxxramas/boss_gothik.cpp
index 46f97a5e4..23eb083d2 100644
--- a/src/server/scripts/Northrend/Naxxramas/boss_gothik.cpp
+++ b/src/server/scripts/Northrend/Naxxramas/boss_gothik.cpp
@@ -15,7 +15,6 @@
* with this program. If not, see .
*/
-#include "boss_gothik.h"
#include "CombatAI.h"
#include "CreatureScript.h"
#include "GridNotifiers.h"
@@ -24,11 +23,730 @@
#include "SpellScriptLoader.h"
#include "naxxramas.h"
+enum Yells
+{
+ SAY_INTRO_1 = 0,
+ SAY_INTRO_2 = 1,
+ SAY_INTRO_3 = 2,
+ SAY_INTRO_4 = 3,
+ SAY_PHASE_TWO = 4,
+ SAY_DEATH = 5,
+ SAY_KILL = 6,
-using namespace Gothik;
+ EMOTE_PHASE_TWO = 7,
+ EMOTE_GATE_OPENED = 8
+};
-// no custom changes has been made for mod-playerbot other then placing
-// the impl in a header file
+enum Spells
+{
+ // Gothik
+ SPELL_HARVEST_SOUL = 28679,
+ SPELL_SHADOW_BOLT = 29317,
+ // Teleport spells
+ SPELL_TELEPORT_DEAD = 28025,
+ SPELL_TELEPORT_LIVE = 28026,
+ // Visual spells
+ SPELL_ANCHOR_1_TRAINEE = 27892,
+ SPELL_ANCHOR_1_DK = 27928,
+ SPELL_ANCHOR_1_RIDER = 27935,
+ SPELL_ANCHOR_2_TRAINEE = 27893,
+ SPELL_ANCHOR_2_DK = 27929,
+ SPELL_ANCHOR_2_RIDER = 27936,
+ SPELL_SKULLS_TRAINEE = 27915,
+ SPELL_SKULLS_DK = 27931,
+ SPELL_SKULLS_RIDER = 27937,
+ // Living trainee
+ SPELL_DEATH_PLAGUE = 55604,
+ // Dead trainee
+ SPELL_ARCANE_EXPLOSION = 27989,
+ // Living knight
+ SPELL_SHADOW_MARK = 27825,
+ // Dead knight
+ SPELL_WHIRLWIND = 56408,
+ // Living rider
+ SPELL_SHADOW_BOLT_VOLLEY = 27831,
+ // Dead rider
+ SPELL_DRAIN_LIFE = 27994,
+ SPELL_UNHOLY_FRENZY = 55648,
+ // Horse
+ SPELL_STOMP = 27993
+};
+
+enum Misc
+{
+ NPC_LIVING_TRAINEE = 16124,
+ NPC_LIVING_KNIGHT = 16125,
+ NPC_LIVING_RIDER = 16126,
+ NPC_DEAD_TRAINEE = 16127,
+ NPC_DEAD_KNIGHT = 16148,
+ NPC_DEAD_HORSE = 16149,
+ NPC_DEAD_RIDER = 16150,
+ NPC_TRIGGER = 16137
+};
+
+enum Events
+{
+ // Gothik
+ EVENT_SUMMON_ADDS = 1,
+ EVENT_HARVEST_SOUL = 2,
+ EVENT_SHADOW_BOLT = 3,
+ EVENT_TELEPORT = 4,
+ EVENT_CHECK_HEALTH = 5,
+ EVENT_CHECK_PLAYERS = 6,
+ // Living trainee
+ EVENT_DEATH_PLAGUE = 7,
+ // Dead trainee
+ EVENT_ARCANE_EXPLOSION = 8,
+ // Living knight
+ EVENT_SHADOW_MARK = 9,
+ // Dead knight
+ EVENT_WHIRLWIND = 10,
+ // Living rider
+ EVENT_SHADOW_BOLT_VOLLEY = 11,
+ // Dead rider
+ EVENT_DRAIN_LIFE = 12,
+ EVENT_UNHOLY_FRENZY = 13,
+ // HORSE
+ EVENT_STOMP = 14,
+ // Intro
+ EVENT_INTRO_2 = 15,
+ EVENT_INTRO_3 = 16,
+ EVENT_INTRO_4 = 17
+};
+
+const uint32 gothikWaves[24][2] =
+{
+ {NPC_LIVING_TRAINEE, 20000},
+ {NPC_LIVING_TRAINEE, 20000},
+ {NPC_LIVING_TRAINEE, 10000},
+ {NPC_LIVING_KNIGHT, 10000},
+ {NPC_LIVING_TRAINEE, 15000},
+ {NPC_LIVING_KNIGHT, 10000},
+ {NPC_LIVING_TRAINEE, 15000},
+ {NPC_LIVING_TRAINEE, 0},
+ {NPC_LIVING_KNIGHT, 10000},
+ {NPC_LIVING_RIDER, 10000},
+ {NPC_LIVING_TRAINEE, 5000},
+ {NPC_LIVING_KNIGHT, 15000},
+ {NPC_LIVING_RIDER, 0},
+ {NPC_LIVING_TRAINEE, 10000},
+ {NPC_LIVING_KNIGHT, 10000},
+ {NPC_LIVING_TRAINEE, 10000},
+ {NPC_LIVING_RIDER, 5000},
+ {NPC_LIVING_KNIGHT, 5000},
+ {NPC_LIVING_TRAINEE, 20000},
+ {NPC_LIVING_RIDER, 0},
+ {NPC_LIVING_KNIGHT, 0},
+ {NPC_LIVING_TRAINEE, 15000},
+ {NPC_LIVING_TRAINEE, 29000},
+ {0, 0}
+};
+
+const Position PosSummonLiving[6] =
+{
+ {2669.7f, -3428.76f, 268.56f, 1.6f},
+ {2692.1f, -3428.76f, 268.56f, 1.6f},
+ {2714.4f, -3428.76f, 268.56f, 1.6f},
+ {2669.7f, -3431.67f, 268.56f, 1.6f},
+ {2692.1f, -3431.67f, 268.56f, 1.6f},
+ {2714.4f, -3431.67f, 268.56f, 1.6f}
+};
+
+const Position PosSummonDead[5] =
+{
+ {2725.1f, -3310.0f, 268.85f, 3.4f},
+ {2699.3f, -3322.8f, 268.60f, 3.3f},
+ {2733.1f, -3348.5f, 268.84f, 3.1f},
+ {2682.8f, -3304.2f, 268.85f, 3.9f},
+ {2664.8f, -3340.7f, 268.23f, 3.7f}
+};
+
+//const Position PosGroundLivingSide = {2691.2f, -3387.0f, 267.68f, 1.52f};
+//const Position PosGroundDeadSide = {2693.5f, -3334.6f, 267.68f, 4.67f};
+//const Position PosPlatform = {2640.5f, -3360.6f, 285.26f, 0.0f};
+
+#define POS_Y_GATE -3360.78f
+#define POS_Y_WEST -3285.0f
+#define POS_Y_EAST -3434.0f
+#define POS_X_NORTH 2750.49f
+#define POS_X_SOUTH 2633.84f
+#define IN_LIVE_SIDE(who) (who->GetPositionY() < POS_Y_GATE)
+
+// Predicate function to check that the r efzr unit is NOT on the same side as the source.
+struct NotOnSameSide
+{
+public:
+ explicit NotOnSameSide(Unit* pSource) : m_inLiveSide(IN_LIVE_SIDE(pSource)) { }
+
+ bool operator() (Unit const* pTarget)
+ {
+ return (m_inLiveSide != IN_LIVE_SIDE(pTarget));
+ }
+
+private:
+ bool m_inLiveSide;
+};
+
+class boss_gothik : public CreatureScript
+{
+public:
+ boss_gothik() : CreatureScript("boss_gothik") { }
+
+ CreatureAI* GetAI(Creature* pCreature) const override
+ {
+ return GetNaxxramasAI(pCreature);
+ }
+
+ struct boss_gothikAI : public BossAI
+ {
+ explicit boss_gothikAI(Creature* c) : BossAI(c, BOSS_GOTHIK), summons(me)
+ {}
+
+ EventMap events;
+ SummonList summons;
+ bool secondPhase{};
+ bool gateOpened{};
+ uint8 waveCount{};
+
+ bool IsInRoom()
+ {
+ if (me->GetPositionX() > 2767 || me->GetPositionX() < 2618 || me->GetPositionY() > -3285 || me->GetPositionY() < -3435)
+ {
+ EnterEvadeMode();
+ return false;
+ }
+ return true;
+ }
+
+ void Reset() override
+ {
+ BossAI::Reset();
+ events.Reset();
+ summons.DespawnAll();
+ me->RemoveUnitFlag(UNIT_FLAG_DISABLE_MOVE);
+ me->SetImmuneToPC(false);
+ me->SetReactState(REACT_PASSIVE);
+ secondPhase = false;
+ gateOpened = false;
+ waveCount = 0;
+ me->NearTeleportTo(2642.139f, -3386.959f, 285.492f, 6.265f);
+ }
+
+ void JustEngagedWith(Unit* who) override
+ {
+ BossAI::JustEngagedWith(who);
+ me->SetInCombatWithZone();
+ Talk(SAY_INTRO_1);
+ events.ScheduleEvent(EVENT_INTRO_2, 4s);
+ events.ScheduleEvent(EVENT_INTRO_3, 9s);
+ events.ScheduleEvent(EVENT_INTRO_4, 14s);
+ me->SetUnitFlag(UNIT_FLAG_DISABLE_MOVE);
+ events.ScheduleEvent(EVENT_SUMMON_ADDS, 30s);
+ events.ScheduleEvent(EVENT_CHECK_PLAYERS, 2min);
+ }
+
+ void JustSummoned(Creature* summon) override
+ {
+ summons.Summon(summon);
+ // If central gate is open, attack any one
+ if (gateOpened)
+ {
+ if (Unit* target = SelectTarget(SelectTargetMethod::MinDistance, 0, 200.0f))
+ {
+ summon->AI()->AttackStart(target);
+ summon->SetInCombatWithZone();
+ summon->SetReactState(REACT_AGGRESSIVE);
+ summon->CallForHelp(150.0f);
+ }
+ }
+ // Else look for a random target on the side the summoned NPC is
+ else
+ {
+ Map::PlayerList const& pList = me->GetMap()->GetPlayers();
+ std::vector tList;
+ for(Map::PlayerList::const_iterator itr = pList.begin(); itr != pList.end(); ++itr)
+ {
+ if (!me->IsWithinDistInMap(itr->GetSource(), 200.0f, true, false, false) || !itr->GetSource()->IsAlive() || itr->GetSource()->IsGameMaster())
+ {
+ continue;
+ }
+ if (IN_LIVE_SIDE(itr->GetSource()) != IN_LIVE_SIDE(summon))
+ {
+ continue;
+ }
+ tList.push_back(itr->GetSource());
+ }
+ if (!tList.empty())
+ {
+ Player* target = tList[urand(0, tList.size() - 1)];
+ summon->AI()->AttackStart(target);
+ summon->SetInCombatWithZone();
+ summon->SetReactState(REACT_AGGRESSIVE);
+ summon->CallForHelp(150.0f);
+ }
+ }
+ }
+
+ void SummonedCreatureDespawn(Creature* cr) override
+ {
+ summons.Despawn(cr);
+ }
+
+ void KilledUnit(Unit* who) override
+ {
+ if (!who->IsPlayer())
+ return;
+
+ Talk(SAY_KILL);
+ instance->StorePersistentData(PERSISTENT_DATA_IMMORTAL_FAIL, 1);
+ }
+
+ void JustDied(Unit* killer) override
+ {
+ BossAI::JustDied(killer);
+ Talk(SAY_DEATH);
+ summons.DespawnAll();
+ }
+
+ void SummonHelpers(uint32 entry)
+ {
+ switch (entry)
+ {
+ case NPC_LIVING_TRAINEE:
+ me->SummonCreature(NPC_LIVING_TRAINEE, PosSummonLiving[0].GetPositionX(), PosSummonLiving[0].GetPositionY(), PosSummonLiving[0].GetPositionZ(), PosSummonLiving[0].GetOrientation());
+ me->SummonCreature(NPC_LIVING_TRAINEE, PosSummonLiving[1].GetPositionX(), PosSummonLiving[1].GetPositionY(), PosSummonLiving[1].GetPositionZ(), PosSummonLiving[1].GetOrientation());
+ if (Is25ManRaid())
+ {
+ me->SummonCreature(NPC_LIVING_TRAINEE, PosSummonLiving[2].GetPositionX(), PosSummonLiving[2].GetPositionY(), PosSummonLiving[2].GetPositionZ(), PosSummonLiving[2].GetOrientation());
+ }
+ break;
+ case NPC_LIVING_KNIGHT:
+ me->SummonCreature(NPC_LIVING_KNIGHT, PosSummonLiving[3].GetPositionX(), PosSummonLiving[3].GetPositionY(), PosSummonLiving[3].GetPositionZ(), PosSummonLiving[3].GetOrientation());
+ if (Is25ManRaid())
+ {
+ me->SummonCreature(NPC_LIVING_KNIGHT, PosSummonLiving[5].GetPositionX(), PosSummonLiving[5].GetPositionY(), PosSummonLiving[5].GetPositionZ(), PosSummonLiving[5].GetOrientation());
+ }
+ break;
+ case NPC_LIVING_RIDER:
+ me->SummonCreature(NPC_LIVING_RIDER, PosSummonLiving[4].GetPositionX(), PosSummonLiving[4].GetPositionY(), PosSummonLiving[4].GetPositionZ(), PosSummonLiving[4].GetOrientation());
+ break;
+ }
+ }
+
+ bool CheckGroupSplitted()
+ {
+ Map::PlayerList const& PlayerList = me->GetMap()->GetPlayers();
+ if (!PlayerList.IsEmpty())
+ {
+ bool checklife = false;
+ bool checkdead = false;
+ for (auto const& i : PlayerList)
+ {
+ Player* player = i.GetSource();
+ if (player->IsAlive() &&
+ player->GetPositionX() <= POS_X_NORTH &&
+ player->GetPositionX() >= POS_X_SOUTH &&
+ player->GetPositionY() <= POS_Y_GATE &&
+ player->GetPositionY() >= POS_Y_EAST)
+ {
+ checklife = true;
+ }
+ else if (player->IsAlive() &&
+ player->GetPositionX() <= POS_X_NORTH &&
+ player->GetPositionX() >= POS_X_SOUTH &&
+ player->GetPositionY() >= POS_Y_GATE &&
+ player->GetPositionY() <= POS_Y_WEST)
+ {
+ checkdead = true;
+ }
+
+ if (checklife && checkdead)
+ return true;
+ }
+ }
+ return false;
+ }
+
+ void DamageTaken(Unit*, uint32& damage, DamageEffectType, SpellSchoolMask) override
+ {
+ if (!secondPhase)
+ {
+ damage = 0;
+ }
+ }
+
+ void UpdateAI(uint32 diff) override
+ {
+ if (!IsInRoom())
+ return;
+
+ if (!UpdateVictim())
+ return;
+
+ events.Update(diff);
+ if (me->HasUnitState(UNIT_STATE_CASTING))
+ return;
+
+ switch (events.ExecuteEvent())
+ {
+ case EVENT_INTRO_2:
+ Talk(SAY_INTRO_2);
+ break;
+ case EVENT_INTRO_3:
+ Talk(SAY_INTRO_3);
+ break;
+ case EVENT_INTRO_4:
+ Talk(SAY_INTRO_4);
+ break;
+ case EVENT_SHADOW_BOLT:
+ me->CastSpell(me->GetVictim(), SPELL_SHADOW_BOLT, false);
+ events.Repeat(1s);
+ break;
+ case EVENT_HARVEST_SOUL:
+ me->CastSpell(me, SPELL_HARVEST_SOUL, false);
+ events.Repeat(15s);
+ break;
+ case EVENT_TELEPORT:
+ me->AttackStop();
+ if (IN_LIVE_SIDE(me))
+ {
+ me->CastSpell(me, SPELL_TELEPORT_DEAD, false);
+ }
+ else
+ {
+ me->CastSpell(me, SPELL_TELEPORT_LIVE, false);
+ }
+ me->GetThreatMgr().resetAggro(NotOnSameSide(me));
+ if (Unit* pTarget = SelectTarget(SelectTargetMethod::MaxDistance, 0))
+ {
+ me->GetThreatMgr().AddThreat(pTarget, 100.0f);
+ AttackStart(pTarget);
+ }
+ events.Repeat(20s);
+ break;
+ case EVENT_CHECK_HEALTH:
+ if (me->HealthBelowPct(30))
+ {
+ if (GameObject* go = instance->GetGameObject(DATA_GOTHIK_INNER_GATE))
+ go->SetGoState(GO_STATE_ACTIVE);
+
+ events.CancelEvent(EVENT_TELEPORT);
+ break;
+ }
+ events.Repeat(1s);
+ break;
+ case EVENT_SUMMON_ADDS:
+ if (gothikWaves[waveCount][0])
+ {
+ SummonHelpers(gothikWaves[waveCount][0]);
+ events.Repeat(Milliseconds(gothikWaves[waveCount][1]));
+ }
+ else
+ {
+ secondPhase = true;
+ Talk(SAY_PHASE_TWO);
+ Talk(EMOTE_PHASE_TWO);
+ me->CastSpell(me, SPELL_TELEPORT_LIVE, false);
+ me->SetReactState(REACT_AGGRESSIVE);
+ me->RemoveUnitFlag(UNIT_FLAG_DISABLE_MOVE);
+ me->SetImmuneToPC(false);
+ me->RemoveAllAuras();
+ events.ScheduleEvent(EVENT_SHADOW_BOLT, 1s);
+ events.ScheduleEvent(EVENT_HARVEST_SOUL, 5s, 15s);
+ events.ScheduleEvent(EVENT_TELEPORT, 20s);
+ events.ScheduleEvent(EVENT_CHECK_HEALTH, 1s);
+ }
+ waveCount++;
+ break;
+ case EVENT_CHECK_PLAYERS:
+ if (!CheckGroupSplitted())
+ {
+ if (GameObject* go = instance->GetGameObject(DATA_GOTHIK_INNER_GATE))
+ go->SetGoState(GO_STATE_ACTIVE);
+
+ gateOpened = true;
+ Talk(EMOTE_GATE_OPENED);
+ }
+ break;
+ }
+ DoMeleeAttackIfReady();
+ }
+ };
+};
+
+class npc_boss_gothik_minion : public CreatureScript
+{
+public:
+ npc_boss_gothik_minion() : CreatureScript("npc_boss_gothik_minion") { }
+
+ CreatureAI* GetAI(Creature* pCreature) const override
+ {
+ return GetNaxxramasAI(pCreature);
+ }
+
+ struct npc_boss_gothik_minionAI : public CombatAI
+ {
+ explicit npc_boss_gothik_minionAI(Creature* c) : CombatAI(c)
+ {
+ livingSide = IN_LIVE_SIDE(me);
+ }
+ EventMap events;
+ bool livingSide;
+ bool IsOnSameSide(Unit const* who) const { return livingSide == IN_LIVE_SIDE(who); }
+
+ void Reset() override
+ {
+ me->SetReactState(REACT_AGGRESSIVE);
+ me->SetNoCallAssistance(false);
+ events.Reset();
+ }
+
+ void JustEngagedWith(Unit* /*who*/) override
+ {
+ switch (me->GetEntry())
+ {
+ case NPC_LIVING_TRAINEE:
+ events.ScheduleEvent(EVENT_DEATH_PLAGUE, 3s);
+ break;
+ case NPC_DEAD_TRAINEE:
+ events.ScheduleEvent(EVENT_ARCANE_EXPLOSION, 2500ms);
+ break;
+ case NPC_LIVING_KNIGHT:
+ events.ScheduleEvent(EVENT_SHADOW_MARK, 3s);
+ break;
+ case NPC_DEAD_KNIGHT:
+ events.ScheduleEvent(EVENT_WHIRLWIND, 2s);
+ break;
+ case NPC_LIVING_RIDER:
+ events.ScheduleEvent(EVENT_SHADOW_BOLT_VOLLEY, 3s);
+ break;
+ case NPC_DEAD_RIDER:
+ events.ScheduleEvent(EVENT_DRAIN_LIFE, 2s, 3500ms);
+ events.ScheduleEvent(EVENT_UNHOLY_FRENZY, 5s, 9s);
+ break;
+ case NPC_DEAD_HORSE:
+ events.ScheduleEvent(EVENT_STOMP, 2s, 5s);
+ break;
+ }
+ }
+
+ void JustDied(Unit*) override
+ {
+ switch (me->GetEntry())
+ {
+ case NPC_LIVING_TRAINEE:
+ DoCastAOE(SPELL_ANCHOR_1_TRAINEE, true);
+ break;
+ case NPC_LIVING_KNIGHT:
+ DoCastAOE(SPELL_ANCHOR_1_DK, true);
+ break;
+ case NPC_LIVING_RIDER:
+ DoCastAOE(SPELL_ANCHOR_1_RIDER, true);
+ break;
+ }
+ }
+
+ void KilledUnit(Unit* who) override
+ {
+ if (who->IsPlayer())
+ me->GetInstanceScript()->StorePersistentData(PERSISTENT_DATA_IMMORTAL_FAIL, 1);
+ }
+
+ void UpdateAI(uint32 diff) override
+ {
+ events.Update(diff);
+ if (me->GetUnitState() == UNIT_STATE_CASTING)
+ return;
+
+ switch (events.ExecuteEvent())
+ {
+ case EVENT_DEATH_PLAGUE:
+ me->CastSpell(me->GetVictim(), SPELL_DEATH_PLAGUE, false);
+ events.Repeat(4s, 7s);
+ break;
+ case EVENT_ARCANE_EXPLOSION:
+ if (Unit* victim = me->GetVictim())
+ {
+ if (victim->IsWithinDist(me, 20))
+ {
+ me->CastSpell(victim, SPELL_ARCANE_EXPLOSION, false);
+ }
+ }
+ events.Repeat(2500ms);
+ break;
+ case EVENT_SHADOW_MARK:
+ if (Unit* victim = me->GetVictim())
+ {
+ if (victim->IsWithinDist(me, 10))
+ {
+ me->CastSpell(victim, SPELL_SHADOW_MARK, false);
+ }
+ }
+ events.Repeat(5s, 7s);
+ break;
+ case EVENT_WHIRLWIND:
+ if (Unit* victim = me->GetVictim())
+ {
+ if (victim->IsWithinDist(me, 10))
+ {
+ me->CastSpell(victim, SPELL_WHIRLWIND, false);
+ }
+ }
+ events.Repeat(4s, 6s);
+ break;
+ case EVENT_SHADOW_BOLT_VOLLEY:
+ me->CastSpell(me->GetVictim(), SPELL_SHADOW_BOLT_VOLLEY, false);
+ events.Repeat(5s);
+ break;
+ case EVENT_DRAIN_LIFE:
+ if (Unit* victim = me->GetVictim())
+ {
+ if (victim->IsWithinDist(me, 20))
+ {
+ me->CastSpell(victim, SPELL_DRAIN_LIFE, false);
+ }
+ }
+ events.Repeat(8s, 12s);
+ break;
+ case EVENT_UNHOLY_FRENZY:
+ me->AddAura(SPELL_UNHOLY_FRENZY, me);
+ events.Repeat(15s, 17s);
+ break;
+ case EVENT_STOMP:
+ if (Unit* victim = me->GetVictim())
+ {
+ if (victim->IsWithinDist(me, 10))
+ {
+ me->CastSpell(victim, SPELL_STOMP, false);
+ }
+ }
+ events.Repeat(4s, 9s);
+ break;
+ }
+ DoMeleeAttackIfReady();
+ }
+ };
+};
+
+class npc_gothik_trigger : public CreatureScript
+{
+public:
+ npc_gothik_trigger() : CreatureScript("npc_gothik_trigger") { }
+
+ CreatureAI* GetAI(Creature* creature) const override
+ {
+ return new npc_gothik_triggerAI(creature);
+ }
+
+ struct npc_gothik_triggerAI : public ScriptedAI
+ {
+ npc_gothik_triggerAI(Creature* creature) : ScriptedAI(creature) { creature->SetDisableGravity(true); }
+
+ void EnterEvadeMode(EvadeReason /*why*/) override {}
+ void UpdateAI(uint32 /*diff*/) override {}
+ void JustEngagedWith(Unit* /*who*/) override {}
+ void DamageTaken(Unit* /*who*/, uint32& damage, DamageEffectType /*damagetype*/, SpellSchoolMask /*damageSchoolMask*/) override { damage = 0; }
+
+ Creature* SelectRandomSkullPile()
+ {
+ std::list triggers;
+ me->GetCreatureListWithEntryInGrid(triggers, NPC_TRIGGER, 150.0f);
+ // Remove triggers that are on live side or soul triggers on the platform
+ triggers.remove_if([](Creature* trigger){
+ return ((trigger->GetPositionY() < POS_Y_GATE) || (trigger->GetPositionZ() > 280.0f));
+ });
+ if (!triggers.empty())
+ {
+ std::list::iterator itr = triggers.begin();
+ std::advance(itr, urand(0, triggers.size() - 1));
+ return *itr;
+ }
+ return nullptr;
+ }
+
+ void SpellHit(Unit* /*caster*/, SpellInfo const* spell) override
+ {
+ if (!spell)
+ {
+ return;
+ }
+
+ switch (spell->Id)
+ {
+ case SPELL_ANCHOR_1_TRAINEE:
+ DoCastAOE(SPELL_ANCHOR_2_TRAINEE, true);
+ break;
+ case SPELL_ANCHOR_1_DK:
+ DoCastAOE(SPELL_ANCHOR_2_DK, true);
+ break;
+ case SPELL_ANCHOR_1_RIDER:
+ DoCastAOE(SPELL_ANCHOR_2_RIDER, true);
+ break;
+ case SPELL_ANCHOR_2_TRAINEE:
+ if (Creature* target = SelectRandomSkullPile())
+ {
+ DoCast(target, SPELL_SKULLS_TRAINEE, true);
+ }
+ break;
+ case SPELL_ANCHOR_2_DK:
+ if (Creature* target = SelectRandomSkullPile())
+ {
+ DoCast(target, SPELL_SKULLS_DK, true);
+ }
+ break;
+ case SPELL_ANCHOR_2_RIDER:
+ if (Creature* target = SelectRandomSkullPile())
+ {
+ DoCast(target, SPELL_SKULLS_RIDER, true);
+ }
+ break;
+ case SPELL_SKULLS_TRAINEE:
+ DoSummon(NPC_DEAD_TRAINEE, me, 0.0f, 15 * IN_MILLISECONDS, TEMPSUMMON_CORPSE_TIMED_DESPAWN);
+ break;
+ case SPELL_SKULLS_DK:
+ DoSummon(NPC_DEAD_KNIGHT, me, 0.0f, 15 * IN_MILLISECONDS, TEMPSUMMON_CORPSE_TIMED_DESPAWN);
+ break;
+ case SPELL_SKULLS_RIDER:
+ DoSummon(NPC_DEAD_RIDER, me, 0.0f, 15 * IN_MILLISECONDS, TEMPSUMMON_CORPSE_TIMED_DESPAWN);
+ DoSummon(NPC_DEAD_HORSE, me, 0.0f, 15 * IN_MILLISECONDS, TEMPSUMMON_CORPSE_TIMED_DESPAWN);
+ break;
+ }
+ }
+
+ // dead side summons are "owned" by gothik
+ void JustSummoned(Creature* summon) override
+ {
+ if (Creature* gothik = me->GetInstanceScript()->GetCreature(DATA_GOTHIK_BOSS))
+ gothik->AI()->JustSummoned(summon);
+ }
+
+ void SummonedCreatureDespawn(Creature* summon) override
+ {
+ if (Creature* gothik = me->GetInstanceScript()->GetCreature(DATA_GOTHIK_BOSS))
+ gothik->AI()->SummonedCreatureDespawn(summon);
+ }
+ };
+};
+
+class spell_gothik_shadow_bolt_volley : public SpellScript
+{
+ PrepareSpellScript(spell_gothik_shadow_bolt_volley);
+
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ return ValidateSpellInfo({ SPELL_SHADOW_MARK });
+ }
+
+ void FilterTargets(std::list& targets)
+ {
+ targets.remove_if(Acore::UnitAuraCheck(false, SPELL_SHADOW_MARK));
+ }
+
+ void Register() override
+ {
+ OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_gothik_shadow_bolt_volley::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY);
+ }
+};
void AddSC_boss_gothik()
{
diff --git a/src/server/scripts/Northrend/Naxxramas/boss_gothik.h b/src/server/scripts/Northrend/Naxxramas/boss_gothik.h
deleted file mode 100644
index 9edfd0d7b..000000000
--- a/src/server/scripts/Northrend/Naxxramas/boss_gothik.h
+++ /dev/null
@@ -1,741 +0,0 @@
-#ifndef BOSSGOTHIK_H_
-#define BOSSGOTHIK_H_
-
-#include "CombatAI.h"
-#include "GridNotifiers.h"
-#include "ScriptMgr.h"
-#include "ScriptedCreature.h"
-#include "SpellScript.h"
-#include "SpellInfo.h"
-#include "naxxramas.h"
-
-namespace Gothik {
-
-enum Yells
-{
- SAY_INTRO_1 = 0,
- SAY_INTRO_2 = 1,
- SAY_INTRO_3 = 2,
- SAY_INTRO_4 = 3,
- SAY_PHASE_TWO = 4,
- SAY_DEATH = 5,
- SAY_KILL = 6,
-
- EMOTE_PHASE_TWO = 7,
- EMOTE_GATE_OPENED = 8
-};
-
-enum Spells
-{
- // Gothik
- SPELL_HARVEST_SOUL = 28679,
- SPELL_SHADOW_BOLT = 29317,
- // Teleport spells
- SPELL_TELEPORT_DEAD = 28025,
- SPELL_TELEPORT_LIVE = 28026,
- // Visual spells
- SPELL_ANCHOR_1_TRAINEE = 27892,
- SPELL_ANCHOR_1_DK = 27928,
- SPELL_ANCHOR_1_RIDER = 27935,
- SPELL_ANCHOR_2_TRAINEE = 27893,
- SPELL_ANCHOR_2_DK = 27929,
- SPELL_ANCHOR_2_RIDER = 27936,
- SPELL_SKULLS_TRAINEE = 27915,
- SPELL_SKULLS_DK = 27931,
- SPELL_SKULLS_RIDER = 27937,
- // Living trainee
- SPELL_DEATH_PLAGUE = 55604,
- // Dead trainee
- SPELL_ARCANE_EXPLOSION = 27989,
- // Living knight
- SPELL_SHADOW_MARK = 27825,
- // Dead knight
- SPELL_WHIRLWIND = 56408,
- // Living rider
- SPELL_SHADOW_BOLT_VOLLEY = 27831,
- // Dead rider
- SPELL_DRAIN_LIFE = 27994,
- SPELL_UNHOLY_FRENZY = 55648,
- // Horse
- SPELL_STOMP = 27993
-};
-
-enum Misc
-{
- NPC_LIVING_TRAINEE = 16124,
- NPC_LIVING_KNIGHT = 16125,
- NPC_LIVING_RIDER = 16126,
- NPC_DEAD_TRAINEE = 16127,
- NPC_DEAD_KNIGHT = 16148,
- NPC_DEAD_HORSE = 16149,
- NPC_DEAD_RIDER = 16150,
- NPC_TRIGGER = 16137
-};
-
-enum Events
-{
- // Gothik
- EVENT_SUMMON_ADDS = 1,
- EVENT_HARVEST_SOUL = 2,
- EVENT_SHADOW_BOLT = 3,
- EVENT_TELEPORT = 4,
- EVENT_CHECK_HEALTH = 5,
- EVENT_CHECK_PLAYERS = 6,
- // Living trainee
- EVENT_DEATH_PLAGUE = 7,
- // Dead trainee
- EVENT_ARCANE_EXPLOSION = 8,
- // Living knight
- EVENT_SHADOW_MARK = 9,
- // Dead knight
- EVENT_WHIRLWIND = 10,
- // Living rider
- EVENT_SHADOW_BOLT_VOLLEY = 11,
- // Dead rider
- EVENT_DRAIN_LIFE = 12,
- EVENT_UNHOLY_FRENZY = 13,
- // HORSE
- EVENT_STOMP = 14,
- // Intro
- EVENT_INTRO_2 = 15,
- EVENT_INTRO_3 = 16,
- EVENT_INTRO_4 = 17
-};
-
-const uint32 gothikWaves[24][2] =
-{
- {NPC_LIVING_TRAINEE, 20000},
- {NPC_LIVING_TRAINEE, 20000},
- {NPC_LIVING_TRAINEE, 10000},
- {NPC_LIVING_KNIGHT, 10000},
- {NPC_LIVING_TRAINEE, 15000},
- {NPC_LIVING_KNIGHT, 10000},
- {NPC_LIVING_TRAINEE, 15000},
- {NPC_LIVING_TRAINEE, 0},
- {NPC_LIVING_KNIGHT, 10000},
- {NPC_LIVING_RIDER, 10000},
- {NPC_LIVING_TRAINEE, 5000},
- {NPC_LIVING_KNIGHT, 15000},
- {NPC_LIVING_RIDER, 0},
- {NPC_LIVING_TRAINEE, 10000},
- {NPC_LIVING_KNIGHT, 10000},
- {NPC_LIVING_TRAINEE, 10000},
- {NPC_LIVING_RIDER, 5000},
- {NPC_LIVING_KNIGHT, 5000},
- {NPC_LIVING_TRAINEE, 20000},
- {NPC_LIVING_RIDER, 0},
- {NPC_LIVING_KNIGHT, 0},
- {NPC_LIVING_TRAINEE, 15000},
- {NPC_LIVING_TRAINEE, 29000},
- {0, 0}
-};
-
-const Position PosSummonLiving[6] =
-{
- {2669.7f, -3428.76f, 268.56f, 1.6f},
- {2692.1f, -3428.76f, 268.56f, 1.6f},
- {2714.4f, -3428.76f, 268.56f, 1.6f},
- {2669.7f, -3431.67f, 268.56f, 1.6f},
- {2692.1f, -3431.67f, 268.56f, 1.6f},
- {2714.4f, -3431.67f, 268.56f, 1.6f}
-};
-
-const Position PosSummonDead[5] =
-{
- {2725.1f, -3310.0f, 268.85f, 3.4f},
- {2699.3f, -3322.8f, 268.60f, 3.3f},
- {2733.1f, -3348.5f, 268.84f, 3.1f},
- {2682.8f, -3304.2f, 268.85f, 3.9f},
- {2664.8f, -3340.7f, 268.23f, 3.7f}
-};
-
-//const Position PosGroundLivingSide = {2691.2f, -3387.0f, 267.68f, 1.52f};
-//const Position PosGroundDeadSide = {2693.5f, -3334.6f, 267.68f, 4.67f};
-//const Position PosPlatform = {2640.5f, -3360.6f, 285.26f, 0.0f};
-
-#define POS_Y_GATE -3360.78f
-#define POS_Y_WEST -3285.0f
-#define POS_Y_EAST -3434.0f
-#define POS_X_NORTH 2750.49f
-#define POS_X_SOUTH 2633.84f
-#define IN_LIVE_SIDE(who) (who->GetPositionY() < POS_Y_GATE)
-
-// Predicate function to check that the r efzr unit is NOT on the same side as the source.
-struct NotOnSameSide
-{
-public:
- explicit NotOnSameSide(Unit* pSource) : m_inLiveSide(IN_LIVE_SIDE(pSource)) { }
-
- bool operator() (Unit const* pTarget)
- {
- return (m_inLiveSide != IN_LIVE_SIDE(pTarget));
- }
-
-private:
- bool m_inLiveSide;
-};
-
-class boss_gothik : public CreatureScript
-{
-public:
- boss_gothik() : CreatureScript("boss_gothik") { }
-
- CreatureAI* GetAI(Creature* pCreature) const override
- {
- return GetNaxxramasAI(pCreature);
- }
-
- struct boss_gothikAI : public BossAI
- {
- explicit boss_gothikAI(Creature* c) : BossAI(c, BOSS_GOTHIK), summons(me)
- {}
-
- EventMap events;
- SummonList summons;
- bool secondPhase{};
- bool gateOpened{};
- uint8 waveCount{};
-
- bool IsInRoom()
- {
- if (me->GetPositionX() > 2767 || me->GetPositionX() < 2618 || me->GetPositionY() > -3285 || me->GetPositionY() < -3435)
- {
- EnterEvadeMode();
- return false;
- }
- return true;
- }
-
- void Reset() override
- {
- BossAI::Reset();
- events.Reset();
- summons.DespawnAll();
- me->RemoveUnitFlag(UNIT_FLAG_DISABLE_MOVE);
- me->SetImmuneToPC(false);
- me->SetReactState(REACT_PASSIVE);
- secondPhase = false;
- gateOpened = false;
- waveCount = 0;
- me->NearTeleportTo(2642.139f, -3386.959f, 285.492f, 6.265f);
- }
-
- void JustEngagedWith(Unit* who) override
- {
- BossAI::JustEngagedWith(who);
- me->SetInCombatWithZone();
- Talk(SAY_INTRO_1);
- events.ScheduleEvent(EVENT_INTRO_2, 4s);
- events.ScheduleEvent(EVENT_INTRO_3, 9s);
- events.ScheduleEvent(EVENT_INTRO_4, 14s);
- me->SetUnitFlag(UNIT_FLAG_DISABLE_MOVE);
- events.ScheduleEvent(EVENT_SUMMON_ADDS, 30s);
- events.ScheduleEvent(EVENT_CHECK_PLAYERS, 2min);
- }
-
- void JustSummoned(Creature* summon) override
- {
- summons.Summon(summon);
- // If central gate is open, attack any one
- if (gateOpened)
- {
- if (Unit* target = SelectTarget(SelectTargetMethod::MinDistance, 0, 200.0f))
- {
- summon->AI()->AttackStart(target);
- summon->SetInCombatWithZone();
- summon->SetReactState(REACT_AGGRESSIVE);
- summon->CallForHelp(150.0f);
- }
- }
- // Else look for a random target on the side the summoned NPC is
- else
- {
- Map::PlayerList const& pList = me->GetMap()->GetPlayers();
- std::vector tList;
- for(Map::PlayerList::const_iterator itr = pList.begin(); itr != pList.end(); ++itr)
- {
- if (!me->IsWithinDistInMap(itr->GetSource(), 200.0f, true, false, false) || !itr->GetSource()->IsAlive() || itr->GetSource()->IsGameMaster())
- {
- continue;
- }
- if (IN_LIVE_SIDE(itr->GetSource()) != IN_LIVE_SIDE(summon))
- {
- continue;
- }
- tList.push_back(itr->GetSource());
- }
- if (!tList.empty())
- {
- Player* target = tList[urand(0, tList.size() - 1)];
- summon->AI()->AttackStart(target);
- summon->SetInCombatWithZone();
- summon->SetReactState(REACT_AGGRESSIVE);
- summon->CallForHelp(150.0f);
- }
- }
- }
-
- void SummonedCreatureDespawn(Creature* cr) override
- {
- summons.Despawn(cr);
- }
-
- void KilledUnit(Unit* who) override
- {
- if (!who->IsPlayer())
- return;
-
- Talk(SAY_KILL);
- instance->StorePersistentData(PERSISTENT_DATA_IMMORTAL_FAIL, 1);
- }
-
- void JustDied(Unit* killer) override
- {
- BossAI::JustDied(killer);
- Talk(SAY_DEATH);
- summons.DespawnAll();
- }
-
- void SummonHelpers(uint32 entry)
- {
- switch (entry)
- {
- case NPC_LIVING_TRAINEE:
- me->SummonCreature(NPC_LIVING_TRAINEE, PosSummonLiving[0].GetPositionX(), PosSummonLiving[0].GetPositionY(), PosSummonLiving[0].GetPositionZ(), PosSummonLiving[0].GetOrientation());
- me->SummonCreature(NPC_LIVING_TRAINEE, PosSummonLiving[1].GetPositionX(), PosSummonLiving[1].GetPositionY(), PosSummonLiving[1].GetPositionZ(), PosSummonLiving[1].GetOrientation());
- if (Is25ManRaid())
- {
- me->SummonCreature(NPC_LIVING_TRAINEE, PosSummonLiving[2].GetPositionX(), PosSummonLiving[2].GetPositionY(), PosSummonLiving[2].GetPositionZ(), PosSummonLiving[2].GetOrientation());
- }
- break;
- case NPC_LIVING_KNIGHT:
- me->SummonCreature(NPC_LIVING_KNIGHT, PosSummonLiving[3].GetPositionX(), PosSummonLiving[3].GetPositionY(), PosSummonLiving[3].GetPositionZ(), PosSummonLiving[3].GetOrientation());
- if (Is25ManRaid())
- {
- me->SummonCreature(NPC_LIVING_KNIGHT, PosSummonLiving[5].GetPositionX(), PosSummonLiving[5].GetPositionY(), PosSummonLiving[5].GetPositionZ(), PosSummonLiving[5].GetOrientation());
- }
- break;
- case NPC_LIVING_RIDER:
- me->SummonCreature(NPC_LIVING_RIDER, PosSummonLiving[4].GetPositionX(), PosSummonLiving[4].GetPositionY(), PosSummonLiving[4].GetPositionZ(), PosSummonLiving[4].GetOrientation());
- break;
- }
- }
-
- bool CheckGroupSplitted()
- {
- Map::PlayerList const& PlayerList = me->GetMap()->GetPlayers();
- if (!PlayerList.IsEmpty())
- {
- bool checklife = false;
- bool checkdead = false;
- for (auto const& i : PlayerList)
- {
- Player* player = i.GetSource();
- if (player->IsAlive() &&
- player->GetPositionX() <= POS_X_NORTH &&
- player->GetPositionX() >= POS_X_SOUTH &&
- player->GetPositionY() <= POS_Y_GATE &&
- player->GetPositionY() >= POS_Y_EAST)
- {
- checklife = true;
- }
- else if (player->IsAlive() &&
- player->GetPositionX() <= POS_X_NORTH &&
- player->GetPositionX() >= POS_X_SOUTH &&
- player->GetPositionY() >= POS_Y_GATE &&
- player->GetPositionY() <= POS_Y_WEST)
- {
- checkdead = true;
- }
-
- if (checklife && checkdead)
- return true;
- }
- }
- return false;
- }
-
- void DamageTaken(Unit*, uint32& damage, DamageEffectType, SpellSchoolMask) override
- {
- if (!secondPhase)
- {
- damage = 0;
- }
- }
-
- void UpdateAI(uint32 diff) override
- {
- if (!IsInRoom())
- return;
-
- if (!UpdateVictim())
- return;
-
- events.Update(diff);
- if (me->HasUnitState(UNIT_STATE_CASTING))
- return;
-
- switch (events.ExecuteEvent())
- {
- case EVENT_INTRO_2:
- Talk(SAY_INTRO_2);
- break;
- case EVENT_INTRO_3:
- Talk(SAY_INTRO_3);
- break;
- case EVENT_INTRO_4:
- Talk(SAY_INTRO_4);
- break;
- case EVENT_SHADOW_BOLT:
- me->CastSpell(me->GetVictim(), SPELL_SHADOW_BOLT, false);
- events.Repeat(1s);
- break;
- case EVENT_HARVEST_SOUL:
- me->CastSpell(me, SPELL_HARVEST_SOUL, false);
- events.Repeat(15s);
- break;
- case EVENT_TELEPORT:
- me->AttackStop();
- if (IN_LIVE_SIDE(me))
- {
- me->CastSpell(me, SPELL_TELEPORT_DEAD, false);
- }
- else
- {
- me->CastSpell(me, SPELL_TELEPORT_LIVE, false);
- }
- me->GetThreatMgr().resetAggro(NotOnSameSide(me));
- if (Unit* pTarget = SelectTarget(SelectTargetMethod::MaxDistance, 0))
- {
- me->GetThreatMgr().AddThreat(pTarget, 100.0f);
- AttackStart(pTarget);
- }
- events.Repeat(20s);
- break;
- case EVENT_CHECK_HEALTH:
- if (me->HealthBelowPct(30))
- {
- if (GameObject* go = instance->GetGameObject(DATA_GOTHIK_INNER_GATE))
- go->SetGoState(GO_STATE_ACTIVE);
-
- events.CancelEvent(EVENT_TELEPORT);
- break;
- }
- events.Repeat(1s);
- break;
- case EVENT_SUMMON_ADDS:
- if (gothikWaves[waveCount][0])
- {
- SummonHelpers(gothikWaves[waveCount][0]);
- events.Repeat(Milliseconds(gothikWaves[waveCount][1]));
- }
- else
- {
- secondPhase = true;
- Talk(SAY_PHASE_TWO);
- Talk(EMOTE_PHASE_TWO);
- me->CastSpell(me, SPELL_TELEPORT_LIVE, false);
- me->SetReactState(REACT_AGGRESSIVE);
- me->RemoveUnitFlag(UNIT_FLAG_DISABLE_MOVE);
- me->SetImmuneToPC(false);
- me->RemoveAllAuras();
- events.ScheduleEvent(EVENT_SHADOW_BOLT, 1s);
- events.ScheduleEvent(EVENT_HARVEST_SOUL, 5s, 15s);
- events.ScheduleEvent(EVENT_TELEPORT, 20s);
- events.ScheduleEvent(EVENT_CHECK_HEALTH, 1s);
- }
- waveCount++;
- break;
- case EVENT_CHECK_PLAYERS:
- if (!CheckGroupSplitted())
- {
- if (GameObject* go = instance->GetGameObject(DATA_GOTHIK_INNER_GATE))
- go->SetGoState(GO_STATE_ACTIVE);
-
- gateOpened = true;
- Talk(EMOTE_GATE_OPENED);
- }
- break;
- }
- DoMeleeAttackIfReady();
- }
- };
-};
-
-class npc_boss_gothik_minion : public CreatureScript
-{
-public:
- npc_boss_gothik_minion() : CreatureScript("npc_boss_gothik_minion") { }
-
- CreatureAI* GetAI(Creature* pCreature) const override
- {
- return GetNaxxramasAI(pCreature);
- }
-
- struct npc_boss_gothik_minionAI : public CombatAI
- {
- explicit npc_boss_gothik_minionAI(Creature* c) : CombatAI(c)
- {
- livingSide = IN_LIVE_SIDE(me);
- }
- EventMap events;
- bool livingSide;
- bool IsOnSameSide(Unit const* who) const { return livingSide == IN_LIVE_SIDE(who); }
-
- void Reset() override
- {
- me->SetReactState(REACT_AGGRESSIVE);
- me->SetNoCallAssistance(false);
- events.Reset();
- }
-
- void JustEngagedWith(Unit* /*who*/) override
- {
- switch (me->GetEntry())
- {
- case NPC_LIVING_TRAINEE:
- events.ScheduleEvent(EVENT_DEATH_PLAGUE, 3s);
- break;
- case NPC_DEAD_TRAINEE:
- events.ScheduleEvent(EVENT_ARCANE_EXPLOSION, 2500ms);
- break;
- case NPC_LIVING_KNIGHT:
- events.ScheduleEvent(EVENT_SHADOW_MARK, 3s);
- break;
- case NPC_DEAD_KNIGHT:
- events.ScheduleEvent(EVENT_WHIRLWIND, 2s);
- break;
- case NPC_LIVING_RIDER:
- events.ScheduleEvent(EVENT_SHADOW_BOLT_VOLLEY, 3s);
- break;
- case NPC_DEAD_RIDER:
- events.ScheduleEvent(EVENT_DRAIN_LIFE, 2s, 3500ms);
- events.ScheduleEvent(EVENT_UNHOLY_FRENZY, 5s, 9s);
- break;
- case NPC_DEAD_HORSE:
- events.ScheduleEvent(EVENT_STOMP, 2s, 5s);
- break;
- }
- }
-
- void JustDied(Unit*) override
- {
- switch (me->GetEntry())
- {
- case NPC_LIVING_TRAINEE:
- DoCastAOE(SPELL_ANCHOR_1_TRAINEE, true);
- break;
- case NPC_LIVING_KNIGHT:
- DoCastAOE(SPELL_ANCHOR_1_DK, true);
- break;
- case NPC_LIVING_RIDER:
- DoCastAOE(SPELL_ANCHOR_1_RIDER, true);
- break;
- }
- }
-
- void KilledUnit(Unit* who) override
- {
- if (who->IsPlayer())
- me->GetInstanceScript()->StorePersistentData(PERSISTENT_DATA_IMMORTAL_FAIL, 1);
- }
-
- void UpdateAI(uint32 diff) override
- {
- events.Update(diff);
- if (me->GetUnitState() == UNIT_STATE_CASTING)
- return;
-
- switch (events.ExecuteEvent())
- {
- case EVENT_DEATH_PLAGUE:
- me->CastSpell(me->GetVictim(), SPELL_DEATH_PLAGUE, false);
- events.Repeat(4s, 7s);
- break;
- case EVENT_ARCANE_EXPLOSION:
- if (Unit* victim = me->GetVictim())
- {
- if (victim->IsWithinDist(me, 20))
- {
- me->CastSpell(victim, SPELL_ARCANE_EXPLOSION, false);
- }
- }
- events.Repeat(2500ms);
- break;
- case EVENT_SHADOW_MARK:
- if (Unit* victim = me->GetVictim())
- {
- if (victim->IsWithinDist(me, 10))
- {
- me->CastSpell(victim, SPELL_SHADOW_MARK, false);
- }
- }
- events.Repeat(5s, 7s);
- break;
- case EVENT_WHIRLWIND:
- if (Unit* victim = me->GetVictim())
- {
- if (victim->IsWithinDist(me, 10))
- {
- me->CastSpell(victim, SPELL_WHIRLWIND, false);
- }
- }
- events.Repeat(4s, 6s);
- break;
- case EVENT_SHADOW_BOLT_VOLLEY:
- me->CastSpell(me->GetVictim(), SPELL_SHADOW_BOLT_VOLLEY, false);
- events.Repeat(5s);
- break;
- case EVENT_DRAIN_LIFE:
- if (Unit* victim = me->GetVictim())
- {
- if (victim->IsWithinDist(me, 20))
- {
- me->CastSpell(victim, SPELL_DRAIN_LIFE, false);
- }
- }
- events.Repeat(8s, 12s);
- break;
- case EVENT_UNHOLY_FRENZY:
- me->AddAura(SPELL_UNHOLY_FRENZY, me);
- events.Repeat(15s, 17s);
- break;
- case EVENT_STOMP:
- if (Unit* victim = me->GetVictim())
- {
- if (victim->IsWithinDist(me, 10))
- {
- me->CastSpell(victim, SPELL_STOMP, false);
- }
- }
- events.Repeat(4s, 9s);
- break;
- }
- DoMeleeAttackIfReady();
- }
- };
-};
-
-class npc_gothik_trigger : public CreatureScript
-{
-public:
- npc_gothik_trigger() : CreatureScript("npc_gothik_trigger") { }
-
- CreatureAI* GetAI(Creature* creature) const override
- {
- return new npc_gothik_triggerAI(creature);
- }
-
- struct npc_gothik_triggerAI : public ScriptedAI
- {
- npc_gothik_triggerAI(Creature* creature) : ScriptedAI(creature) { creature->SetDisableGravity(true); }
-
- void EnterEvadeMode(EvadeReason /*why*/) override {}
- void UpdateAI(uint32 /*diff*/) override {}
- void JustEngagedWith(Unit* /*who*/) override {}
- void DamageTaken(Unit* /*who*/, uint32& damage, DamageEffectType /*damagetype*/, SpellSchoolMask /*damageSchoolMask*/) override { damage = 0; }
-
- Creature* SelectRandomSkullPile()
- {
- std::list triggers;
- me->GetCreatureListWithEntryInGrid(triggers, NPC_TRIGGER, 150.0f);
- // Remove triggers that are on live side or soul triggers on the platform
- triggers.remove_if([](Creature* trigger){
- return ((trigger->GetPositionY() < POS_Y_GATE) || (trigger->GetPositionZ() > 280.0f));
- });
- if (!triggers.empty())
- {
- std::list::iterator itr = triggers.begin();
- std::advance(itr, urand(0, triggers.size() - 1));
- return *itr;
- }
- return nullptr;
- }
-
- void SpellHit(Unit* /*caster*/, SpellInfo const* spell) override
- {
- if (!spell)
- {
- return;
- }
-
- switch (spell->Id)
- {
- case SPELL_ANCHOR_1_TRAINEE:
- DoCastAOE(SPELL_ANCHOR_2_TRAINEE, true);
- break;
- case SPELL_ANCHOR_1_DK:
- DoCastAOE(SPELL_ANCHOR_2_DK, true);
- break;
- case SPELL_ANCHOR_1_RIDER:
- DoCastAOE(SPELL_ANCHOR_2_RIDER, true);
- break;
- case SPELL_ANCHOR_2_TRAINEE:
- if (Creature* target = SelectRandomSkullPile())
- {
- DoCast(target, SPELL_SKULLS_TRAINEE, true);
- }
- break;
- case SPELL_ANCHOR_2_DK:
- if (Creature* target = SelectRandomSkullPile())
- {
- DoCast(target, SPELL_SKULLS_DK, true);
- }
- break;
- case SPELL_ANCHOR_2_RIDER:
- if (Creature* target = SelectRandomSkullPile())
- {
- DoCast(target, SPELL_SKULLS_RIDER, true);
- }
- break;
- case SPELL_SKULLS_TRAINEE:
- DoSummon(NPC_DEAD_TRAINEE, me, 0.0f, 15 * IN_MILLISECONDS, TEMPSUMMON_CORPSE_TIMED_DESPAWN);
- break;
- case SPELL_SKULLS_DK:
- DoSummon(NPC_DEAD_KNIGHT, me, 0.0f, 15 * IN_MILLISECONDS, TEMPSUMMON_CORPSE_TIMED_DESPAWN);
- break;
- case SPELL_SKULLS_RIDER:
- DoSummon(NPC_DEAD_RIDER, me, 0.0f, 15 * IN_MILLISECONDS, TEMPSUMMON_CORPSE_TIMED_DESPAWN);
- DoSummon(NPC_DEAD_HORSE, me, 0.0f, 15 * IN_MILLISECONDS, TEMPSUMMON_CORPSE_TIMED_DESPAWN);
- break;
- }
- }
-
- // dead side summons are "owned" by gothik
- void JustSummoned(Creature* summon) override
- {
- if (Creature* gothik = me->GetInstanceScript()->GetCreature(DATA_GOTHIK_BOSS))
- gothik->AI()->JustSummoned(summon);
- }
-
- void SummonedCreatureDespawn(Creature* summon) override
- {
- if (Creature* gothik = me->GetInstanceScript()->GetCreature(DATA_GOTHIK_BOSS))
- gothik->AI()->SummonedCreatureDespawn(summon);
- }
- };
-};
-
-class spell_gothik_shadow_bolt_volley : public SpellScript
-{
- PrepareSpellScript(spell_gothik_shadow_bolt_volley);
-
- bool Validate(SpellInfo const* /*spellInfo*/) override
- {
- return ValidateSpellInfo({ SPELL_SHADOW_MARK });
- }
-
- void FilterTargets(std::list& targets)
- {
- targets.remove_if(Acore::UnitAuraCheck(false, SPELL_SHADOW_MARK));
- }
-
- void Register() override
- {
- OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_gothik_shadow_bolt_volley::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY);
- }
-};
-
-}
-
-#endif
\ No newline at end of file
diff --git a/src/server/scripts/Northrend/Naxxramas/boss_grobbulus.cpp b/src/server/scripts/Northrend/Naxxramas/boss_grobbulus.cpp
index 28514cb8b..e37646f12 100644
--- a/src/server/scripts/Northrend/Naxxramas/boss_grobbulus.cpp
+++ b/src/server/scripts/Northrend/Naxxramas/boss_grobbulus.cpp
@@ -15,7 +15,6 @@
* with this program. If not, see .
*/
-#include "boss_grobbulus.h"
#include "CreatureScript.h"
#include "PassiveAI.h"
#include "ScriptedCreature.h"
@@ -25,10 +24,278 @@
#include "SpellScriptLoader.h"
#include "naxxramas.h"
-using namespace Grobbulus;
+enum Spells
+{
+ SPELL_POISON_CLOUD = 28240,
+ SPELL_MUTATING_INJECTION = 28169,
+ SPELL_MUTATING_EXPLOSION = 28206,
+ SPELL_SLIME_SPRAY = 28157,
+ SPELL_POISON_CLOUD_DAMAGE_AURA = 28158,
+ SPELL_BERSERK = 26662,
+ SPELL_BOMBARD_SLIME = 28280
+};
-// no custom changes has been made for mod-playerbot other then placing
-// the impl in a header file
+enum Emotes
+{
+ EMOTE_SLIME = 0
+};
+
+enum Events
+{
+ EVENT_BERSERK = 1,
+ EVENT_POISON_CLOUD = 2,
+ EVENT_SLIME_SPRAY = 3,
+ EVENT_MUTATING_INJECTION = 4
+};
+
+enum Misc
+{
+ NPC_FALLOUT_SLIME = 16290,
+ NPC_SEWAGE_SLIME = 16375,
+ NPC_STICHED_GIANT = 16025
+};
+
+class boss_grobbulus : public CreatureScript
+{
+public:
+ boss_grobbulus() : CreatureScript("boss_grobbulus") { }
+
+ CreatureAI* GetAI(Creature* pCreature) const override
+ {
+ return GetNaxxramasAI(pCreature);
+ }
+
+ struct boss_grobbulusAI : public BossAI
+ {
+ explicit boss_grobbulusAI(Creature* c) : BossAI(c, BOSS_GROBBULUS), summons(me)
+ {}
+
+ EventMap events;
+ SummonList summons;
+ uint32 dropSludgeTimer{};
+
+ void Reset() override
+ {
+ BossAI::Reset();
+ events.Reset();
+ summons.DespawnAll();
+ dropSludgeTimer = 0;
+ }
+
+ void PullChamberAdds()
+ {
+ std::list StichedGiants;
+ me->GetCreaturesWithEntryInRange(StichedGiants, 300.0f, NPC_STICHED_GIANT);
+ for (std::list::const_iterator itr = StichedGiants.begin(); itr != StichedGiants.end(); ++itr)
+ {
+ (*itr)->ToCreature()->AI()->AttackStart(me->GetVictim());
+ }
+ }
+
+ void JustEngagedWith(Unit* who) override
+ {
+ BossAI::JustEngagedWith(who);
+ PullChamberAdds();
+ me->SetInCombatWithZone();
+ events.ScheduleEvent(EVENT_POISON_CLOUD, 15s);
+ events.ScheduleEvent(EVENT_MUTATING_INJECTION, 20s);
+ events.ScheduleEvent(EVENT_SLIME_SPRAY, 10s);
+ events.ScheduleEvent(EVENT_BERSERK, RAID_MODE(720s, 540s));
+ }
+
+ void JustSummoned(Creature* cr) override
+ {
+ if (cr->GetEntry() == NPC_FALLOUT_SLIME)
+ {
+ cr->SetInCombatWithZone();
+ }
+ summons.Summon(cr);
+ }
+
+ void SummonedCreatureDespawn(Creature* summon) override
+ {
+ summons.Despawn(summon);
+ }
+
+ void JustDied(Unit* killer) override
+ {
+ BossAI::JustDied(killer);
+ summons.DespawnAll();
+ }
+
+ void KilledUnit(Unit* who) override
+ {
+ if (who->IsPlayer())
+ instance->StorePersistentData(PERSISTENT_DATA_IMMORTAL_FAIL, 1);
+ }
+
+ void UpdateAI(uint32 diff) override
+ {
+ dropSludgeTimer += diff;
+ if (!me->IsInCombat() && dropSludgeTimer >= 5000)
+ {
+ if (me->IsWithinDist3d(3178, -3305, 319, 5.0f) && !summons.HasEntry(NPC_SEWAGE_SLIME))
+ {
+ me->CastSpell(3128.96f + irand(-20, 20), -3312.96f + irand(-20, 20), 293.25f, SPELL_BOMBARD_SLIME, false);
+ }
+ dropSludgeTimer = 0;
+ }
+
+ if (!UpdateVictim())
+ return;
+
+ events.Update(diff);
+ if (me->HasUnitState(UNIT_STATE_CASTING))
+ return;
+
+ switch (events.ExecuteEvent())
+ {
+ case EVENT_POISON_CLOUD:
+ me->CastSpell(me, SPELL_POISON_CLOUD, true);
+ events.Repeat(15s);
+ break;
+ case EVENT_BERSERK:
+ me->CastSpell(me, SPELL_BERSERK, true);
+ break;
+ case EVENT_SLIME_SPRAY:
+ Talk(EMOTE_SLIME);
+ me->CastSpell(me->GetVictim(), SPELL_SLIME_SPRAY, false);
+ events.Repeat(20s);
+ break;
+ case EVENT_MUTATING_INJECTION:
+ if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 100.0f, true, false, -SPELL_MUTATING_INJECTION))
+ {
+ me->CastSpell(target, SPELL_MUTATING_INJECTION, false);
+ }
+ events.Repeat(Milliseconds(6000 + uint32(120 * me->GetHealthPct())));
+ break;
+ }
+ DoMeleeAttackIfReady();
+ }
+ };
+};
+
+class boss_grobbulus_poison_cloud : public CreatureScript
+{
+public:
+ boss_grobbulus_poison_cloud() : CreatureScript("boss_grobbulus_poison_cloud") { }
+
+ CreatureAI* GetAI(Creature* pCreature) const override
+ {
+ return GetNaxxramasAI(pCreature);
+ }
+
+ struct boss_grobbulus_poison_cloudAI : public NullCreatureAI
+ {
+ explicit boss_grobbulus_poison_cloudAI(Creature* pCreature) : NullCreatureAI(pCreature) { }
+
+ uint32 sizeTimer{};
+ uint32 auraVisualTimer{};
+
+ void Reset() override
+ {
+ sizeTimer = 0;
+ auraVisualTimer = 1;
+ me->SetFloatValue(UNIT_FIELD_COMBATREACH, 2.0f);
+ me->SetFaction(FACTION_BOOTY_BAY);
+ }
+
+ void KilledUnit(Unit* who) override
+ {
+ if (who->IsPlayer())
+ me->GetInstanceScript()->StorePersistentData(PERSISTENT_DATA_IMMORTAL_FAIL, 1);
+ }
+
+ void UpdateAI(uint32 diff) override
+ {
+ if (auraVisualTimer) // this has to be delayed to be visible
+ {
+ auraVisualTimer += diff;
+ if (auraVisualTimer >= 1000)
+ {
+ me->CastSpell(me, SPELL_POISON_CLOUD_DAMAGE_AURA, true);
+ auraVisualTimer = 0;
+ }
+ }
+ sizeTimer += diff; // increase size to 15yd in 60 seconds, 0.00025 is the growth of size in 1ms
+ me->SetFloatValue(UNIT_FIELD_COMBATREACH, 2.0f + (0.00025f * sizeTimer));
+ }
+ };
+};
+
+class spell_grobbulus_poison : public SpellScript
+{
+ PrepareSpellScript(spell_grobbulus_poison);
+
+ void FilterTargets(std::list& targets)
+ {
+ std::list tmplist;
+ for (auto& target : targets)
+ {
+ if (GetCaster()->IsWithinDist3d(target, 0.0f))
+ {
+ tmplist.push_back(target);
+ }
+ }
+ targets.clear();
+ for (auto& itr : tmplist)
+ {
+ targets.push_back(itr);
+ }
+ }
+
+ void Register() override
+ {
+ OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_grobbulus_poison::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY);
+ }
+};
+
+class spell_grobbulus_mutating_injection_aura : public AuraScript
+{
+ PrepareAuraScript(spell_grobbulus_mutating_injection_aura);
+
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ return ValidateSpellInfo({ SPELL_MUTATING_EXPLOSION });
+ }
+
+ void HandleRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
+ {
+ switch (GetTargetApplication()->GetRemoveMode())
+ {
+ case AURA_REMOVE_BY_ENEMY_SPELL:
+ case AURA_REMOVE_BY_EXPIRE:
+ if (auto caster = GetCaster())
+ {
+ caster->CastSpell(GetTarget(), SPELL_MUTATING_EXPLOSION, true);
+ }
+ break;
+ default:
+ return;
+ }
+ }
+
+ void Register() override
+ {
+ AfterEffectRemove += AuraEffectRemoveFn(spell_grobbulus_mutating_injection_aura::HandleRemove, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL);
+ }
+};
+
+class spell_grobbulus_slime_spray : public SpellScript
+{
+ PrepareSpellScript(spell_grobbulus_slime_spray);
+
+ void HandleHit()
+ {
+ if (Unit* target = GetHitUnit())
+ GetCaster()->SummonCreature(NPC_FALLOUT_SLIME, target->GetPositionX(), target->GetPositionY(), target->GetPositionZ());
+ }
+
+ void Register() override
+ {
+ OnHit += SpellHitFn(spell_grobbulus_slime_spray::HandleHit);
+ }
+};
void AddSC_boss_grobbulus()
{
diff --git a/src/server/scripts/Northrend/Naxxramas/boss_grobbulus.h b/src/server/scripts/Northrend/Naxxramas/boss_grobbulus.h
deleted file mode 100644
index 3e904a681..000000000
--- a/src/server/scripts/Northrend/Naxxramas/boss_grobbulus.h
+++ /dev/null
@@ -1,291 +0,0 @@
-#ifndef BOSSGROBBULUS_H_
-#define BOSSGROBBULUS_H_
-
-#include "PassiveAI.h"
-#include "ScriptMgr.h"
-#include "ScriptedCreature.h"
-#include "SpellAuraEffects.h"
-#include "SpellAuras.h"
-#include "SpellScript.h"
-#include "SpellInfo.h"
-#include "naxxramas.h"
-
-namespace Grobbulus {
-
-enum Spells
-{
- SPELL_POISON_CLOUD = 28240,
- SPELL_MUTATING_INJECTION = 28169,
- SPELL_MUTATING_EXPLOSION = 28206,
- SPELL_SLIME_SPRAY = 28157,
- SPELL_POISON_CLOUD_DAMAGE_AURA = 28158,
- SPELL_BERSERK = 26662,
- SPELL_BOMBARD_SLIME = 28280
-};
-
-enum Emotes
-{
- EMOTE_SLIME = 0
-};
-
-enum Events
-{
- EVENT_BERSERK = 1,
- EVENT_POISON_CLOUD = 2,
- EVENT_SLIME_SPRAY = 3,
- EVENT_MUTATING_INJECTION = 4
-};
-
-enum Misc
-{
- NPC_FALLOUT_SLIME = 16290,
- NPC_SEWAGE_SLIME = 16375,
- NPC_STICHED_GIANT = 16025
-};
-
-class boss_grobbulus : public CreatureScript
-{
-public:
- boss_grobbulus() : CreatureScript("boss_grobbulus") { }
-
- CreatureAI* GetAI(Creature* pCreature) const override
- {
- return GetNaxxramasAI(pCreature);
- }
-
- struct boss_grobbulusAI : public BossAI
- {
- explicit boss_grobbulusAI(Creature* c) : BossAI(c, BOSS_GROBBULUS), summons(me)
- {}
-
- EventMap events;
- SummonList summons;
- uint32 dropSludgeTimer{};
-
- void Reset() override
- {
- BossAI::Reset();
- events.Reset();
- summons.DespawnAll();
- dropSludgeTimer = 0;
- }
-
- void PullChamberAdds()
- {
- std::list StichedGiants;
- me->GetCreaturesWithEntryInRange(StichedGiants, 300.0f, NPC_STICHED_GIANT);
- for (std::list::const_iterator itr = StichedGiants.begin(); itr != StichedGiants.end(); ++itr)
- {
- (*itr)->ToCreature()->AI()->AttackStart(me->GetVictim());
- }
- }
-
- void JustEngagedWith(Unit* who) override
- {
- BossAI::JustEngagedWith(who);
- PullChamberAdds();
- me->SetInCombatWithZone();
- events.ScheduleEvent(EVENT_POISON_CLOUD, 15s);
- events.ScheduleEvent(EVENT_MUTATING_INJECTION, 20s);
- events.ScheduleEvent(EVENT_SLIME_SPRAY, 10s);
- events.ScheduleEvent(EVENT_BERSERK, RAID_MODE(720s, 540s));
- }
-
- void JustSummoned(Creature* cr) override
- {
- if (cr->GetEntry() == NPC_FALLOUT_SLIME)
- {
- cr->SetInCombatWithZone();
- }
- summons.Summon(cr);
- }
-
- void SummonedCreatureDespawn(Creature* summon) override
- {
- summons.Despawn(summon);
- }
-
- void JustDied(Unit* killer) override
- {
- BossAI::JustDied(killer);
- summons.DespawnAll();
- }
-
- void KilledUnit(Unit* who) override
- {
- if (who->IsPlayer())
- instance->StorePersistentData(PERSISTENT_DATA_IMMORTAL_FAIL, 1);
- }
-
- void UpdateAI(uint32 diff) override
- {
- dropSludgeTimer += diff;
- if (!me->IsInCombat() && dropSludgeTimer >= 5000)
- {
- if (me->IsWithinDist3d(3178, -3305, 319, 5.0f) && !summons.HasEntry(NPC_SEWAGE_SLIME))
- {
- me->CastSpell(3128.96f + irand(-20, 20), -3312.96f + irand(-20, 20), 293.25f, SPELL_BOMBARD_SLIME, false);
- }
- dropSludgeTimer = 0;
- }
-
- if (!UpdateVictim())
- return;
-
- events.Update(diff);
- if (me->HasUnitState(UNIT_STATE_CASTING))
- return;
-
- switch (events.ExecuteEvent())
- {
- case EVENT_POISON_CLOUD:
- me->CastSpell(me, SPELL_POISON_CLOUD, true);
- events.Repeat(15s);
- break;
- case EVENT_BERSERK:
- me->CastSpell(me, SPELL_BERSERK, true);
- break;
- case EVENT_SLIME_SPRAY:
- Talk(EMOTE_SLIME);
- me->CastSpell(me->GetVictim(), SPELL_SLIME_SPRAY, false);
- events.Repeat(20s);
- break;
- case EVENT_MUTATING_INJECTION:
- if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 100.0f, true, false, -SPELL_MUTATING_INJECTION))
- {
- me->CastSpell(target, SPELL_MUTATING_INJECTION, false);
- }
- events.Repeat(Milliseconds(6000 + uint32(120 * me->GetHealthPct())));
- break;
- }
- DoMeleeAttackIfReady();
- }
- };
-};
-
-class boss_grobbulus_poison_cloud : public CreatureScript
-{
-public:
- boss_grobbulus_poison_cloud() : CreatureScript("boss_grobbulus_poison_cloud") { }
-
- CreatureAI* GetAI(Creature* pCreature) const override
- {
- return GetNaxxramasAI(pCreature);
- }
-
- struct boss_grobbulus_poison_cloudAI : public NullCreatureAI
- {
- explicit boss_grobbulus_poison_cloudAI(Creature* pCreature) : NullCreatureAI(pCreature) { }
-
- uint32 sizeTimer{};
- uint32 auraVisualTimer{};
-
- void Reset() override
- {
- sizeTimer = 0;
- auraVisualTimer = 1;
- me->SetFloatValue(UNIT_FIELD_COMBATREACH, 2.0f);
- me->SetFaction(FACTION_BOOTY_BAY);
- }
-
- void KilledUnit(Unit* who) override
- {
- if (who->IsPlayer())
- me->GetInstanceScript()->StorePersistentData(PERSISTENT_DATA_IMMORTAL_FAIL, 1);
- }
-
- void UpdateAI(uint32 diff) override
- {
- if (auraVisualTimer) // this has to be delayed to be visible
- {
- auraVisualTimer += diff;
- if (auraVisualTimer >= 1000)
- {
- me->CastSpell(me, SPELL_POISON_CLOUD_DAMAGE_AURA, true);
- auraVisualTimer = 0;
- }
- }
- sizeTimer += diff; // increase size to 15yd in 60 seconds, 0.00025 is the growth of size in 1ms
- me->SetFloatValue(UNIT_FIELD_COMBATREACH, 2.0f + (0.00025f * sizeTimer));
- }
- };
-};
-
-class spell_grobbulus_poison : public SpellScript
-{
- PrepareSpellScript(spell_grobbulus_poison);
-
- void FilterTargets(std::list& targets)
- {
- std::list tmplist;
- for (auto& target : targets)
- {
- if (GetCaster()->IsWithinDist3d(target, 0.0f))
- {
- tmplist.push_back(target);
- }
- }
- targets.clear();
- for (auto& itr : tmplist)
- {
- targets.push_back(itr);
- }
- }
-
- void Register() override
- {
- OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_grobbulus_poison::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY);
- }
-};
-
-class spell_grobbulus_mutating_injection_aura : public AuraScript
-{
- PrepareAuraScript(spell_grobbulus_mutating_injection_aura);
-
- bool Validate(SpellInfo const* /*spellInfo*/) override
- {
- return ValidateSpellInfo({ SPELL_MUTATING_EXPLOSION });
- }
-
- void HandleRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
- {
- switch (GetTargetApplication()->GetRemoveMode())
- {
- case AURA_REMOVE_BY_ENEMY_SPELL:
- case AURA_REMOVE_BY_EXPIRE:
- if (auto caster = GetCaster())
- {
- caster->CastSpell(GetTarget(), SPELL_MUTATING_EXPLOSION, true);
- }
- break;
- default:
- return;
- }
- }
-
- void Register() override
- {
- AfterEffectRemove += AuraEffectRemoveFn(spell_grobbulus_mutating_injection_aura::HandleRemove, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL);
- }
-};
-
-class spell_grobbulus_slime_spray : public SpellScript
-{
- PrepareSpellScript(spell_grobbulus_slime_spray);
-
- void HandleHit()
- {
- if (Unit* target = GetHitUnit())
- GetCaster()->SummonCreature(NPC_FALLOUT_SLIME, target->GetPositionX(), target->GetPositionY(), target->GetPositionZ());
- }
-
- void Register() override
- {
- OnHit += SpellHitFn(spell_grobbulus_slime_spray::HandleHit);
- }
-};
-
-
-}
-
-#endif
\ No newline at end of file
diff --git a/src/server/scripts/Northrend/Naxxramas/boss_heigan.h b/src/server/scripts/Northrend/Naxxramas/boss_heigan.h
deleted file mode 100644
index a199067bb..000000000
--- a/src/server/scripts/Northrend/Naxxramas/boss_heigan.h
+++ /dev/null
@@ -1,215 +0,0 @@
-#ifndef BOSS_HEIGAN_H_
-#define BOSS_HEIGAN_H_
-
-#include "Player.h"
-#include "ScriptMgr.h"
-#include "ScriptedCreature.h"
-#include "SpellInfo.h"
-#include "naxxramas.h"
-
-namespace Heigan {
-
-enum Says
-{
- SAY_AGGRO = 0,
- SAY_SLAY = 1,
- SAY_TAUNT = 2,
- EMOTE_DEATH = 3,
- EMOTE_DANCE = 4,
- EMOTE_DANCE_END = 5,
- SAY_DANCE = 6
-};
-
-enum Spells
-{
- SPELL_SPELL_DISRUPTION = 29310,
- SPELL_DECREPIT_FEVER = 29998,
- SPELL_PLAGUE_CLOUD = 29350,
- SPELL_TELEPORT_SELF = 30211
-};
-
-enum Events
-{
- EVENT_DISRUPTION = 1,
- EVENT_DECEPIT_FEVER = 2,
- EVENT_ERUPT_SECTION = 3,
- EVENT_SWITCH_PHASE = 4,
- EVENT_SAFETY_DANCE = 5,
- EVENT_PLAGUE_CLOUD = 6
-};
-
-enum Misc
-{
- PHASE_SLOW_DANCE = 0,
- PHASE_FAST_DANCE = 1
-};
-
-class boss_heigan : public CreatureScript
-{
-public:
- boss_heigan() : CreatureScript("boss_heigan") { }
-
- CreatureAI* GetAI(Creature* pCreature) const override
- {
- return GetNaxxramasAI(pCreature);
- }
-
- struct boss_heiganAI : public BossAI
- {
- explicit boss_heiganAI(Creature* c) : BossAI(c, BOSS_HEIGAN)
- {}
-
- EventMap events;
- uint8 currentPhase{};
- uint8 currentSection{};
- bool moveRight{};
-
- void Reset() override
- {
- BossAI::Reset();
- events.Reset();
- currentPhase = 0;
- currentSection = 3;
- moveRight = true;
- }
-
- void KilledUnit(Unit* who) override
- {
- if (!who->IsPlayer())
- return;
-
- Talk(SAY_SLAY);
- instance->StorePersistentData(PERSISTENT_DATA_IMMORTAL_FAIL, 1);
- }
-
- void JustDied(Unit* killer) override
- {
- BossAI::JustDied(killer);
- Talk(EMOTE_DEATH);
- }
-
- void JustEngagedWith(Unit* who) override
- {
- BossAI::JustEngagedWith(who);
- me->SetInCombatWithZone();
- Talk(SAY_AGGRO);
- StartFightPhase(PHASE_SLOW_DANCE);
- }
-
- void StartFightPhase(uint8 phase)
- {
- currentSection = 3;
- currentPhase = phase;
- events.Reset();
- if (phase == PHASE_SLOW_DANCE)
- {
- me->CastStop();
- me->SetReactState(REACT_AGGRESSIVE);
- DoZoneInCombat();
- events.ScheduleEvent(EVENT_DISRUPTION, 12s, 15s);
- events.ScheduleEvent(EVENT_DECEPIT_FEVER, 17s);
- events.ScheduleEvent(EVENT_ERUPT_SECTION, 15s);
- events.ScheduleEvent(EVENT_SWITCH_PHASE, 90s);
- }
- else // if (phase == PHASE_FAST_DANCE)
- {
- Talk(EMOTE_DANCE);
- Talk(SAY_DANCE);
- me->AttackStop();
- me->StopMoving();
- me->SetReactState(REACT_PASSIVE);
- me->CastSpell(me, SPELL_TELEPORT_SELF, false);
- me->SetFacingTo(2.40f);
- events.ScheduleEvent(EVENT_PLAGUE_CLOUD, 1s);
- events.ScheduleEvent(EVENT_ERUPT_SECTION, 7s);
- events.ScheduleEvent(EVENT_SWITCH_PHASE, 45s);
- }
- events.ScheduleEvent(EVENT_SAFETY_DANCE, 5s);
- }
-
- bool IsInRoom(Unit* who)
- {
- if (who->GetPositionX() > 2826 || who->GetPositionX() < 2723 || who->GetPositionY() > -3641 || who->GetPositionY() < -3736)
- {
- if (who->GetGUID() == me->GetGUID())
- EnterEvadeMode();
-
- return false;
- }
- return true;
- }
-
- void UpdateAI(uint32 diff) override
- {
- if (!IsInRoom(me))
- return;
-
- if (!UpdateVictim())
- return;
-
- events.Update(diff);
-
- switch (events.ExecuteEvent())
- {
- case EVENT_DISRUPTION:
- me->CastSpell(me, SPELL_SPELL_DISRUPTION, false);
- events.Repeat(10s);
- break;
- case EVENT_DECEPIT_FEVER:
- me->CastSpell(me, SPELL_DECREPIT_FEVER, false);
- events.Repeat(22s, 25s);
- break;
- case EVENT_PLAGUE_CLOUD:
- me->CastSpell(me, SPELL_PLAGUE_CLOUD, false);
- break;
- case EVENT_SWITCH_PHASE:
- if (currentPhase == PHASE_SLOW_DANCE)
- {
- StartFightPhase(PHASE_FAST_DANCE);
- }
- else
- {
- StartFightPhase(PHASE_SLOW_DANCE);
- Talk(EMOTE_DANCE_END); // avoid play the emote on aggro
- }
- break;
- case EVENT_ERUPT_SECTION:
- {
- instance->SetData(DATA_HEIGAN_ERUPTION, currentSection);
- if (currentSection == 3)
- moveRight = false;
- else if (currentSection == 0)
- moveRight = true;
-
- moveRight ? currentSection++ : currentSection--;
-
- if (currentPhase == PHASE_SLOW_DANCE)
- Talk(SAY_TAUNT);
-
- events.Repeat(currentPhase == PHASE_SLOW_DANCE ? 10s : 4s);
- break;
- }
- case EVENT_SAFETY_DANCE:
- {
- Map::PlayerList const& pList = me->GetMap()->GetPlayers();
- for (auto const& itr : pList)
- {
- if (IsInRoom(itr.GetSource()) && !itr.GetSource()->IsAlive())
- {
- instance->SetData(DATA_DANCE_FAIL, 0);
- instance->StorePersistentData(PERSISTENT_DATA_IMMORTAL_FAIL, 1);
- return;
- }
- }
- events.Repeat(5s);
- return;
- }
- }
-
- DoMeleeAttackIfReady();
- }
- };
-};
-
-}
-#endif
\ No newline at end of file
diff --git a/src/server/scripts/Northrend/Naxxramas/boss_kelthuzad.cpp b/src/server/scripts/Northrend/Naxxramas/boss_kelthuzad.cpp
index d7be6124c..38fce6620 100644
--- a/src/server/scripts/Northrend/Naxxramas/boss_kelthuzad.cpp
+++ b/src/server/scripts/Northrend/Naxxramas/boss_kelthuzad.cpp
@@ -15,7 +15,6 @@
* with this program. If not, see .
*/
-#include "boss_kelthuzad.h"
#include "CreatureScript.h"
#include "Player.h"
#include "ScriptedCreature.h"
@@ -23,11 +22,661 @@
#include "SpellScriptLoader.h"
#include "naxxramas.h"
+enum Yells
+{
+ SAY_ANSWER_REQUEST = 3,
+ SAY_TAUNT = 6,
+ SAY_AGGRO = 7,
+ SAY_SLAY = 8,
+ SAY_DEATH = 9,
+ SAY_CHAIN = 10,
+ SAY_FROST_BLAST = 11,
+ SAY_REQUEST_AID = 12,
+ EMOTE_PHASE_TWO = 13,
+ SAY_SUMMON_MINIONS = 14,
+ SAY_SPECIAL = 15,
-using namespace Kelthuzad;
+ EMOTE_GUARDIAN_FLEE = 0,
+ EMOTE_GUARDIAN_APPEAR = 1
+};
-// no custom changes has been made for mod-playerbot other then placing
-// the impl in a header file
+enum Spells
+{
+ // Kel'Thzuad
+ SPELL_FROST_BOLT_SINGLE = 28478,
+ SPELL_FROST_BOLT_MULTI = 28479,
+ SPELL_SHADOW_FISURE = 27810,
+ SPELL_VOID_BLAST = 27812,
+ SPELL_DETONATE_MANA = 27819,
+ SPELL_MANA_DETONATION_DAMAGE = 27820,
+ SPELL_FROST_BLAST = 27808,
+ SPELL_CHAINS_OF_KELTHUZAD = 28410, // 28408 script effect
+ SPELL_BERSERK = 28498,
+ SPELL_KELTHUZAD_CHANNEL = 29423,
+
+ // Minions
+ SPELL_FRENZY = 28468,
+ SPELL_MORTAL_WOUND = 28467,
+ SPELL_BLOOD_TAP = 28470
+};
+
+enum Misc
+{
+ NPC_SOLDIER_OF_THE_FROZEN_WASTES = 16427,
+ NPC_UNSTOPPABLE_ABOMINATION = 16428,
+ NPC_SOUL_WEAVER = 16429,
+ NPC_GUARDIAN_OF_ICECROWN = 16441,
+
+ ACTION_CALL_HELP_ON = 1,
+ ACTION_CALL_HELP_OFF = 2,
+ ACTION_SECOND_PHASE = 3,
+ ACTION_GUARDIANS_OFF = 4
+};
+
+enum Event
+{
+ // Kel'Thuzad
+ EVENT_SUMMON_SOLDIER = 1,
+ EVENT_SUMMON_UNSTOPPABLE_ABOMINATION = 2,
+ EVENT_SUMMON_SOUL_WEAVER = 3,
+ EVENT_PHASE_2 = 4,
+ EVENT_FROST_BOLT_SINGLE = 5,
+ EVENT_FROST_BOLT_MULTI = 6,
+ EVENT_DETONATE_MANA = 7,
+ EVENT_PHASE_3 = 8,
+ EVENT_P3_LICH_KING_SAY = 9,
+ EVENT_SHADOW_FISSURE = 10,
+ EVENT_FROST_BLAST = 11,
+ EVENT_CHAINS = 12,
+ EVENT_SUMMON_GUARDIAN_OF_ICECROWN = 13,
+ EVENT_FLOOR_CHANGE = 14,
+ EVENT_ENRAGE = 15,
+ EVENT_SPAWN_POOL = 16,
+
+ // Minions
+ EVENT_MINION_FRENZY = 17,
+ EVENT_MINION_MORTAL_WOUND = 18,
+ EVENT_MINION_BLOOD_TAP = 19
+};
+
+const Position SummonGroups[12] =
+{
+ // Portals
+ {3783.272705f, -5062.697266f, 143.711203f, 3.617599f}, // LEFT_FAR
+ {3730.291260f, -5027.239258f, 143.956909f, 4.461900f}, // LEFT_MIDDLE
+ {3683.868652f, -5057.281250f, 143.183884f, 5.237086f}, // LEFT_NEAR
+ {3759.355225f, -5174.128418f, 143.802383f, 2.170104f}, // RIGHT_FAR
+ {3700.724365f, -5185.123047f, 143.928024f, 1.309310f}, // RIGHT_MIDDLE
+ {3665.121094f, -5138.679199f, 143.183212f, 0.604023f}, // RIGHT_NEAR
+
+ // Middle
+ {3769.34f, -5071.80f, 143.2082f, 3.658f},
+ {3729.78f, -5043.56f, 143.3867f, 4.475f},
+ {3682.75f, -5055.26f, 143.1848f, 5.295f},
+ {3752.58f, -5161.82f, 143.2944f, 2.126f},
+ {3702.83f, -5171.70f, 143.4356f, 1.305f},
+ {3665.30f, -5141.55f, 143.1846f, 0.566f}
+};
+
+const Position SpawnPool[7] =
+{
+ // Portals
+ {3783.272705f, -5062.697266f, 143.711203f, 3.617599f}, // LEFT_FAR
+ {3730.291260f, -5027.239258f, 143.956909f, 4.461900f}, // LEFT_MIDDLE
+ {3683.868652f, -5057.281250f, 143.183884f, 5.237086f}, // LEFT_NEAR
+ {3759.355225f, -5174.128418f, 143.802383f, 2.170104f}, // RIGHT_FAR
+ {3700.724365f, -5185.123047f, 143.928024f, 1.309310f}, // RIGHT_MIDDLE
+ {3665.121094f, -5138.679199f, 143.183212f, 0.604023f}, // RIGHT_NEAR
+ {3651.729980f, -5092.620117f, 143.380005f, 6.050000f} // GATE
+};
+
+class boss_kelthuzad : public CreatureScript
+{
+public:
+ boss_kelthuzad() : CreatureScript("boss_kelthuzad") { }
+
+ CreatureAI* GetAI(Creature* pCreature) const override
+ {
+ return GetNaxxramasAI(pCreature);
+ }
+
+ struct boss_kelthuzadAI : public BossAI
+ {
+ explicit boss_kelthuzadAI(Creature* c) : BossAI(c, BOSS_KELTHUZAD), summons(me)
+ {}
+
+ EventMap events;
+ SummonList summons;
+
+ float NormalizeOrientation(float o)
+ {
+ return std::fmod(o, 2.0f * static_cast(M_PI)); // Only positive values will be passed
+ }
+
+ void SpawnHelpers()
+ {
+ // spawn at gate
+ me->SummonCreature(NPC_UNSTOPPABLE_ABOMINATION, 3656.19f, -5093.78f, 143.33f, 6.08, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 2000);// abo center
+ me->SummonCreature(NPC_UNSTOPPABLE_ABOMINATION, 3657.94f, -5087.68f, 143.60f, 6.08, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 2000);// abo left
+ me->SummonCreature(NPC_UNSTOPPABLE_ABOMINATION, 3655.48f, -5100.05f, 143.53f, 6.08, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 2000);// abo right
+ me->SummonCreature(NPC_SOUL_WEAVER, 3651.73f, -5092.62f, 143.38f, 6.05, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 2000); // soul behind
+ me->SummonCreature(NPC_SOLDIER_OF_THE_FROZEN_WASTES, 3660.17f, -5092.45f, 143.37f, 6.07, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 2000); // ske front left
+ me->SummonCreature(NPC_SOLDIER_OF_THE_FROZEN_WASTES, 3659.39f, -5096.21f, 143.29f, 6.07, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 2000); // ske front right
+ me->SummonCreature(NPC_SOLDIER_OF_THE_FROZEN_WASTES, 3659.29f, -5090.19f, 143.48f, 6.07, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 2000); // ske left left
+ me->SummonCreature(NPC_SOLDIER_OF_THE_FROZEN_WASTES, 3657.43f, -5098.03f, 143.41f, 6.07, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 2000); // ske right right
+ me->SummonCreature(NPC_SOLDIER_OF_THE_FROZEN_WASTES, 3654.36f, -5090.51f, 143.48f, 6.09, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 2000); // ske behind left
+ me->SummonCreature(NPC_SOLDIER_OF_THE_FROZEN_WASTES, 3653.35f, -5095.91f, 143.41f, 6.09, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 2000); // ske right right
+
+ // 6 rooms, 8 soldiers, 3 abominations and 1 weaver in each room | middle positions in table starts from 6
+ for (uint8 i = 6; i < 12; ++i)
+ {
+ for (uint8 j = 0; j < 8; ++j)
+ {
+ float angle = M_PI * 2 / 8 * j;
+ me->SummonCreature(NPC_SOLDIER_OF_THE_FROZEN_WASTES, SummonGroups[i].GetPositionX() + 6 * cos(angle), SummonGroups[i].GetPositionY() + 6 * std::sin(angle), SummonGroups[i].GetPositionZ(), SummonGroups[i].GetOrientation(), TEMPSUMMON_CORPSE_TIMED_DESPAWN, 20000);
+ }
+ }
+ for (uint8 i = 6; i < 12; ++i)
+ {
+ for (uint8 j = 1; j < 4; ++j)
+ {
+ float dist = j == 2 ? 0.0f : 8.0f; // second in middle
+ float angle = SummonGroups[i].GetOrientation() + M_PI * 2 / 4 * j;
+ me->SummonCreature(NPC_UNSTOPPABLE_ABOMINATION, SummonGroups[i].GetPositionX() + dist * cos(angle), SummonGroups[i].GetPositionY() + dist * std::sin(angle), SummonGroups[i].GetPositionZ(), SummonGroups[i].GetOrientation(), TEMPSUMMON_CORPSE_TIMED_DESPAWN, 20000);
+ }
+ }
+ for (uint8 i = 6; i < 12; ++i)
+ {
+ for (uint8 j = 0; j < 1; ++j)
+ {
+ float angle = SummonGroups[i].GetOrientation() + M_PI;
+ me->SummonCreature(NPC_SOUL_WEAVER, SummonGroups[i].GetPositionX() + 6 * cos(angle), SummonGroups[i].GetPositionY() + 6 * std::sin(angle), SummonGroups[i].GetPositionZ() + 0.5f, SummonGroups[i].GetOrientation(), TEMPSUMMON_CORPSE_TIMED_DESPAWN, 20000);
+ }
+ }
+ }
+
+ void SummonHelper(uint32 entry, uint32 count)
+ {
+ for (uint8 i = 0; i < count; ++i)
+ {
+ if (Creature* cr = me->SummonCreature(entry, SpawnPool[urand(0, 6)], TEMPSUMMON_CORPSE_TIMED_DESPAWN, 20000))
+ {
+ if (Unit* target = SelectTargetFromPlayerList(100.0f))
+ {
+ cr->AI()->DoAction(ACTION_CALL_HELP_OFF);
+ cr->AI()->AttackStart(target);
+ }
+ }
+ }
+ }
+
+ void Reset() override
+ {
+ BossAI::Reset();
+ events.Reset();
+ summons.DespawnAll();
+ me->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_DISABLE_MOVE);
+ me->SetReactState(REACT_AGGRESSIVE);
+ if (GameObject* go = instance->GetGameObject(DATA_KELTHUZAD_FLOOR))
+ {
+ go->SetPhaseMask(1, true);
+ go->SetGoState(GO_STATE_READY);
+ }
+
+ if (GameObject* go = instance->GetGameObject(DATA_KELTHUZAD_PORTAL_1))
+ go->SetGoState(GO_STATE_READY);
+
+ if (GameObject* go = instance->GetGameObject(DATA_KELTHUZAD_PORTAL_2))
+ go->SetGoState(GO_STATE_READY);
+
+ if (GameObject* go = instance->GetGameObject(DATA_KELTHUZAD_PORTAL_3))
+ go->SetGoState(GO_STATE_READY);
+
+ if (GameObject* go = instance->GetGameObject(DATA_KELTHUZAD_PORTAL_4))
+ go->SetGoState(GO_STATE_READY);
+ }
+
+ void EnterEvadeMode(EvadeReason why) override
+ {
+ me->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_DISABLE_MOVE);
+ ScriptedAI::EnterEvadeMode(why);
+ }
+
+ void KilledUnit(Unit* who) override
+ {
+ if (!who->IsPlayer())
+ return;
+
+ Talk(SAY_SLAY);
+ instance->StorePersistentData(PERSISTENT_DATA_IMMORTAL_FAIL, 1);
+ }
+
+ void JustDied(Unit* killer) override
+ {
+ BossAI::JustDied(killer);
+ summons.DoAction(ACTION_GUARDIANS_OFF);
+ if (Creature* guardian = summons.GetCreatureWithEntry(NPC_GUARDIAN_OF_ICECROWN))
+ {
+ guardian->AI()->Talk(EMOTE_GUARDIAN_FLEE);
+ }
+ Talk(SAY_DEATH);
+ }
+
+ void MoveInLineOfSight(Unit* who) override
+ {
+ if (!me->IsInCombat() && who->IsPlayer() && who->IsAlive() && me->GetDistance(who) <= 50.0f)
+ AttackStart(who);
+ }
+
+ void JustEngagedWith(Unit* who) override
+ {
+ BossAI::JustEngagedWith(who);
+ Talk(SAY_SUMMON_MINIONS);
+ me->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_DISABLE_MOVE);
+ me->RemoveAllAttackers();
+ me->SetTarget();
+ me->SetReactState(REACT_PASSIVE);
+ me->CastSpell(me, SPELL_KELTHUZAD_CHANNEL, false);
+ events.ScheduleEvent(EVENT_SPAWN_POOL, 5s);
+ events.ScheduleEvent(EVENT_SUMMON_SOLDIER, 6400ms);
+ events.ScheduleEvent(EVENT_SUMMON_UNSTOPPABLE_ABOMINATION, 10s);
+ events.ScheduleEvent(EVENT_SUMMON_SOUL_WEAVER, 12s);
+ events.ScheduleEvent(EVENT_PHASE_2, 228s);
+ events.ScheduleEvent(EVENT_ENRAGE, 15min);
+
+ if (GameObject* go = instance->GetGameObject(DATA_KELTHUZAD_FLOOR))
+ {
+ events.ScheduleEvent(EVENT_FLOOR_CHANGE, 15s);
+ go->SetGoState(GO_STATE_ACTIVE);
+ }
+ }
+
+ void JustSummoned(Creature* cr) override
+ {
+ summons.Summon(cr);
+ if (!cr->IsInCombat())
+ {
+ cr->GetMotionMaster()->MoveRandom(5);
+ }
+ if (cr->GetEntry() == NPC_GUARDIAN_OF_ICECROWN)
+ {
+ cr->SetHomePosition(cr->GetPositionX(), cr->GetPositionY(), cr->GetPositionZ(), cr->GetOrientation());
+ }
+ }
+
+ void UpdateAI(uint32 diff) override
+ {
+ if (!UpdateVictim())
+ return;
+
+ events.Update(diff);
+ if (!me->HasAura(SPELL_KELTHUZAD_CHANNEL))
+ {
+ if (me->HasUnitState(UNIT_STATE_CASTING))
+ return;
+ }
+
+ switch (events.ExecuteEvent())
+ {
+ case EVENT_FLOOR_CHANGE:
+ if (GameObject* go = instance->GetGameObject(DATA_KELTHUZAD_FLOOR))
+ {
+ events.ScheduleEvent(EVENT_FLOOR_CHANGE, 15s);
+ go->SetGoState(GO_STATE_READY);
+ go->SetPhaseMask(2, true);
+ }
+ break;
+ case EVENT_SPAWN_POOL:
+ SpawnHelpers();
+ break;
+ case EVENT_SUMMON_SOLDIER:
+ SummonHelper(NPC_SOLDIER_OF_THE_FROZEN_WASTES, 1);
+ events.Repeat(3100ms);
+ break;
+ case EVENT_SUMMON_UNSTOPPABLE_ABOMINATION:
+ SummonHelper(NPC_UNSTOPPABLE_ABOMINATION, 1);
+ events.Repeat(18s + 500ms);
+ break;
+ case EVENT_SUMMON_SOUL_WEAVER:
+ SummonHelper(NPC_SOUL_WEAVER, 1);
+ events.Repeat(30s);
+ break;
+ case EVENT_PHASE_2:
+ Talk(EMOTE_PHASE_TWO);
+ Talk(SAY_AGGRO);
+ events.Reset();
+ summons.DoAction(ACTION_SECOND_PHASE);
+ me->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_DISABLE_MOVE);
+ me->GetMotionMaster()->MoveChase(me->GetVictim());
+ me->RemoveAura(SPELL_KELTHUZAD_CHANNEL);
+ me->SetReactState(REACT_AGGRESSIVE);
+ events.ScheduleEvent(EVENT_FROST_BOLT_SINGLE, 2s, 10s);
+ events.ScheduleEvent(EVENT_FROST_BOLT_MULTI, 15s, 30s);
+ events.ScheduleEvent(EVENT_DETONATE_MANA, 30s);
+ events.ScheduleEvent(EVENT_PHASE_3, 1s);
+ events.ScheduleEvent(EVENT_SHADOW_FISSURE, 25s);
+ events.ScheduleEvent(EVENT_FROST_BLAST, 45s);
+ if (Is25ManRaid())
+ {
+ events.ScheduleEvent(EVENT_CHAINS, 90s);
+ }
+ break;
+ case EVENT_ENRAGE:
+ me->CastSpell(me, SPELL_BERSERK, true);
+ break;
+ case EVENT_FROST_BOLT_SINGLE:
+ me->CastSpell(me->GetVictim(), SPELL_FROST_BOLT_SINGLE, false);
+ events.Repeat(2s, 10s);
+ break;
+ case EVENT_FROST_BOLT_MULTI:
+ me->CastSpell(me, SPELL_FROST_BOLT_MULTI, false);
+ events.Repeat(15s, 30s);
+ break;
+ case EVENT_SHADOW_FISSURE:
+ if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 100.0f, true))
+ {
+ me->CastSpell(target, SPELL_SHADOW_FISURE, false);
+ }
+ events.Repeat(25s);
+ break;
+ case EVENT_FROST_BLAST:
+ if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 0, true, RAID_MODE(false, true)))
+ {
+ me->CastSpell(target, SPELL_FROST_BLAST, false);
+ }
+ Talk(SAY_FROST_BLAST);
+ events.Repeat(45s);
+ break;
+ case EVENT_CHAINS:
+ for (uint8 i = 0; i < 3; ++i)
+ {
+ if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 200, true, false, -SPELL_CHAINS_OF_KELTHUZAD))
+ {
+ me->CastSpell(target, SPELL_CHAINS_OF_KELTHUZAD, true);
+ }
+ }
+ Talk(SAY_CHAIN);
+ events.Repeat(90s);
+ break;
+ case EVENT_DETONATE_MANA:
+ {
+ std::vector unitList;
+ ThreatContainer::StorageType const& threatList = me->GetThreatMgr().GetThreatList();
+ for (auto itr : threatList)
+ {
+ if (itr->getTarget()->IsPlayer()
+ && itr->getTarget()->getPowerType() == POWER_MANA
+ && itr->getTarget()->GetPower(POWER_MANA))
+ {
+ unitList.push_back(itr->getTarget());
+ }
+ }
+ if (!unitList.empty())
+ {
+ auto itr = unitList.begin();
+ advance(itr, urand(0, unitList.size() - 1));
+ me->CastSpell(*itr, SPELL_DETONATE_MANA, false);
+ Talk(SAY_SPECIAL);
+ }
+ events.Repeat(30s);
+ break;
+ }
+ case EVENT_PHASE_3:
+ if (me->HealthBelowPct(45))
+ {
+ Talk(SAY_REQUEST_AID);
+ events.DelayEvents(5500ms);
+ events.ScheduleEvent(EVENT_P3_LICH_KING_SAY, 5s);
+ if (GameObject* go = instance->GetGameObject(DATA_KELTHUZAD_PORTAL_1))
+ go->SetGoState(GO_STATE_ACTIVE);
+
+ if (GameObject* go = instance->GetGameObject(DATA_KELTHUZAD_PORTAL_2))
+ go->SetGoState(GO_STATE_ACTIVE);
+
+ if (GameObject* go = instance->GetGameObject(DATA_KELTHUZAD_PORTAL_3))
+ go->SetGoState(GO_STATE_ACTIVE);
+
+ if (GameObject* go = instance->GetGameObject(DATA_KELTHUZAD_PORTAL_4))
+ go->SetGoState(GO_STATE_ACTIVE);
+
+ break;
+ }
+ events.Repeat(1s);
+ break;
+ case EVENT_P3_LICH_KING_SAY:
+ {
+ if (Creature* cr = instance->GetCreature(DATA_LICH_KING_BOSS))
+ cr->AI()->Talk(SAY_ANSWER_REQUEST);
+
+ for (uint8 i = 0 ; i < RAID_MODE(2, 4); ++i)
+ events.ScheduleEvent(EVENT_SUMMON_GUARDIAN_OF_ICECROWN, Milliseconds(10000 + (i * 5000)));
+
+ break;
+ }
+ case EVENT_SUMMON_GUARDIAN_OF_ICECROWN:
+ if (Creature* cr = me->SummonCreature(NPC_GUARDIAN_OF_ICECROWN, SpawnPool[RAND(0, 1, 3, 4)]))
+ {
+ cr->AI()->Talk(EMOTE_GUARDIAN_APPEAR);
+ cr->AI()->AttackStart(me->GetVictim());
+ }
+ break;
+ }
+ if (!me->HasUnitFlag(UNIT_FLAG_DISABLE_MOVE))
+ DoMeleeAttackIfReady();
+ }
+ };
+};
+
+class boss_kelthuzad_minion : public CreatureScript
+{
+public:
+ boss_kelthuzad_minion() : CreatureScript("boss_kelthuzad_minion") { }
+
+ CreatureAI* GetAI(Creature* pCreature) const override
+ {
+ return GetNaxxramasAI(pCreature);
+ }
+
+ struct boss_kelthuzad_minionAI : public ScriptedAI
+ {
+ explicit boss_kelthuzad_minionAI(Creature* c) : ScriptedAI(c) { }
+
+ EventMap events;
+ bool callHelp{};
+
+ void Reset() override
+ {
+ me->SetNoCallAssistance(true);
+ callHelp = true;
+ events.Reset();
+ }
+
+ void DoAction(int32 param) override
+ {
+ if (param == ACTION_CALL_HELP_ON)
+ {
+ callHelp = true;
+ }
+ else if (param == ACTION_CALL_HELP_OFF)
+ {
+ callHelp = false;
+ }
+ else if (param == ACTION_SECOND_PHASE)
+ {
+ if (!me->IsInCombat())
+ {
+ me->DespawnOrUnsummon(500ms);
+ }
+ }
+ if (param == ACTION_GUARDIANS_OFF)
+ {
+ me->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
+ me->SetUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
+ me->RemoveAllAuras();
+ EnterEvadeMode();
+ me->SetPosition(me->GetHomePosition());
+ }
+ }
+
+ void MoveInLineOfSight(Unit* who) override
+ {
+ if (!who->IsPlayer() && !who->IsPet())
+ return;
+
+ ScriptedAI::MoveInLineOfSight(who);
+ }
+
+ void JustDied(Unit* /*killer*/) override
+ {
+ if (me->GetEntry() == NPC_UNSTOPPABLE_ABOMINATION)
+ me->GetInstanceScript()->SetData(DATA_ABOMINATION_KILLED, 0);
+ }
+
+ void AttackStart(Unit* who) override
+ {
+ ScriptedAI::AttackStart(who);
+ if (callHelp)
+ {
+ std::list targets;
+ me->GetCreaturesWithEntryInRange(targets, 15.0f, me->GetEntry());
+ for (std::list::const_iterator itr = targets.begin(); itr != targets.end(); ++itr)
+ {
+ if ((*itr)->GetGUID() != me->GetGUID())
+ {
+ (*itr)->ToCreature()->AI()->DoAction(ACTION_CALL_HELP_OFF);
+ (*itr)->ToCreature()->AI()->AttackStart(who);
+ }
+ }
+ }
+
+ if (me->GetEntry() != NPC_UNSTOPPABLE_ABOMINATION && me->GetEntry() != NPC_GUARDIAN_OF_ICECROWN)
+ {
+ me->AddThreat(who, 1000000.0f);
+ }
+ }
+
+ void JustEngagedWith(Unit* /*who*/) override
+ {
+ me->SetInCombatWithZone();
+ if (me->GetEntry() == NPC_UNSTOPPABLE_ABOMINATION)
+ {
+ events.ScheduleEvent(EVENT_MINION_FRENZY, 1s);
+ events.ScheduleEvent(EVENT_MINION_MORTAL_WOUND, 5s);
+ }
+ else if (me->GetEntry() == NPC_GUARDIAN_OF_ICECROWN)
+ {
+ events.ScheduleEvent(EVENT_MINION_BLOOD_TAP, 15s);
+ }
+ }
+
+ void KilledUnit(Unit* who) override
+ {
+ if (who->IsPlayer())
+ me->GetInstanceScript()->StorePersistentData(PERSISTENT_DATA_IMMORTAL_FAIL, 1);
+ }
+
+ void JustReachedHome() override
+ {
+ if (me->GetEntry() == NPC_GUARDIAN_OF_ICECROWN)
+ {
+ me->DespawnOrUnsummon();
+ }
+ }
+
+ void UpdateAI(uint32 diff) override
+ {
+ if (!UpdateVictim())
+ return;
+
+ events.Update(diff);
+ if (me->HasUnitState(UNIT_STATE_CASTING))
+ return;
+
+ switch (events.ExecuteEvent())
+ {
+ case EVENT_MINION_MORTAL_WOUND:
+ me->CastSpell(me->GetVictim(), SPELL_MORTAL_WOUND, false);
+ events.Repeat(15s);
+ break;
+ case EVENT_MINION_FRENZY:
+ if (me->HealthBelowPct(35))
+ {
+ me->CastSpell(me, SPELL_FRENZY, true);
+ break;
+ }
+ events.Repeat(1s);
+ break;
+ case EVENT_MINION_BLOOD_TAP:
+ me->CastSpell(me->GetVictim(), SPELL_BLOOD_TAP, false);
+ events.Repeat(15s);
+ break;
+ }
+ DoMeleeAttackIfReady();
+ }
+ };
+};
+
+class spell_kelthuzad_frost_blast : public SpellScript
+{
+ PrepareSpellScript(spell_kelthuzad_frost_blast);
+
+ bool Validate(SpellInfo const* /*spell*/) override
+ {
+ return ValidateSpellInfo({ SPELL_FROST_BLAST });
+ }
+
+ void FilterTargets(std::list& targets)
+ {
+ Unit* caster = GetCaster();
+ if (!caster || !caster->ToCreature())
+ return;
+
+ std::list tmplist;
+ for (auto& target : targets)
+ {
+ if (!target->ToUnit()->HasAura(SPELL_FROST_BLAST))
+ {
+ tmplist.push_back(target);
+ }
+ }
+ targets.clear();
+ for (auto& itr : tmplist)
+ {
+ targets.push_back(itr);
+ }
+ }
+
+ void Register() override
+ {
+ OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_kelthuzad_frost_blast::FilterTargets, EFFECT_ALL, TARGET_UNIT_DEST_AREA_ENEMY);
+ }
+};
+
+class spell_kelthuzad_detonate_mana_aura : public AuraScript
+{
+ PrepareAuraScript(spell_kelthuzad_detonate_mana_aura);
+
+ bool Validate(SpellInfo const* /*spell*/) override
+ {
+ return ValidateSpellInfo({ SPELL_MANA_DETONATION_DAMAGE });
+ }
+
+ void HandleScript(AuraEffect const* aurEff)
+ {
+ PreventDefaultAction();
+ Unit* target = GetTarget();
+ if (auto mana = int32(target->GetMaxPower(POWER_MANA) / 10))
+ {
+ mana = target->ModifyPower(POWER_MANA, -mana);
+ target->CastCustomSpell(SPELL_MANA_DETONATION_DAMAGE, SPELLVALUE_BASE_POINT0, -mana * 10, target, true, nullptr, aurEff);
+ }
+ }
+
+ void Register() override
+ {
+ OnEffectPeriodic += AuraEffectPeriodicFn(spell_kelthuzad_detonate_mana_aura::HandleScript, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL);
+ }
+};
void AddSC_boss_kelthuzad()
{
diff --git a/src/server/scripts/Northrend/Naxxramas/boss_kelthuzad.h b/src/server/scripts/Northrend/Naxxramas/boss_kelthuzad.h
deleted file mode 100644
index c3f9ef8b5..000000000
--- a/src/server/scripts/Northrend/Naxxramas/boss_kelthuzad.h
+++ /dev/null
@@ -1,670 +0,0 @@
-#ifndef BOSS_KELTHUZAD_H_
-#define BOSS_KELTHUZAD_H_
-
-#include "Player.h"
-#include "ScriptMgr.h"
-#include "ScriptedCreature.h"
-#include "SpellScript.h"
-#include "SpellInfo.h"
-#include "naxxramas.h"
-
-namespace Kelthuzad {
-
-enum Yells
-{
- SAY_ANSWER_REQUEST = 3,
- SAY_TAUNT = 6,
- SAY_AGGRO = 7,
- SAY_SLAY = 8,
- SAY_DEATH = 9,
- SAY_CHAIN = 10,
- SAY_FROST_BLAST = 11,
- SAY_REQUEST_AID = 12,
- EMOTE_PHASE_TWO = 13,
- SAY_SUMMON_MINIONS = 14,
- SAY_SPECIAL = 15,
-
- EMOTE_GUARDIAN_FLEE = 0,
- EMOTE_GUARDIAN_APPEAR = 1
-};
-
-enum Spells
-{
- // Kel'Thzuad
- SPELL_FROST_BOLT_SINGLE = 28478,
- SPELL_FROST_BOLT_MULTI = 28479,
- SPELL_SHADOW_FISURE = 27810,
- SPELL_VOID_BLAST = 27812,
- SPELL_DETONATE_MANA = 27819,
- SPELL_MANA_DETONATION_DAMAGE = 27820,
- SPELL_FROST_BLAST = 27808,
- SPELL_CHAINS_OF_KELTHUZAD = 28410, // 28408 script effect
- SPELL_BERSERK = 28498,
- SPELL_KELTHUZAD_CHANNEL = 29423,
-
- // Minions
- SPELL_FRENZY = 28468,
- SPELL_MORTAL_WOUND = 28467,
- SPELL_BLOOD_TAP = 28470
-};
-
-enum Misc
-{
- NPC_SOLDIER_OF_THE_FROZEN_WASTES = 16427,
- NPC_UNSTOPPABLE_ABOMINATION = 16428,
- NPC_SOUL_WEAVER = 16429,
- NPC_GUARDIAN_OF_ICECROWN = 16441,
-
- ACTION_CALL_HELP_ON = 1,
- ACTION_CALL_HELP_OFF = 2,
- ACTION_SECOND_PHASE = 3,
- ACTION_GUARDIANS_OFF = 4
-};
-
-enum Event
-{
- // Kel'Thuzad
- EVENT_SUMMON_SOLDIER = 1,
- EVENT_SUMMON_UNSTOPPABLE_ABOMINATION = 2,
- EVENT_SUMMON_SOUL_WEAVER = 3,
- EVENT_PHASE_2 = 4,
- EVENT_FROST_BOLT_SINGLE = 5,
- EVENT_FROST_BOLT_MULTI = 6,
- EVENT_DETONATE_MANA = 7,
- EVENT_PHASE_3 = 8,
- EVENT_P3_LICH_KING_SAY = 9,
- EVENT_SHADOW_FISSURE = 10,
- EVENT_FROST_BLAST = 11,
- EVENT_CHAINS = 12,
- EVENT_SUMMON_GUARDIAN_OF_ICECROWN = 13,
- EVENT_FLOOR_CHANGE = 14,
- EVENT_ENRAGE = 15,
- EVENT_SPAWN_POOL = 16,
-
- // Minions
- EVENT_MINION_FRENZY = 17,
- EVENT_MINION_MORTAL_WOUND = 18,
- EVENT_MINION_BLOOD_TAP = 19
-};
-
-const Position SummonGroups[12] =
-{
- // Portals
- {3783.272705f, -5062.697266f, 143.711203f, 3.617599f}, // LEFT_FAR
- {3730.291260f, -5027.239258f, 143.956909f, 4.461900f}, // LEFT_MIDDLE
- {3683.868652f, -5057.281250f, 143.183884f, 5.237086f}, // LEFT_NEAR
- {3759.355225f, -5174.128418f, 143.802383f, 2.170104f}, // RIGHT_FAR
- {3700.724365f, -5185.123047f, 143.928024f, 1.309310f}, // RIGHT_MIDDLE
- {3665.121094f, -5138.679199f, 143.183212f, 0.604023f}, // RIGHT_NEAR
-
- // Middle
- {3769.34f, -5071.80f, 143.2082f, 3.658f},
- {3729.78f, -5043.56f, 143.3867f, 4.475f},
- {3682.75f, -5055.26f, 143.1848f, 5.295f},
- {3752.58f, -5161.82f, 143.2944f, 2.126f},
- {3702.83f, -5171.70f, 143.4356f, 1.305f},
- {3665.30f, -5141.55f, 143.1846f, 0.566f}
-};
-
-const Position SpawnPool[7] =
-{
- // Portals
- {3783.272705f, -5062.697266f, 143.711203f, 3.617599f}, // LEFT_FAR
- {3730.291260f, -5027.239258f, 143.956909f, 4.461900f}, // LEFT_MIDDLE
- {3683.868652f, -5057.281250f, 143.183884f, 5.237086f}, // LEFT_NEAR
- {3759.355225f, -5174.128418f, 143.802383f, 2.170104f}, // RIGHT_FAR
- {3700.724365f, -5185.123047f, 143.928024f, 1.309310f}, // RIGHT_MIDDLE
- {3665.121094f, -5138.679199f, 143.183212f, 0.604023f}, // RIGHT_NEAR
- {3651.729980f, -5092.620117f, 143.380005f, 6.050000f} // GATE
-};
-
-class boss_kelthuzad : public CreatureScript
-{
-public:
- boss_kelthuzad() : CreatureScript("boss_kelthuzad") { }
-
- CreatureAI* GetAI(Creature* pCreature) const override
- {
- return GetNaxxramasAI(pCreature);
- }
-
- struct boss_kelthuzadAI : public BossAI
- {
- explicit boss_kelthuzadAI(Creature* c) : BossAI(c, BOSS_KELTHUZAD), summons(me)
- {}
-
- EventMap events;
- SummonList summons;
-
- float NormalizeOrientation(float o)
- {
- return std::fmod(o, 2.0f * static_cast(M_PI)); // Only positive values will be passed
- }
-
- void SpawnHelpers()
- {
- // spawn at gate
- me->SummonCreature(NPC_UNSTOPPABLE_ABOMINATION, 3656.19f, -5093.78f, 143.33f, 6.08, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 2000);// abo center
- me->SummonCreature(NPC_UNSTOPPABLE_ABOMINATION, 3657.94f, -5087.68f, 143.60f, 6.08, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 2000);// abo left
- me->SummonCreature(NPC_UNSTOPPABLE_ABOMINATION, 3655.48f, -5100.05f, 143.53f, 6.08, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 2000);// abo right
- me->SummonCreature(NPC_SOUL_WEAVER, 3651.73f, -5092.62f, 143.38f, 6.05, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 2000); // soul behind
- me->SummonCreature(NPC_SOLDIER_OF_THE_FROZEN_WASTES, 3660.17f, -5092.45f, 143.37f, 6.07, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 2000); // ske front left
- me->SummonCreature(NPC_SOLDIER_OF_THE_FROZEN_WASTES, 3659.39f, -5096.21f, 143.29f, 6.07, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 2000); // ske front right
- me->SummonCreature(NPC_SOLDIER_OF_THE_FROZEN_WASTES, 3659.29f, -5090.19f, 143.48f, 6.07, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 2000); // ske left left
- me->SummonCreature(NPC_SOLDIER_OF_THE_FROZEN_WASTES, 3657.43f, -5098.03f, 143.41f, 6.07, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 2000); // ske right right
- me->SummonCreature(NPC_SOLDIER_OF_THE_FROZEN_WASTES, 3654.36f, -5090.51f, 143.48f, 6.09, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 2000); // ske behind left
- me->SummonCreature(NPC_SOLDIER_OF_THE_FROZEN_WASTES, 3653.35f, -5095.91f, 143.41f, 6.09, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 2000); // ske right right
-
- // 6 rooms, 8 soldiers, 3 abominations and 1 weaver in each room | middle positions in table starts from 6
- for (uint8 i = 6; i < 12; ++i)
- {
- for (uint8 j = 0; j < 8; ++j)
- {
- float angle = M_PI * 2 / 8 * j;
- me->SummonCreature(NPC_SOLDIER_OF_THE_FROZEN_WASTES, SummonGroups[i].GetPositionX() + 6 * cos(angle), SummonGroups[i].GetPositionY() + 6 * std::sin(angle), SummonGroups[i].GetPositionZ(), SummonGroups[i].GetOrientation(), TEMPSUMMON_CORPSE_TIMED_DESPAWN, 20000);
- }
- }
- for (uint8 i = 6; i < 12; ++i)
- {
- for (uint8 j = 1; j < 4; ++j)
- {
- float dist = j == 2 ? 0.0f : 8.0f; // second in middle
- float angle = SummonGroups[i].GetOrientation() + M_PI * 2 / 4 * j;
- me->SummonCreature(NPC_UNSTOPPABLE_ABOMINATION, SummonGroups[i].GetPositionX() + dist * cos(angle), SummonGroups[i].GetPositionY() + dist * std::sin(angle), SummonGroups[i].GetPositionZ(), SummonGroups[i].GetOrientation(), TEMPSUMMON_CORPSE_TIMED_DESPAWN, 20000);
- }
- }
- for (uint8 i = 6; i < 12; ++i)
- {
- for (uint8 j = 0; j < 1; ++j)
- {
- float angle = SummonGroups[i].GetOrientation() + M_PI;
- me->SummonCreature(NPC_SOUL_WEAVER, SummonGroups[i].GetPositionX() + 6 * cos(angle), SummonGroups[i].GetPositionY() + 6 * std::sin(angle), SummonGroups[i].GetPositionZ() + 0.5f, SummonGroups[i].GetOrientation(), TEMPSUMMON_CORPSE_TIMED_DESPAWN, 20000);
- }
- }
- }
-
- void SummonHelper(uint32 entry, uint32 count)
- {
- for (uint8 i = 0; i < count; ++i)
- {
- if (Creature* cr = me->SummonCreature(entry, SpawnPool[urand(0, 6)], TEMPSUMMON_CORPSE_TIMED_DESPAWN, 20000))
- {
- if (Unit* target = SelectTargetFromPlayerList(100.0f))
- {
- cr->AI()->DoAction(ACTION_CALL_HELP_OFF);
- cr->AI()->AttackStart(target);
- }
- }
- }
- }
-
- void Reset() override
- {
- BossAI::Reset();
- events.Reset();
- summons.DespawnAll();
- me->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_DISABLE_MOVE);
- me->SetReactState(REACT_AGGRESSIVE);
- if (GameObject* go = instance->GetGameObject(DATA_KELTHUZAD_FLOOR))
- {
- go->SetPhaseMask(1, true);
- go->SetGoState(GO_STATE_READY);
- }
-
- if (GameObject* go = instance->GetGameObject(DATA_KELTHUZAD_PORTAL_1))
- go->SetGoState(GO_STATE_READY);
-
- if (GameObject* go = instance->GetGameObject(DATA_KELTHUZAD_PORTAL_2))
- go->SetGoState(GO_STATE_READY);
-
- if (GameObject* go = instance->GetGameObject(DATA_KELTHUZAD_PORTAL_3))
- go->SetGoState(GO_STATE_READY);
-
- if (GameObject* go = instance->GetGameObject(DATA_KELTHUZAD_PORTAL_4))
- go->SetGoState(GO_STATE_READY);
- }
-
- void EnterEvadeMode(EvadeReason why) override
- {
- me->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_DISABLE_MOVE);
- ScriptedAI::EnterEvadeMode(why);
- }
-
- void KilledUnit(Unit* who) override
- {
- if (!who->IsPlayer())
- return;
-
- Talk(SAY_SLAY);
- instance->StorePersistentData(PERSISTENT_DATA_IMMORTAL_FAIL, 1);
- }
-
- void JustDied(Unit* killer) override
- {
- BossAI::JustDied(killer);
- summons.DoAction(ACTION_GUARDIANS_OFF);
- if (Creature* guardian = summons.GetCreatureWithEntry(NPC_GUARDIAN_OF_ICECROWN))
- {
- guardian->AI()->Talk(EMOTE_GUARDIAN_FLEE);
- }
- Talk(SAY_DEATH);
- }
-
- void MoveInLineOfSight(Unit* who) override
- {
- if (!me->IsInCombat() && who->IsPlayer() && who->IsAlive() && me->GetDistance(who) <= 50.0f)
- AttackStart(who);
- }
-
- void JustEngagedWith(Unit* who) override
- {
- BossAI::JustEngagedWith(who);
- Talk(SAY_SUMMON_MINIONS);
- me->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_DISABLE_MOVE);
- me->RemoveAllAttackers();
- me->SetTarget();
- me->SetReactState(REACT_PASSIVE);
- me->CastSpell(me, SPELL_KELTHUZAD_CHANNEL, false);
- events.ScheduleEvent(EVENT_SPAWN_POOL, 5s);
- events.ScheduleEvent(EVENT_SUMMON_SOLDIER, 6400ms);
- events.ScheduleEvent(EVENT_SUMMON_UNSTOPPABLE_ABOMINATION, 10s);
- events.ScheduleEvent(EVENT_SUMMON_SOUL_WEAVER, 12s);
- events.ScheduleEvent(EVENT_PHASE_2, 228s);
- events.ScheduleEvent(EVENT_ENRAGE, 15min);
-
- if (GameObject* go = instance->GetGameObject(DATA_KELTHUZAD_FLOOR))
- {
- events.ScheduleEvent(EVENT_FLOOR_CHANGE, 15s);
- go->SetGoState(GO_STATE_ACTIVE);
- }
- }
-
- void JustSummoned(Creature* cr) override
- {
- summons.Summon(cr);
- if (!cr->IsInCombat())
- {
- cr->GetMotionMaster()->MoveRandom(5);
- }
- if (cr->GetEntry() == NPC_GUARDIAN_OF_ICECROWN)
- {
- cr->SetHomePosition(cr->GetPositionX(), cr->GetPositionY(), cr->GetPositionZ(), cr->GetOrientation());
- }
- }
-
- void UpdateAI(uint32 diff) override
- {
- if (!UpdateVictim())
- return;
-
- events.Update(diff);
- if (!me->HasAura(SPELL_KELTHUZAD_CHANNEL))
- {
- if (me->HasUnitState(UNIT_STATE_CASTING))
- return;
- }
-
- switch (events.ExecuteEvent())
- {
- case EVENT_FLOOR_CHANGE:
- if (GameObject* go = instance->GetGameObject(DATA_KELTHUZAD_FLOOR))
- {
- events.ScheduleEvent(EVENT_FLOOR_CHANGE, 15s);
- go->SetGoState(GO_STATE_READY);
- go->SetPhaseMask(2, true);
- }
- break;
- case EVENT_SPAWN_POOL:
- SpawnHelpers();
- break;
- case EVENT_SUMMON_SOLDIER:
- SummonHelper(NPC_SOLDIER_OF_THE_FROZEN_WASTES, 1);
- events.Repeat(3100ms);
- break;
- case EVENT_SUMMON_UNSTOPPABLE_ABOMINATION:
- SummonHelper(NPC_UNSTOPPABLE_ABOMINATION, 1);
- events.Repeat(18s + 500ms);
- break;
- case EVENT_SUMMON_SOUL_WEAVER:
- SummonHelper(NPC_SOUL_WEAVER, 1);
- events.Repeat(30s);
- break;
- case EVENT_PHASE_2:
- Talk(EMOTE_PHASE_TWO);
- Talk(SAY_AGGRO);
- events.Reset();
- summons.DoAction(ACTION_SECOND_PHASE);
- me->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_DISABLE_MOVE);
- me->GetMotionMaster()->MoveChase(me->GetVictim());
- me->RemoveAura(SPELL_KELTHUZAD_CHANNEL);
- me->SetReactState(REACT_AGGRESSIVE);
- events.ScheduleEvent(EVENT_FROST_BOLT_SINGLE, 2s, 10s);
- events.ScheduleEvent(EVENT_FROST_BOLT_MULTI, 15s, 30s);
- events.ScheduleEvent(EVENT_DETONATE_MANA, 30s);
- events.ScheduleEvent(EVENT_PHASE_3, 1s);
- events.ScheduleEvent(EVENT_SHADOW_FISSURE, 25s);
- events.ScheduleEvent(EVENT_FROST_BLAST, 45s);
- if (Is25ManRaid())
- {
- events.ScheduleEvent(EVENT_CHAINS, 90s);
- }
- break;
- case EVENT_ENRAGE:
- me->CastSpell(me, SPELL_BERSERK, true);
- break;
- case EVENT_FROST_BOLT_SINGLE:
- me->CastSpell(me->GetVictim(), SPELL_FROST_BOLT_SINGLE, false);
- events.Repeat(2s, 10s);
- break;
- case EVENT_FROST_BOLT_MULTI:
- me->CastSpell(me, SPELL_FROST_BOLT_MULTI, false);
- events.Repeat(15s, 30s);
- break;
- case EVENT_SHADOW_FISSURE:
- if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 100.0f, true))
- {
- me->CastSpell(target, SPELL_SHADOW_FISURE, false);
- }
- events.Repeat(25s);
- break;
- case EVENT_FROST_BLAST:
- if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 0, true, RAID_MODE(false, true)))
- {
- me->CastSpell(target, SPELL_FROST_BLAST, false);
- }
- Talk(SAY_FROST_BLAST);
- events.Repeat(45s);
- break;
- case EVENT_CHAINS:
- for (uint8 i = 0; i < 3; ++i)
- {
- if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 200, true, false, -SPELL_CHAINS_OF_KELTHUZAD))
- {
- me->CastSpell(target, SPELL_CHAINS_OF_KELTHUZAD, true);
- }
- }
- Talk(SAY_CHAIN);
- events.Repeat(90s);
- break;
- case EVENT_DETONATE_MANA:
- {
- std::vector unitList;
- ThreatContainer::StorageType const& threatList = me->GetThreatMgr().GetThreatList();
- for (auto itr : threatList)
- {
- if (itr->getTarget()->IsPlayer()
- && itr->getTarget()->getPowerType() == POWER_MANA
- && itr->getTarget()->GetPower(POWER_MANA))
- {
- unitList.push_back(itr->getTarget());
- }
- }
- if (!unitList.empty())
- {
- auto itr = unitList.begin();
- advance(itr, urand(0, unitList.size() - 1));
- me->CastSpell(*itr, SPELL_DETONATE_MANA, false);
- Talk(SAY_SPECIAL);
- }
- events.Repeat(30s);
- break;
- }
- case EVENT_PHASE_3:
- if (me->HealthBelowPct(45))
- {
- Talk(SAY_REQUEST_AID);
- events.DelayEvents(5500ms);
- events.ScheduleEvent(EVENT_P3_LICH_KING_SAY, 5s);
- if (GameObject* go = instance->GetGameObject(DATA_KELTHUZAD_PORTAL_1))
- go->SetGoState(GO_STATE_ACTIVE);
-
- if (GameObject* go = instance->GetGameObject(DATA_KELTHUZAD_PORTAL_2))
- go->SetGoState(GO_STATE_ACTIVE);
-
- if (GameObject* go = instance->GetGameObject(DATA_KELTHUZAD_PORTAL_3))
- go->SetGoState(GO_STATE_ACTIVE);
-
- if (GameObject* go = instance->GetGameObject(DATA_KELTHUZAD_PORTAL_4))
- go->SetGoState(GO_STATE_ACTIVE);
-
- break;
- }
- events.Repeat(1s);
- break;
- case EVENT_P3_LICH_KING_SAY:
- {
- if (Creature* cr = instance->GetCreature(DATA_LICH_KING_BOSS))
- cr->AI()->Talk(SAY_ANSWER_REQUEST);
-
- for (uint8 i = 0 ; i < RAID_MODE(2, 4); ++i)
- events.ScheduleEvent(EVENT_SUMMON_GUARDIAN_OF_ICECROWN, Milliseconds(10000 + (i * 5000)));
-
- break;
- }
- case EVENT_SUMMON_GUARDIAN_OF_ICECROWN:
- if (Creature* cr = me->SummonCreature(NPC_GUARDIAN_OF_ICECROWN, SpawnPool[RAND(0, 1, 3, 4)]))
- {
- cr->AI()->Talk(EMOTE_GUARDIAN_APPEAR);
- cr->AI()->AttackStart(me->GetVictim());
- }
- break;
- }
- if (!me->HasUnitFlag(UNIT_FLAG_DISABLE_MOVE))
- DoMeleeAttackIfReady();
- }
- };
-};
-
-class boss_kelthuzad_minion : public CreatureScript
-{
-public:
- boss_kelthuzad_minion() : CreatureScript("boss_kelthuzad_minion") { }
-
- CreatureAI* GetAI(Creature* pCreature) const override
- {
- return GetNaxxramasAI(pCreature);
- }
-
- struct boss_kelthuzad_minionAI : public ScriptedAI
- {
- explicit boss_kelthuzad_minionAI(Creature* c) : ScriptedAI(c) { }
-
- EventMap events;
- bool callHelp{};
-
- void Reset() override
- {
- me->SetNoCallAssistance(true);
- callHelp = true;
- events.Reset();
- }
-
- void DoAction(int32 param) override
- {
- if (param == ACTION_CALL_HELP_ON)
- {
- callHelp = true;
- }
- else if (param == ACTION_CALL_HELP_OFF)
- {
- callHelp = false;
- }
- else if (param == ACTION_SECOND_PHASE)
- {
- if (!me->IsInCombat())
- {
- me->DespawnOrUnsummon(500ms);
- }
- }
- if (param == ACTION_GUARDIANS_OFF)
- {
- me->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
- me->SetUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
- me->RemoveAllAuras();
- EnterEvadeMode();
- me->SetPosition(me->GetHomePosition());
- }
- }
-
- void MoveInLineOfSight(Unit* who) override
- {
- if (!who->IsPlayer() && !who->IsPet())
- return;
-
- ScriptedAI::MoveInLineOfSight(who);
- }
-
- void JustDied(Unit* /*killer*/) override
- {
- if (me->GetEntry() == NPC_UNSTOPPABLE_ABOMINATION)
- me->GetInstanceScript()->SetData(DATA_ABOMINATION_KILLED, 0);
- }
-
- void AttackStart(Unit* who) override
- {
- ScriptedAI::AttackStart(who);
- if (callHelp)
- {
- std::list targets;
- me->GetCreaturesWithEntryInRange(targets, 15.0f, me->GetEntry());
- for (std::list::const_iterator itr = targets.begin(); itr != targets.end(); ++itr)
- {
- if ((*itr)->GetGUID() != me->GetGUID())
- {
- (*itr)->ToCreature()->AI()->DoAction(ACTION_CALL_HELP_OFF);
- (*itr)->ToCreature()->AI()->AttackStart(who);
- }
- }
- }
-
- if (me->GetEntry() != NPC_UNSTOPPABLE_ABOMINATION && me->GetEntry() != NPC_GUARDIAN_OF_ICECROWN)
- {
- me->AddThreat(who, 1000000.0f);
- }
- }
-
- void JustEngagedWith(Unit* /*who*/) override
- {
- me->SetInCombatWithZone();
- if (me->GetEntry() == NPC_UNSTOPPABLE_ABOMINATION)
- {
- events.ScheduleEvent(EVENT_MINION_FRENZY, 1s);
- events.ScheduleEvent(EVENT_MINION_MORTAL_WOUND, 5s);
- }
- else if (me->GetEntry() == NPC_GUARDIAN_OF_ICECROWN)
- {
- events.ScheduleEvent(EVENT_MINION_BLOOD_TAP, 15s);
- }
- }
-
- void KilledUnit(Unit* who) override
- {
- if (who->IsPlayer())
- me->GetInstanceScript()->StorePersistentData(PERSISTENT_DATA_IMMORTAL_FAIL, 1);
- }
-
- void JustReachedHome() override
- {
- if (me->GetEntry() == NPC_GUARDIAN_OF_ICECROWN)
- {
- me->DespawnOrUnsummon();
- }
- }
-
- void UpdateAI(uint32 diff) override
- {
- if (!UpdateVictim())
- return;
-
- events.Update(diff);
- if (me->HasUnitState(UNIT_STATE_CASTING))
- return;
-
- switch (events.ExecuteEvent())
- {
- case EVENT_MINION_MORTAL_WOUND:
- me->CastSpell(me->GetVictim(), SPELL_MORTAL_WOUND, false);
- events.Repeat(15s);
- break;
- case EVENT_MINION_FRENZY:
- if (me->HealthBelowPct(35))
- {
- me->CastSpell(me, SPELL_FRENZY, true);
- break;
- }
- events.Repeat(1s);
- break;
- case EVENT_MINION_BLOOD_TAP:
- me->CastSpell(me->GetVictim(), SPELL_BLOOD_TAP, false);
- events.Repeat(15s);
- break;
- }
- DoMeleeAttackIfReady();
- }
- };
-};
-
-class spell_kelthuzad_frost_blast : public SpellScript
-{
- PrepareSpellScript(spell_kelthuzad_frost_blast);
-
- bool Validate(SpellInfo const* /*spell*/) override
- {
- return ValidateSpellInfo({ SPELL_FROST_BLAST });
- }
-
- void FilterTargets(std::list& targets)
- {
- Unit* caster = GetCaster();
- if (!caster || !caster->ToCreature())
- return;
-
- std::list tmplist;
- for (auto& target : targets)
- {
- if (!target->ToUnit()->HasAura(SPELL_FROST_BLAST))
- {
- tmplist.push_back(target);
- }
- }
- targets.clear();
- for (auto& itr : tmplist)
- {
- targets.push_back(itr);
- }
- }
-
- void Register() override
- {
- OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_kelthuzad_frost_blast::FilterTargets, EFFECT_ALL, TARGET_UNIT_DEST_AREA_ENEMY);
- }
-};
-
-class spell_kelthuzad_detonate_mana_aura : public AuraScript
-{
- PrepareAuraScript(spell_kelthuzad_detonate_mana_aura);
-
- bool Validate(SpellInfo const* /*spell*/) override
- {
- return ValidateSpellInfo({ SPELL_MANA_DETONATION_DAMAGE });
- }
-
- void HandleScript(AuraEffect const* aurEff)
- {
- PreventDefaultAction();
- Unit* target = GetTarget();
- if (auto mana = int32(target->GetMaxPower(POWER_MANA) / 10))
- {
- mana = target->ModifyPower(POWER_MANA, -mana);
- target->CastCustomSpell(SPELL_MANA_DETONATION_DAMAGE, SPELLVALUE_BASE_POINT0, -mana * 10, target, true, nullptr, aurEff);
- }
- }
-
- void Register() override
- {
- OnEffectPeriodic += AuraEffectPeriodicFn(spell_kelthuzad_detonate_mana_aura::HandleScript, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL);
- }
-};
-
-}
-#endif
\ No newline at end of file
diff --git a/src/server/scripts/Northrend/Naxxramas/boss_loatheb.cpp b/src/server/scripts/Northrend/Naxxramas/boss_loatheb.cpp
index 5dc78fc08..0a91706ea 100644
--- a/src/server/scripts/Northrend/Naxxramas/boss_loatheb.cpp
+++ b/src/server/scripts/Northrend/Naxxramas/boss_loatheb.cpp
@@ -15,16 +15,158 @@
* with this program. If not, see .
*/
-#include "boss_loatheb.h"
#include "CreatureScript.h"
#include "ScriptedCreature.h"
#include "naxxramas.h"
+enum Spells
+{
+ SPELL_NECROTIC_AURA = 55593,
+ SPELL_SUMMON_SPORE = 29234,
+ SPELL_DEATHBLOOM = 29865,
+ SPELL_INEVITABLE_DOOM = 29204,
+ SPELL_BERSERK = 26662
+};
-using namespace Loatheb;
+enum Events
+{
+ EVENT_NECROTIC_AURA = 1,
+ EVENT_DEATHBLOOM = 2,
+ EVENT_INEVITABLE_DOOM = 3,
+ EVENT_BERSERK = 4,
+ EVENT_SUMMON_SPORE = 5,
+ EVENT_NECROTIC_AURA_FADING = 6,
+ EVENT_NECROTIC_AURA_REMOVED = 7
+};
-// no custom changes has been made for mod-playerbot other then placing
-// the impl in a header file
+enum Texts
+{
+ SAY_NECROTIC_AURA_APPLIED = 0,
+ SAY_NECROTIC_AURA_REMOVED = 1,
+ SAY_NECROTIC_AURA_FADING = 2
+};
+
+class boss_loatheb : public CreatureScript
+{
+public:
+ boss_loatheb() : CreatureScript("boss_loatheb") { }
+
+ CreatureAI* GetAI(Creature* pCreature) const override
+ {
+ return GetNaxxramasAI(pCreature);
+ }
+
+ struct boss_loathebAI : public BossAI
+ {
+ explicit boss_loathebAI(Creature* c) : BossAI(c, BOSS_LOATHEB), summons(me)
+ {
+ me->SetHomePosition(me->GetPositionX(), me->GetPositionY(), me->GetPositionZ(), me->GetOrientation());
+ }
+
+ uint8 doomCounter;
+ EventMap events;
+ SummonList summons;
+
+ void Reset() override
+ {
+ BossAI::Reset();
+ events.Reset();
+ summons.DespawnAll();
+ doomCounter = 0;
+ }
+
+ void JustSummoned(Creature* cr) override
+ {
+ cr->SetInCombatWithZone();
+ summons.Summon(cr);
+ }
+
+ void SummonedCreatureDies(Creature* /*cr*/, Unit*) override
+ {
+ instance->SetData(DATA_SPORE_KILLED, 0);
+ }
+
+ void KilledUnit(Unit* who) override
+ {
+ if (who->IsPlayer())
+ instance->StorePersistentData(PERSISTENT_DATA_IMMORTAL_FAIL, 1);
+ }
+
+ void JustEngagedWith(Unit* who) override
+ {
+ BossAI::JustEngagedWith(who);
+ me->SetInCombatWithZone();
+ events.ScheduleEvent(EVENT_NECROTIC_AURA, 10s);
+ events.ScheduleEvent(EVENT_DEATHBLOOM, 5s);
+ events.ScheduleEvent(EVENT_INEVITABLE_DOOM, 2min);
+ events.ScheduleEvent(EVENT_SUMMON_SPORE, 15s);
+ events.ScheduleEvent(EVENT_BERSERK, 12min);
+ }
+
+ void JustDied(Unit* killer) override
+ {
+ BossAI::JustDied(killer);
+ summons.DespawnAll();
+ }
+
+ void UpdateAI(uint32 diff) override
+ {
+ if (!UpdateVictim() || !IsInRoom())
+ return;
+
+ events.Update(diff);
+ if (me->HasUnitState(UNIT_STATE_CASTING))
+ return;
+
+ switch (events.ExecuteEvent())
+ {
+ case EVENT_SUMMON_SPORE:
+ me->CastSpell(me, SPELL_SUMMON_SPORE, true);
+ events.Repeat(35s);
+ break;
+ case EVENT_NECROTIC_AURA:
+ me->CastSpell(me, SPELL_NECROTIC_AURA, true);
+ Talk(SAY_NECROTIC_AURA_APPLIED);
+ events.ScheduleEvent(EVENT_NECROTIC_AURA_FADING, 14s);
+ events.ScheduleEvent(EVENT_NECROTIC_AURA_REMOVED, 17s);
+ events.Repeat(20s);
+ break;
+ case EVENT_DEATHBLOOM:
+ me->CastSpell(me, SPELL_DEATHBLOOM, false);
+ events.Repeat(30s);
+ break;
+ case EVENT_INEVITABLE_DOOM:
+ me->CastSpell(me, SPELL_INEVITABLE_DOOM, false);
+ doomCounter++;
+ events.Repeat(doomCounter < 6 ? 30s : 15s);
+ break;
+ case EVENT_BERSERK:
+ me->CastSpell(me, SPELL_BERSERK, true);
+ break;
+ case EVENT_NECROTIC_AURA_FADING:
+ Talk(SAY_NECROTIC_AURA_FADING);
+ break;
+ case EVENT_NECROTIC_AURA_REMOVED:
+ Talk(SAY_NECROTIC_AURA_REMOVED);
+ break;
+ }
+ DoMeleeAttackIfReady();
+ }
+
+ bool IsInRoom()
+ {
+ // Calculate the distance between his home position to the gate
+ if (me->GetExactDist(me->GetHomePosition().GetPositionX(),
+ me->GetHomePosition().GetPositionY(),
+ me->GetHomePosition().GetPositionZ()) > 50.0f)
+ {
+ EnterEvadeMode();
+ return false;
+ }
+ return true;
+ }
+ };
+};
void AddSC_boss_loatheb()
{
diff --git a/src/server/scripts/Northrend/Naxxramas/boss_loatheb.h b/src/server/scripts/Northrend/Naxxramas/boss_loatheb.h
deleted file mode 100644
index a2ab34642..000000000
--- a/src/server/scripts/Northrend/Naxxramas/boss_loatheb.h
+++ /dev/null
@@ -1,162 +0,0 @@
-#ifndef BOSS_LOATHEB_H_
-#define BOSS_LOATHEB_H_
-
-#include "ScriptMgr.h"
-#include "ScriptedCreature.h"
-#include "SpellInfo.h"
-#include "naxxramas.h"
-
-namespace Loatheb {
-
-enum Spells
-{
- SPELL_NECROTIC_AURA = 55593,
- SPELL_SUMMON_SPORE = 29234,
- SPELL_DEATHBLOOM = 29865,
- SPELL_INEVITABLE_DOOM = 29204,
- SPELL_BERSERK = 26662
-};
-
-enum Events
-{
- EVENT_NECROTIC_AURA = 1,
- EVENT_DEATHBLOOM = 2,
- EVENT_INEVITABLE_DOOM = 3,
- EVENT_BERSERK = 4,
- EVENT_SUMMON_SPORE = 5,
- EVENT_NECROTIC_AURA_FADING = 6,
- EVENT_NECROTIC_AURA_REMOVED = 7
-};
-
-enum Texts
-{
- SAY_NECROTIC_AURA_APPLIED = 0,
- SAY_NECROTIC_AURA_REMOVED = 1,
- SAY_NECROTIC_AURA_FADING = 2
-};
-
-class boss_loatheb : public CreatureScript
-{
-public:
- boss_loatheb() : CreatureScript("boss_loatheb") { }
-
- CreatureAI* GetAI(Creature* pCreature) const override
- {
- return GetNaxxramasAI(pCreature);
- }
-
- struct boss_loathebAI : public BossAI
- {
- explicit boss_loathebAI(Creature* c) : BossAI(c, BOSS_LOATHEB), summons(me)
- {
- me->SetHomePosition(me->GetPositionX(), me->GetPositionY(), me->GetPositionZ(), me->GetOrientation());
- }
-
- uint8 doomCounter;
- EventMap events;
- SummonList summons;
-
- void Reset() override
- {
- BossAI::Reset();
- events.Reset();
- summons.DespawnAll();
- doomCounter = 0;
- }
-
- void JustSummoned(Creature* cr) override
- {
- cr->SetInCombatWithZone();
- summons.Summon(cr);
- }
-
- void SummonedCreatureDies(Creature* /*cr*/, Unit*) override
- {
- instance->SetData(DATA_SPORE_KILLED, 0);
- }
-
- void KilledUnit(Unit* who) override
- {
- if (who->IsPlayer())
- instance->StorePersistentData(PERSISTENT_DATA_IMMORTAL_FAIL, 1);
- }
-
- void JustEngagedWith(Unit* who) override
- {
- BossAI::JustEngagedWith(who);
- me->SetInCombatWithZone();
- events.ScheduleEvent(EVENT_NECROTIC_AURA, 10s);
- events.ScheduleEvent(EVENT_DEATHBLOOM, 5s);
- events.ScheduleEvent(EVENT_INEVITABLE_DOOM, 2min);
- events.ScheduleEvent(EVENT_SUMMON_SPORE, 15s);
- events.ScheduleEvent(EVENT_BERSERK, 12min);
- }
-
- void JustDied(Unit* killer) override
- {
- BossAI::JustDied(killer);
- summons.DespawnAll();
- }
-
- void UpdateAI(uint32 diff) override
- {
- if (!UpdateVictim() || !IsInRoom())
- return;
-
- events.Update(diff);
- if (me->HasUnitState(UNIT_STATE_CASTING))
- return;
-
- switch (events.ExecuteEvent())
- {
- case EVENT_SUMMON_SPORE:
- me->CastSpell(me, SPELL_SUMMON_SPORE, true);
- events.Repeat(35s);
- break;
- case EVENT_NECROTIC_AURA:
- me->CastSpell(me, SPELL_NECROTIC_AURA, true);
- Talk(SAY_NECROTIC_AURA_APPLIED);
- events.ScheduleEvent(EVENT_NECROTIC_AURA_FADING, 14s);
- events.ScheduleEvent(EVENT_NECROTIC_AURA_REMOVED, 17s);
- events.Repeat(20s);
- break;
- case EVENT_DEATHBLOOM:
- me->CastSpell(me, SPELL_DEATHBLOOM, false);
- events.Repeat(30s);
- break;
- case EVENT_INEVITABLE_DOOM:
- me->CastSpell(me, SPELL_INEVITABLE_DOOM, false);
- doomCounter++;
- events.Repeat(doomCounter < 6 ? 30s : 15s);
- break;
- case EVENT_BERSERK:
- me->CastSpell(me, SPELL_BERSERK, true);
- break;
- case EVENT_NECROTIC_AURA_FADING:
- Talk(SAY_NECROTIC_AURA_FADING);
- break;
- case EVENT_NECROTIC_AURA_REMOVED:
- Talk(SAY_NECROTIC_AURA_REMOVED);
- break;
- }
- DoMeleeAttackIfReady();
- }
-
- bool IsInRoom()
- {
- // Calculate the distance between his home position to the gate
- if (me->GetExactDist(me->GetHomePosition().GetPositionX(),
- me->GetHomePosition().GetPositionY(),
- me->GetHomePosition().GetPositionZ()) > 50.0f)
- {
- EnterEvadeMode();
- return false;
- }
- return true;
- }
- };
-};
-
-}
-
-#endif
\ No newline at end of file
diff --git a/src/server/scripts/Northrend/Naxxramas/boss_maexxna.cpp b/src/server/scripts/Northrend/Naxxramas/boss_maexxna.cpp
index bf72579cd..ce6c18f11 100644
--- a/src/server/scripts/Northrend/Naxxramas/boss_maexxna.cpp
+++ b/src/server/scripts/Northrend/Naxxramas/boss_maexxna.cpp
@@ -15,7 +15,6 @@
* with this program. If not, see .
*/
-#include "boss_maexxna.h"
#include "CreatureScript.h"
#include "PassiveAI.h"
#include "Player.h"
@@ -25,11 +24,336 @@
#include "SpellScriptLoader.h"
#include "naxxramas.h"
+enum Spells
+{
+ SPELL_WEB_SPRAY = 29484,
+ SPELL_POISON_SHOCK = 28741,
+ SPELL_NECROTIC_POISON = 54121,
+ SPELL_FRENZY = 54123,
+ SPELL_WEB_WRAP_STUN = 28622,
+ SPELL_WEB_WRAP_SUMMON = 28627,
+ SPELL_WEB_WRAP_KILL_WEBS = 52512,
+ SPELL_WEB_WRAP_PACIFY_5 = 28618 // 5 seconds pacify silence
+};
-using namespace Maexxna;
+enum Events
+{
+ EVENT_WEB_SPRAY = 1,
+ EVENT_POISON_SHOCK = 2,
+ EVENT_NECROTIC_POISON = 3,
+ EVENT_WEB_WRAP = 4,
+ EVENT_HEALTH_CHECK = 5,
+ EVENT_SUMMON_SPIDERLINGS = 6,
+ EVENT_WEB_WRAP_APPLY_STUN = 7
+};
-// no custom changes has been made for mod-playerbot other then placing
-// the impl in a header file
+enum Emotes
+{
+ EMOTE_SPIDERS = 0,
+ EMOTE_WEB_WRAP = 1,
+ EMOTE_WEB_SPRAY = 2
+};
+
+enum Misc
+{
+ NPC_WEB_WRAP = 16486,
+ NPC_MAEXXNA_SPIDERLING = 17055
+};
+
+const Position PosWrap[7] =
+{
+ {3496.615f, -3834.182f, 320.7863f},
+ {3509.108f, -3833.922f, 320.4750f},
+ {3523.644f, -3838.309f, 320.5775f},
+ {3538.152f, -3846.353f, 320.5188f},
+ {3546.219f, -3856.167f, 320.9324f},
+ {3555.135f, -3869.507f, 320.8307f},
+ {3560.282f, -3886.143f, 321.2827f}
+};
+
+struct WebTargetSelector
+{
+ WebTargetSelector(Unit* maexxna) : _maexxna(maexxna) {}
+ bool operator()(Unit const* target) const
+ {
+ if (!target->IsPlayer()) // never web nonplayers (pets, guardians, etc.)
+ return false;
+ if (_maexxna->GetVictim() == target) // never target tank
+ return false;
+ if (target->HasAura(SPELL_WEB_WRAP_STUN)) // never target targets that are already webbed
+ return false;
+ return true;
+ }
+
+ private:
+ Unit const* _maexxna;
+};
+
+class boss_maexxna : public CreatureScript
+{
+public:
+ boss_maexxna() : CreatureScript("boss_maexxna") { }
+
+ CreatureAI* GetAI(Creature* pCreature) const override
+ {
+ return GetNaxxramasAI(pCreature);
+ }
+
+ struct boss_maexxnaAI : public BossAI
+ {
+ explicit boss_maexxnaAI(Creature* c) : BossAI(c, BOSS_MAEXXNA), summons(me)
+ {}
+
+ EventMap events;
+ SummonList summons;
+
+ GuidList wraps;
+
+ bool IsInRoom()
+ {
+ if (me->GetExactDist(3486.6f, -3890.6f, 291.8f) > 100.0f)
+ {
+ EnterEvadeMode();
+ return false;
+ }
+ return true;
+ }
+
+ void Reset() override
+ {
+ BossAI::Reset();
+ events.Reset();
+ summons.DespawnAll();
+ }
+
+ void JustEngagedWith(Unit* who) override
+ {
+ BossAI::JustEngagedWith(who);
+ me->SetInCombatWithZone();
+ events.ScheduleEvent(EVENT_WEB_WRAP, 20s);
+ events.ScheduleEvent(EVENT_WEB_SPRAY, 40s);
+ events.ScheduleEvent(EVENT_POISON_SHOCK, 10s);
+ events.ScheduleEvent(EVENT_NECROTIC_POISON, 5s);
+ events.ScheduleEvent(EVENT_HEALTH_CHECK, 1s);
+ events.ScheduleEvent(EVENT_SUMMON_SPIDERLINGS, 30s);
+ }
+
+ void JustSummoned(Creature* cr) override
+ {
+ if (cr->GetEntry() == NPC_MAEXXNA_SPIDERLING)
+ {
+ cr->SetInCombatWithZone();
+ if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0))
+ {
+ cr->AI()->AttackStart(target);
+ }
+ }
+ summons.Summon(cr);
+ }
+
+ void KilledUnit(Unit* who) override
+ {
+ if (who->IsPlayer())
+ instance->StorePersistentData(PERSISTENT_DATA_IMMORTAL_FAIL, 1);
+ }
+
+ void JustDied(Unit* killer) override
+ {
+ BossAI::JustDied(killer);
+ }
+
+ void DoCastWebWrap()
+ {
+ std::list candidates;
+ SelectTargetList(candidates, RAID_MODE(1, 2), SelectTargetMethod::Random, 0, WebTargetSelector(me));
+
+ std::vector positions {0, 1, 2, 3, 4, 5, 6};
+ Acore::Containers::RandomShuffle(positions);
+
+ if (candidates.empty())
+ return;
+
+ for (int i = 0; i < RAID_MODE(1, 2) ; i++)
+ {
+ if (candidates.empty())
+ break;
+ const Position &randomPos = PosWrap[positions[i]];
+
+ auto itr = candidates.begin();
+
+ if (candidates.size() > 1)
+ std::advance(itr, urand(0, candidates.size() - 1));
+
+ Unit *target = *itr;
+ candidates.erase(itr);
+
+ float dx = randomPos.GetPositionX() - target->GetPositionX();
+ float dy = randomPos.GetPositionY() - target->GetPositionY();
+ float distXY = std::hypotf(dx, dy);
+
+ // smooth knockback arc that avoids the ceiling
+ float horizontalSpeed = distXY / 1.5f;
+ float verticalSpeed = 28.0f;
+ if (distXY <= 10.0f)
+ verticalSpeed = 12.0f;
+ else if (distXY <= 20.0f)
+ verticalSpeed = 16.0f;
+ else if (distXY <= 30.0f)
+ verticalSpeed = 20.0f;
+ else if (distXY <= 40.0f)
+ verticalSpeed = 24.0f;
+
+ target->KnockbackFrom(randomPos.GetPositionX(), randomPos.GetPositionY(), -horizontalSpeed, verticalSpeed);
+ me->CastSpell(target, SPELL_WEB_WRAP_PACIFY_5, true); // pacify silence for 5 seconds
+
+ wraps.push_back(target->GetGUID());
+ }
+ events.ScheduleEvent(EVENT_WEB_WRAP_APPLY_STUN, 2s);
+ }
+
+ void UpdateAI(uint32 diff) override
+ {
+ if (!IsInRoom())
+ return;
+
+ if (!UpdateVictim())
+ return;
+
+ events.Update(diff);
+ if (me->HasUnitState(UNIT_STATE_CASTING))
+ return;
+
+ switch (events.ExecuteEvent())
+ {
+ case EVENT_WEB_SPRAY:
+ Talk(EMOTE_WEB_SPRAY);
+ me->CastSpell(me, SPELL_WEB_SPRAY, true);
+ events.Repeat(40s);
+ break;
+ case EVENT_POISON_SHOCK:
+ me->CastSpell(me->GetVictim(), SPELL_POISON_SHOCK, false);
+ events.Repeat(10s);
+ break;
+ case EVENT_NECROTIC_POISON:
+ me->CastSpell(me->GetVictim(), SPELL_NECROTIC_POISON, false);
+ events.Repeat(30s);
+ break;
+ case EVENT_SUMMON_SPIDERLINGS:
+ Talk(EMOTE_SPIDERS);
+ for (uint8 i = 0; i < 8; ++i)
+ {
+ me->SummonCreature(NPC_MAEXXNA_SPIDERLING, me->GetPositionX(), me->GetPositionY(), me->GetPositionZ(), me->GetOrientation());
+ }
+ events.Repeat(40s);
+ break;
+ case EVENT_HEALTH_CHECK:
+ if (me->GetHealthPct() < 30)
+ {
+ me->CastSpell(me, SPELL_FRENZY, true);
+ break;
+ }
+ events.Repeat(1s);
+ break;
+ case EVENT_WEB_WRAP:
+ Talk(EMOTE_WEB_WRAP);
+ DoCastWebWrap();
+ events.Repeat(40s);
+ break;
+ case EVENT_WEB_WRAP_APPLY_STUN:
+ {
+ for (auto& p : wraps)
+ {
+ if (Player* player = ObjectAccessor::GetPlayer(*me, p))
+ {
+ player->CastSpell(player, SPELL_WEB_WRAP_STUN, true);
+ }
+ }
+ wraps.clear();
+ break;
+ }
+ }
+ DoMeleeAttackIfReady();
+ }
+ };
+};
+
+class boss_maexxna_webwrap : public CreatureScript
+{
+public:
+ boss_maexxna_webwrap() : CreatureScript("boss_maexxna_webwrap") { }
+
+ CreatureAI* GetAI(Creature* pCreature) const override
+ {
+ return GetNaxxramasAI(pCreature);
+ }
+
+ struct boss_maexxna_webwrapAI : public NullCreatureAI
+ {
+ explicit boss_maexxna_webwrapAI(Creature* c) : NullCreatureAI(c) { }
+
+ ObjectGuid victimGUID;
+
+ void IsSummonedBy(WorldObject* summoner) override
+ {
+ if (!summoner)
+ return;
+ victimGUID = summoner->GetGUID();
+ }
+
+ void JustDied(Unit* /*killer*/) override
+ {
+ if (victimGUID)
+ {
+ if (Unit* victim = ObjectAccessor::GetUnit(*me, victimGUID))
+ {
+ if (victim->IsAlive())
+ {
+ victim->RemoveAurasDueToSpell(SPELL_WEB_WRAP_STUN);
+ victim->RemoveAurasDueToSpell(SPELL_WEB_WRAP_SUMMON);
+ }
+ }
+ }
+ }
+
+ void UpdateAI(uint32 /*diff*/) override
+ {
+ if (victimGUID)
+ {
+ if (Unit* victim = ObjectAccessor::GetUnit(*me, victimGUID))
+ {
+ if (!victim->IsAlive())
+ {
+ me->CastSpell(me, SPELL_WEB_WRAP_KILL_WEBS, true);
+ }
+ }
+ }
+ }
+ };
+};
+
+class spell_web_wrap_damage : public AuraScript
+{
+public:
+ PrepareAuraScript(spell_web_wrap_damage);
+
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ return ValidateSpellInfo({ SPELL_WEB_WRAP_SUMMON });
+ }
+
+ void OnPeriodic(AuraEffect const* aurEff)
+ {
+ if (aurEff->GetTickNumber() == 2)
+ {
+ GetTarget()->CastSpell(GetTarget(), SPELL_WEB_WRAP_SUMMON, true);
+ }
+ }
+
+ void Register() override
+ {
+ OnEffectPeriodic += AuraEffectPeriodicFn(spell_web_wrap_damage::OnPeriodic, EFFECT_1, SPELL_AURA_PERIODIC_DAMAGE);
+ }
+};
void AddSC_boss_maexxna()
{
diff --git a/src/server/scripts/Northrend/Naxxramas/boss_maexxna.h b/src/server/scripts/Northrend/Naxxramas/boss_maexxna.h
deleted file mode 100644
index 455f330e6..000000000
--- a/src/server/scripts/Northrend/Naxxramas/boss_maexxna.h
+++ /dev/null
@@ -1,348 +0,0 @@
-#ifndef BOSS_MAEXXNA_H_
-#define BOSS_MAEXXNA_H_
-
-#include "CreatureScript.h"
-#include "Player.h"
-#include "PassiveAI.h"
-#include "ScriptedCreature.h"
-#include "SpellAuraEffects.h"
-#include "SpellScript.h"
-#include "SpellScriptLoader.h"
-#include "SpellInfo.h"
-#include "naxxramas.h"
-
-namespace Maexxna {
-
-enum Spells
-{
- SPELL_WEB_SPRAY = 29484,
- SPELL_POISON_SHOCK = 28741,
- SPELL_NECROTIC_POISON = 54121,
- SPELL_FRENZY = 54123,
- SPELL_WEB_WRAP_STUN = 28622,
- SPELL_WEB_WRAP_SUMMON = 28627,
- SPELL_WEB_WRAP_KILL_WEBS = 52512,
- SPELL_WEB_WRAP_PACIFY_5 = 28618 // 5 seconds pacify silence
-};
-
-enum Events
-{
- EVENT_WEB_SPRAY = 1,
- EVENT_POISON_SHOCK = 2,
- EVENT_NECROTIC_POISON = 3,
- EVENT_WEB_WRAP = 4,
- EVENT_HEALTH_CHECK = 5,
- EVENT_SUMMON_SPIDERLINGS = 6,
- EVENT_WEB_WRAP_APPLY_STUN = 7
-};
-
-enum Emotes
-{
- EMOTE_SPIDERS = 0,
- EMOTE_WEB_WRAP = 1,
- EMOTE_WEB_SPRAY = 2
-};
-
-enum Misc
-{
- NPC_WEB_WRAP = 16486,
- NPC_MAEXXNA_SPIDERLING = 17055
-};
-
-const Position PosWrap[7] =
-{
- {3496.615f, -3834.182f, 320.7863f},
- {3509.108f, -3833.922f, 320.4750f},
- {3523.644f, -3838.309f, 320.5775f},
- {3538.152f, -3846.353f, 320.5188f},
- {3546.219f, -3856.167f, 320.9324f},
- {3555.135f, -3869.507f, 320.8307f},
- {3560.282f, -3886.143f, 321.2827f}
-};
-
-struct WebTargetSelector
-{
- WebTargetSelector(Unit* maexxna) : _maexxna(maexxna) {}
- bool operator()(Unit const* target) const
- {
- if (!target->IsPlayer()) // never web nonplayers (pets, guardians, etc.)
- return false;
- if (_maexxna->GetVictim() == target) // never target tank
- return false;
- if (target->HasAura(SPELL_WEB_WRAP_STUN)) // never target targets that are already webbed
- return false;
- return true;
- }
-
- private:
- Unit const* _maexxna;
-};
-
-class boss_maexxna : public CreatureScript
-{
-public:
- boss_maexxna() : CreatureScript("boss_maexxna") { }
-
- CreatureAI* GetAI(Creature* pCreature) const override
- {
- return GetNaxxramasAI(pCreature);
- }
-
- struct boss_maexxnaAI : public BossAI
- {
- explicit boss_maexxnaAI(Creature* c) : BossAI(c, BOSS_MAEXXNA), summons(me)
- {}
-
- EventMap events;
- SummonList summons;
-
- GuidList wraps;
-
- bool IsInRoom()
- {
- if (me->GetExactDist(3486.6f, -3890.6f, 291.8f) > 100.0f)
- {
- EnterEvadeMode();
- return false;
- }
- return true;
- }
-
- void Reset() override
- {
- BossAI::Reset();
- events.Reset();
- summons.DespawnAll();
- }
-
- void JustEngagedWith(Unit* who) override
- {
- BossAI::JustEngagedWith(who);
- me->SetInCombatWithZone();
- events.ScheduleEvent(EVENT_WEB_WRAP, 20s);
- events.ScheduleEvent(EVENT_WEB_SPRAY, 40s);
- events.ScheduleEvent(EVENT_POISON_SHOCK, 10s);
- events.ScheduleEvent(EVENT_NECROTIC_POISON, 5s);
- events.ScheduleEvent(EVENT_HEALTH_CHECK, 1s);
- events.ScheduleEvent(EVENT_SUMMON_SPIDERLINGS, 30s);
- }
-
- void JustSummoned(Creature* cr) override
- {
- if (cr->GetEntry() == NPC_MAEXXNA_SPIDERLING)
- {
- cr->SetInCombatWithZone();
- if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0))
- {
- cr->AI()->AttackStart(target);
- }
- }
- summons.Summon(cr);
- }
-
- void KilledUnit(Unit* who) override
- {
- if (who->IsPlayer())
- instance->StorePersistentData(PERSISTENT_DATA_IMMORTAL_FAIL, 1);
- }
-
- void JustDied(Unit* killer) override
- {
- BossAI::JustDied(killer);
- }
-
- void DoCastWebWrap()
- {
- std::list candidates;
- SelectTargetList(candidates, RAID_MODE(1, 2), SelectTargetMethod::Random, 0, WebTargetSelector(me));
-
- std::vector positions {0, 1, 2, 3, 4, 5, 6};
- Acore::Containers::RandomShuffle(positions);
-
- if (candidates.empty())
- return;
-
- for (int i = 0; i < RAID_MODE(1, 2) ; i++)
- {
- if (candidates.empty())
- break;
- const Position &randomPos = PosWrap[positions[i]];
-
- auto itr = candidates.begin();
-
- if (candidates.size() > 1)
- std::advance(itr, urand(0, candidates.size() - 1));
-
- Unit *target = *itr;
- candidates.erase(itr);
-
- float dx = randomPos.GetPositionX() - target->GetPositionX();
- float dy = randomPos.GetPositionY() - target->GetPositionY();
- float distXY = std::hypotf(dx, dy);
-
- // smooth knockback arc that avoids the ceiling
- float horizontalSpeed = distXY / 1.5f;
- float verticalSpeed = 28.0f;
- if (distXY <= 10.0f)
- verticalSpeed = 12.0f;
- else if (distXY <= 20.0f)
- verticalSpeed = 16.0f;
- else if (distXY <= 30.0f)
- verticalSpeed = 20.0f;
- else if (distXY <= 40.0f)
- verticalSpeed = 24.0f;
-
- target->KnockbackFrom(randomPos.GetPositionX(), randomPos.GetPositionY(), -horizontalSpeed, verticalSpeed);
- me->CastSpell(target, SPELL_WEB_WRAP_PACIFY_5, true); // pacify silence for 5 seconds
-
- wraps.push_back(target->GetGUID());
- }
- events.ScheduleEvent(EVENT_WEB_WRAP_APPLY_STUN, 2s);
- }
-
- void UpdateAI(uint32 diff) override
- {
- if (!IsInRoom())
- return;
-
- if (!UpdateVictim())
- return;
-
- events.Update(diff);
- if (me->HasUnitState(UNIT_STATE_CASTING))
- return;
-
- switch (events.ExecuteEvent())
- {
- case EVENT_WEB_SPRAY:
- Talk(EMOTE_WEB_SPRAY);
- me->CastSpell(me, SPELL_WEB_SPRAY, true);
- events.Repeat(40s);
- break;
- case EVENT_POISON_SHOCK:
- me->CastSpell(me->GetVictim(), SPELL_POISON_SHOCK, false);
- events.Repeat(10s);
- break;
- case EVENT_NECROTIC_POISON:
- me->CastSpell(me->GetVictim(), SPELL_NECROTIC_POISON, false);
- events.Repeat(30s);
- break;
- case EVENT_SUMMON_SPIDERLINGS:
- Talk(EMOTE_SPIDERS);
- for (uint8 i = 0; i < 8; ++i)
- {
- me->SummonCreature(NPC_MAEXXNA_SPIDERLING, me->GetPositionX(), me->GetPositionY(), me->GetPositionZ(), me->GetOrientation());
- }
- events.Repeat(40s);
- break;
- case EVENT_HEALTH_CHECK:
- if (me->GetHealthPct() < 30)
- {
- me->CastSpell(me, SPELL_FRENZY, true);
- break;
- }
- events.Repeat(1s);
- break;
- case EVENT_WEB_WRAP:
- Talk(EMOTE_WEB_WRAP);
- DoCastWebWrap();
- events.Repeat(40s);
- break;
- case EVENT_WEB_WRAP_APPLY_STUN:
- {
- for (auto& p : wraps)
- {
- if (Player* player = ObjectAccessor::GetPlayer(*me, p))
- {
- player->CastSpell(player, SPELL_WEB_WRAP_STUN, true);
- }
- }
- wraps.clear();
- break;
- }
- }
- DoMeleeAttackIfReady();
- }
- };
-};
-
-class boss_maexxna_webwrap : public CreatureScript
-{
-public:
- boss_maexxna_webwrap() : CreatureScript("boss_maexxna_webwrap") { }
-
- CreatureAI* GetAI(Creature* pCreature) const override
- {
- return GetNaxxramasAI(pCreature);
- }
-
- struct boss_maexxna_webwrapAI : public NullCreatureAI
- {
- explicit boss_maexxna_webwrapAI(Creature* c) : NullCreatureAI(c) { }
-
- ObjectGuid victimGUID;
-
- void IsSummonedBy(WorldObject* summoner) override
- {
- if (!summoner)
- return;
- victimGUID = summoner->GetGUID();
- }
-
- void JustDied(Unit* /*killer*/) override
- {
- if (victimGUID)
- {
- if (Unit* victim = ObjectAccessor::GetUnit(*me, victimGUID))
- {
- if (victim->IsAlive())
- {
- victim->RemoveAurasDueToSpell(SPELL_WEB_WRAP_STUN);
- victim->RemoveAurasDueToSpell(SPELL_WEB_WRAP_SUMMON);
- }
- }
- }
- }
-
- void UpdateAI(uint32 /*diff*/) override
- {
- if (victimGUID)
- {
- if (Unit* victim = ObjectAccessor::GetUnit(*me, victimGUID))
- {
- if (!victim->IsAlive())
- {
- me->CastSpell(me, SPELL_WEB_WRAP_KILL_WEBS, true);
- }
- }
- }
- }
- };
-};
-
-class spell_web_wrap_damage : public AuraScript
-{
-public:
- PrepareAuraScript(spell_web_wrap_damage);
-
- bool Validate(SpellInfo const* /*spellInfo*/) override
- {
- return ValidateSpellInfo({ SPELL_WEB_WRAP_SUMMON });
- }
-
- void OnPeriodic(AuraEffect const* aurEff)
- {
- if (aurEff->GetTickNumber() == 2)
- {
- GetTarget()->CastSpell(GetTarget(), SPELL_WEB_WRAP_SUMMON, true);
- }
- }
-
- void Register() override
- {
- OnEffectPeriodic += AuraEffectPeriodicFn(spell_web_wrap_damage::OnPeriodic, EFFECT_1, SPELL_AURA_PERIODIC_DAMAGE);
- }
-};
-
-} // namespace Maexxna
-#endif
\ No newline at end of file
diff --git a/src/server/scripts/Northrend/Naxxramas/boss_noth.cpp b/src/server/scripts/Northrend/Naxxramas/boss_noth.cpp
index 667f61d01..33d6ff391 100644
--- a/src/server/scripts/Northrend/Naxxramas/boss_noth.cpp
+++ b/src/server/scripts/Northrend/Naxxramas/boss_noth.cpp
@@ -15,16 +15,260 @@
* with this program. If not, see .
*/
-#include "boss_noth.h"
#include "CreatureScript.h"
#include "ScriptedCreature.h"
#include "naxxramas.h"
+enum Says
+{
+ SAY_AGGRO = 0,
+ SAY_SUMMON = 1,
+ SAY_SLAY = 2,
+ SAY_DEATH = 3,
+ EMOTE_SUMMON = 4,
+ EMOTE_SUMMON_WAVE = 5,
+ EMOTE_TELEPORT_BALCONY = 6,
+ EMOTE_TELEPORT_BACK = 7,
+ EMOTE_BLINK = 8
+};
-using namespace Noth;
+enum Spells
+{
+ SPELL_CURSE_OF_THE_PLAGUEBRINGER = 29213,
+ SPELL_CRIPPLE = 29212,
+ SPELL_SUMMON_PLAGUED_WARRIORS = 29237,
+ SPELL_TELEPORT = 29216,
+ SPELL_TELEPORT_BACK = 29231,
+ SPELL_BERSERK = 68378,
+ SPELL_BLINK = 29208
+};
-// no custom changes has been made for mod-playerbot other then placing
-// the impl in a header file
+enum Events
+{
+ EVENT_CURSE = 1,
+ EVENT_CRIPPLE = 2,
+ EVENT_SUMMON_PLAGUED_WARRIOR_ANNOUNCE = 3,
+ EVENT_MOVE_TO_BALCONY = 4,
+ EVENT_BLINK = 5,
+ EVENT_MOVE_TO_GROUND = 6,
+ EVENT_SUMMON_PLAGUED_WARRIOR_REAL = 7,
+ EVENT_BALCONY_SUMMON_ANNOUNCE = 8,
+ EVENT_BALCONY_SUMMON_REAL = 9
+};
+
+enum Misc
+{
+ NPC_PLAGUED_WARRIOR = 16984,
+ NPC_PLAGUED_CHAMPION = 16983,
+ NPC_PLAGUED_GUARDIAN = 16981
+};
+
+const Position summoningPosition[5] =
+{
+ {2728.06f, -3535.38f, 263.21f, 2.75f},
+ {2725.71f, -3514.80f, 263.23f, 2.86f},
+ {2728.24f, -3465.08f, 264.20f, 3.56f},
+ {2704.79f, -3459.17f, 263.74f, 4.25f},
+ {2652.02f, -3459.13f, 262.50f, 5.39f}
+};
+
+const Position nothPosition = {2684.94f, -3502.53f, 261.31f, 4.7f};
+
+class boss_noth : public CreatureScript
+{
+public:
+ boss_noth() : CreatureScript("boss_noth") { }
+
+ CreatureAI* GetAI(Creature* pCreature) const override
+ {
+ return GetNaxxramasAI(pCreature);
+ }
+
+ struct boss_nothAI : public BossAI
+ {
+ explicit boss_nothAI(Creature* c) : BossAI(c, BOSS_NOTH), summons(me)
+ {}
+
+ uint8 timesInBalcony;
+ EventMap events;
+ SummonList summons;
+
+ void StartGroundPhase()
+ {
+ me->SetReactState(REACT_AGGRESSIVE);
+ me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_DISABLE_MOVE);
+ me->SetControlled(false, UNIT_STATE_ROOT);
+ events.Reset();
+ events.ScheduleEvent(EVENT_MOVE_TO_BALCONY, 110s);
+ events.ScheduleEvent(EVENT_CURSE, 15s);
+ events.ScheduleEvent(EVENT_SUMMON_PLAGUED_WARRIOR_ANNOUNCE, 10s);
+ if (Is25ManRaid())
+ {
+ events.ScheduleEvent(EVENT_BLINK, 26s);
+ }
+ }
+
+ void StartBalconyPhase()
+ {
+ me->SetReactState(REACT_PASSIVE);
+ me->AttackStop();
+ me->SetUnitFlag(UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_DISABLE_MOVE);
+ me->SetControlled(true, UNIT_STATE_ROOT);
+ events.Reset();
+ events.ScheduleEvent(EVENT_BALCONY_SUMMON_ANNOUNCE, 4s);
+ events.ScheduleEvent(EVENT_MOVE_TO_GROUND, 70s);
+ }
+
+ void SummonHelper(uint32 entry, uint32 count)
+ {
+ for (uint8 i = 0; i < count; ++i)
+ {
+ me->SummonCreature(entry, summoningPosition[urand(0, 4)]);
+ }
+ }
+
+ bool IsInRoom()
+ {
+ if (me->GetExactDist(2684.8f, -3502.5f, 261.3f) > 80.0f)
+ {
+ EnterEvadeMode(EVADE_REASON_OTHER);
+ return false;
+ }
+ return true;
+ }
+
+ void Reset() override
+ {
+ BossAI::Reset();
+ events.Reset();
+ summons.DespawnAll();
+ me->CastSpell(me, SPELL_TELEPORT_BACK, true);
+ me->SetControlled(false, UNIT_STATE_ROOT);
+ me->SetReactState(REACT_AGGRESSIVE);
+ timesInBalcony = 0;
+ }
+
+ void EnterEvadeMode(EvadeReason why) override
+ {
+ me->SetControlled(false, UNIT_STATE_ROOT);
+ ScriptedAI::EnterEvadeMode(why);
+ }
+
+ void JustEngagedWith(Unit* who) override
+ {
+ BossAI::JustEngagedWith(who);
+ Talk(SAY_AGGRO);
+ StartGroundPhase();
+ }
+
+ void JustSummoned(Creature* summon) override
+ {
+ summons.Summon(summon);
+ summon->SetInCombatWithZone();
+ }
+
+ void JustDied(Unit* killer) override
+ {
+ if (me->GetPositionZ() > 270.27f)
+ {
+ me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_DISABLE_MOVE);
+ me->NearTeleportTo(nothPosition.GetPositionX(), nothPosition.GetPositionY(), nothPosition.GetPositionZ(), nothPosition.GetOrientation(), true);
+ }
+ BossAI::JustDied(killer);
+ Talk(SAY_DEATH);
+ }
+
+ void KilledUnit(Unit* who) override
+ {
+ if (!who->IsPlayer())
+ return;
+
+ Talk(SAY_SLAY);
+ instance->StorePersistentData(PERSISTENT_DATA_IMMORTAL_FAIL, 1);
+ }
+
+ void UpdateAI(uint32 diff) override
+ {
+ if (!IsInRoom())
+ return;
+
+ if (!UpdateVictim())
+ return;
+
+ events.Update(diff);
+ if (me->HasUnitState(UNIT_STATE_CASTING))
+ return;
+
+ switch (events.ExecuteEvent())
+ {
+ // GROUND
+ case EVENT_CURSE:
+ if (events.GetPhaseMask() == 0)
+ {
+ me->CastCustomSpell(SPELL_CURSE_OF_THE_PLAGUEBRINGER, SPELLVALUE_MAX_TARGETS, RAID_MODE(3, 10), me, false);
+ }
+ events.Repeat(25s);
+ break;
+ case EVENT_SUMMON_PLAGUED_WARRIOR_ANNOUNCE:
+ Talk(SAY_SUMMON);
+ Talk(EMOTE_SUMMON);
+ events.Repeat(30s);
+ events.ScheduleEvent(EVENT_SUMMON_PLAGUED_WARRIOR_REAL, 4s);
+ break;
+ case EVENT_SUMMON_PLAGUED_WARRIOR_REAL:
+ me->CastSpell(me, SPELL_SUMMON_PLAGUED_WARRIORS, true);
+ SummonHelper(NPC_PLAGUED_WARRIOR, RAID_MODE(2, 3));
+ break;
+ case EVENT_MOVE_TO_BALCONY:
+ Talk(EMOTE_TELEPORT_BALCONY);
+ me->CastSpell(me, SPELL_TELEPORT, true);
+ StartBalconyPhase();
+ break;
+ case EVENT_BLINK:
+ DoResetThreatList();
+ me->CastSpell(me, SPELL_CRIPPLE, false);
+ me->CastSpell(me, SPELL_BLINK, true);
+ Talk(EMOTE_BLINK);
+ events.Repeat(30s);
+ break;
+ // BALCONY
+ case EVENT_BALCONY_SUMMON_ANNOUNCE:
+ Talk(EMOTE_SUMMON_WAVE);
+ events.Repeat(30s);
+ events.ScheduleEvent(EVENT_BALCONY_SUMMON_REAL, 4s);
+ break;
+ case EVENT_BALCONY_SUMMON_REAL:
+ me->CastSpell(me, SPELL_SUMMON_PLAGUED_WARRIORS, true); // visual
+ switch (timesInBalcony)
+ {
+ case 0:
+ SummonHelper(NPC_PLAGUED_CHAMPION, RAID_MODE(2, 4));
+ break;
+ case 1:
+ SummonHelper(NPC_PLAGUED_CHAMPION, RAID_MODE(1, 2));
+ SummonHelper(NPC_PLAGUED_GUARDIAN, RAID_MODE(1, 2));
+ break;
+ default:
+ SummonHelper(NPC_PLAGUED_GUARDIAN, RAID_MODE(2, 4));
+ break;
+ }
+ break;
+ case EVENT_MOVE_TO_GROUND:
+ Talk(EMOTE_TELEPORT_BACK);
+ me->CastSpell(me, SPELL_TELEPORT_BACK, true);
+ timesInBalcony++;
+ if (timesInBalcony == 3)
+ {
+ DoCastSelf(SPELL_BERSERK);
+ }
+ StartGroundPhase();
+ break;
+ }
+ if (me->HasReactState(REACT_AGGRESSIVE))
+ DoMeleeAttackIfReady();
+ }
+ };
+};
void AddSC_boss_noth()
{
diff --git a/src/server/scripts/Northrend/Naxxramas/boss_noth.h b/src/server/scripts/Northrend/Naxxramas/boss_noth.h
deleted file mode 100644
index 3e88eec6c..000000000
--- a/src/server/scripts/Northrend/Naxxramas/boss_noth.h
+++ /dev/null
@@ -1,264 +0,0 @@
-#ifndef BOSS_NOTH_H_
-#define BOSS_NOTH_H_
-
-#include "ScriptMgr.h"
-#include "ScriptedCreature.h"
-#include "SpellInfo.h"
-#include "naxxramas.h"
-
-namespace Noth {
-
-enum Says
-{
- SAY_AGGRO = 0,
- SAY_SUMMON = 1,
- SAY_SLAY = 2,
- SAY_DEATH = 3,
- EMOTE_SUMMON = 4,
- EMOTE_SUMMON_WAVE = 5,
- EMOTE_TELEPORT_BALCONY = 6,
- EMOTE_TELEPORT_BACK = 7,
- EMOTE_BLINK = 8
-};
-
-enum Spells
-{
- SPELL_CURSE_OF_THE_PLAGUEBRINGER = 29213,
- SPELL_CRIPPLE = 29212,
- SPELL_SUMMON_PLAGUED_WARRIORS = 29237,
- SPELL_TELEPORT = 29216,
- SPELL_TELEPORT_BACK = 29231,
- SPELL_BERSERK = 68378,
- SPELL_BLINK = 29208
-};
-
-enum Events
-{
- EVENT_CURSE = 1,
- EVENT_CRIPPLE = 2,
- EVENT_SUMMON_PLAGUED_WARRIOR_ANNOUNCE = 3,
- EVENT_MOVE_TO_BALCONY = 4,
- EVENT_BLINK = 5,
- EVENT_MOVE_TO_GROUND = 6,
- EVENT_SUMMON_PLAGUED_WARRIOR_REAL = 7,
- EVENT_BALCONY_SUMMON_ANNOUNCE = 8,
- EVENT_BALCONY_SUMMON_REAL = 9
-};
-
-enum Misc
-{
- NPC_PLAGUED_WARRIOR = 16984,
- NPC_PLAGUED_CHAMPION = 16983,
- NPC_PLAGUED_GUARDIAN = 16981
-};
-
-const Position summoningPosition[5] =
-{
- {2728.06f, -3535.38f, 263.21f, 2.75f},
- {2725.71f, -3514.80f, 263.23f, 2.86f},
- {2728.24f, -3465.08f, 264.20f, 3.56f},
- {2704.79f, -3459.17f, 263.74f, 4.25f},
- {2652.02f, -3459.13f, 262.50f, 5.39f}
-};
-
-const Position nothPosition = {2684.94f, -3502.53f, 261.31f, 4.7f};
-
-class boss_noth : public CreatureScript
-{
-public:
- boss_noth() : CreatureScript("boss_noth") { }
-
- CreatureAI* GetAI(Creature* pCreature) const override
- {
- return GetNaxxramasAI(pCreature);
- }
-
- struct boss_nothAI : public BossAI
- {
- explicit boss_nothAI(Creature* c) : BossAI(c, BOSS_NOTH), summons(me)
- {}
-
- uint8 timesInBalcony;
- EventMap events;
- SummonList summons;
-
- void StartGroundPhase()
- {
- me->SetReactState(REACT_AGGRESSIVE);
- me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_DISABLE_MOVE);
- me->SetControlled(false, UNIT_STATE_ROOT);
- events.Reset();
- events.ScheduleEvent(EVENT_MOVE_TO_BALCONY, 110s);
- events.ScheduleEvent(EVENT_CURSE, 15s);
- events.ScheduleEvent(EVENT_SUMMON_PLAGUED_WARRIOR_ANNOUNCE, 10s);
- if (Is25ManRaid())
- {
- events.ScheduleEvent(EVENT_BLINK, 26s);
- }
- }
-
- void StartBalconyPhase()
- {
- me->SetReactState(REACT_PASSIVE);
- me->AttackStop();
- me->SetUnitFlag(UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_DISABLE_MOVE);
- me->SetControlled(true, UNIT_STATE_ROOT);
- events.Reset();
- events.ScheduleEvent(EVENT_BALCONY_SUMMON_ANNOUNCE, 4s);
- events.ScheduleEvent(EVENT_MOVE_TO_GROUND, 70s);
- }
-
- void SummonHelper(uint32 entry, uint32 count)
- {
- for (uint8 i = 0; i < count; ++i)
- {
- me->SummonCreature(entry, summoningPosition[urand(0, 4)]);
- }
- }
-
- bool IsInRoom()
- {
- if (me->GetExactDist(2684.8f, -3502.5f, 261.3f) > 80.0f)
- {
- EnterEvadeMode(EVADE_REASON_OTHER);
- return false;
- }
- return true;
- }
-
- void Reset() override
- {
- BossAI::Reset();
- events.Reset();
- summons.DespawnAll();
- me->CastSpell(me, SPELL_TELEPORT_BACK, true);
- me->SetControlled(false, UNIT_STATE_ROOT);
- me->SetReactState(REACT_AGGRESSIVE);
- timesInBalcony = 0;
- }
-
- void EnterEvadeMode(EvadeReason why) override
- {
- me->SetControlled(false, UNIT_STATE_ROOT);
- ScriptedAI::EnterEvadeMode(why);
- }
-
- void JustEngagedWith(Unit* who) override
- {
- BossAI::JustEngagedWith(who);
- Talk(SAY_AGGRO);
- StartGroundPhase();
- }
-
- void JustSummoned(Creature* summon) override
- {
- summons.Summon(summon);
- summon->SetInCombatWithZone();
- }
-
- void JustDied(Unit* killer) override
- {
- if (me->GetPositionZ() > 270.27f)
- {
- me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_DISABLE_MOVE);
- me->NearTeleportTo(nothPosition.GetPositionX(), nothPosition.GetPositionY(), nothPosition.GetPositionZ(), nothPosition.GetOrientation(), true);
- }
- BossAI::JustDied(killer);
- Talk(SAY_DEATH);
- }
-
- void KilledUnit(Unit* who) override
- {
- if (!who->IsPlayer())
- return;
-
- Talk(SAY_SLAY);
- instance->StorePersistentData(PERSISTENT_DATA_IMMORTAL_FAIL, 1);
- }
-
- void UpdateAI(uint32 diff) override
- {
- if (!IsInRoom())
- return;
-
- if (!UpdateVictim())
- return;
-
- events.Update(diff);
- if (me->HasUnitState(UNIT_STATE_CASTING))
- return;
-
- switch (events.ExecuteEvent())
- {
- // GROUND
- case EVENT_CURSE:
- if (events.GetPhaseMask() == 0)
- {
- me->CastCustomSpell(SPELL_CURSE_OF_THE_PLAGUEBRINGER, SPELLVALUE_MAX_TARGETS, RAID_MODE(3, 10), me, false);
- }
- events.Repeat(25s);
- break;
- case EVENT_SUMMON_PLAGUED_WARRIOR_ANNOUNCE:
- Talk(SAY_SUMMON);
- Talk(EMOTE_SUMMON);
- events.Repeat(30s);
- events.ScheduleEvent(EVENT_SUMMON_PLAGUED_WARRIOR_REAL, 4s);
- break;
- case EVENT_SUMMON_PLAGUED_WARRIOR_REAL:
- me->CastSpell(me, SPELL_SUMMON_PLAGUED_WARRIORS, true);
- SummonHelper(NPC_PLAGUED_WARRIOR, RAID_MODE(2, 3));
- break;
- case EVENT_MOVE_TO_BALCONY:
- Talk(EMOTE_TELEPORT_BALCONY);
- me->CastSpell(me, SPELL_TELEPORT, true);
- StartBalconyPhase();
- break;
- case EVENT_BLINK:
- DoResetThreatList();
- me->CastSpell(me, SPELL_CRIPPLE, false);
- me->CastSpell(me, SPELL_BLINK, true);
- Talk(EMOTE_BLINK);
- events.Repeat(30s);
- break;
- // BALCONY
- case EVENT_BALCONY_SUMMON_ANNOUNCE:
- Talk(EMOTE_SUMMON_WAVE);
- events.Repeat(30s);
- events.ScheduleEvent(EVENT_BALCONY_SUMMON_REAL, 4s);
- break;
- case EVENT_BALCONY_SUMMON_REAL:
- me->CastSpell(me, SPELL_SUMMON_PLAGUED_WARRIORS, true); // visual
- switch (timesInBalcony)
- {
- case 0:
- SummonHelper(NPC_PLAGUED_CHAMPION, RAID_MODE(2, 4));
- break;
- case 1:
- SummonHelper(NPC_PLAGUED_CHAMPION, RAID_MODE(1, 2));
- SummonHelper(NPC_PLAGUED_GUARDIAN, RAID_MODE(1, 2));
- break;
- default:
- SummonHelper(NPC_PLAGUED_GUARDIAN, RAID_MODE(2, 4));
- break;
- }
- break;
- case EVENT_MOVE_TO_GROUND:
- Talk(EMOTE_TELEPORT_BACK);
- me->CastSpell(me, SPELL_TELEPORT_BACK, true);
- timesInBalcony++;
- if (timesInBalcony == 3)
- {
- DoCastSelf(SPELL_BERSERK);
- }
- StartGroundPhase();
- break;
- }
- if (me->HasReactState(REACT_AGGRESSIVE))
- DoMeleeAttackIfReady();
- }
- };
-};
-
-}
-
-#endif
\ No newline at end of file
diff --git a/src/server/scripts/Northrend/Naxxramas/boss_patchwerk.cpp b/src/server/scripts/Northrend/Naxxramas/boss_patchwerk.cpp
index 56ae47e2c..319f08966 100644
--- a/src/server/scripts/Northrend/Naxxramas/boss_patchwerk.cpp
+++ b/src/server/scripts/Northrend/Naxxramas/boss_patchwerk.cpp
@@ -15,16 +15,173 @@
* with this program. If not, see .
*/
-#include "boss_patchwerk.h"
#include "CreatureScript.h"
#include "ScriptedCreature.h"
#include "naxxramas.h"
+enum Yells
+{
+ SAY_AGGRO = 0,
+ SAY_SLAY = 1,
+ SAY_DEATH = 2,
+ EMOTE_BERSERK = 3,
+ EMOTE_ENRAGE = 4
+};
-using namespace PatchWerk;
+enum Spells
+{
+ SPELL_HATEFUL_STRIKE = 41926,
+ SPELL_FRENZY = 28131,
+ SPELL_BERSERK = 26662,
+ SPELL_SLIME_BOLT = 32309
+};
-// no custom changes has been made for mod-playerbot other then placing
-// the impl in a header file
+enum Events
+{
+ EVENT_HEALTH_CHECK = 1,
+ EVENT_HATEFUL_STRIKE = 2,
+ EVENT_SLIME_BOLT = 3,
+ EVENT_BERSERK = 4
+};
+
+enum Misc
+{
+ ACHIEV_TIMED_START_EVENT = 10286
+};
+
+class boss_patchwerk : public CreatureScript
+{
+public:
+ boss_patchwerk() : CreatureScript("boss_patchwerk") { }
+
+ CreatureAI* GetAI(Creature* pCreature) const override
+ {
+ return GetNaxxramasAI(pCreature);
+ }
+
+ struct boss_patchwerkAI : public BossAI
+ {
+ explicit boss_patchwerkAI(Creature* c) : BossAI(c, BOSS_PATCHWERK)
+ {}
+
+ EventMap events;
+
+ void Reset() override
+ {
+ BossAI::Reset();
+ events.Reset();
+ }
+
+ void KilledUnit(Unit* who) override
+ {
+ if (!who->IsPlayer())
+ return;
+
+ if (!urand(0, 3))
+ Talk(SAY_SLAY);
+
+ instance->StorePersistentData(PERSISTENT_DATA_IMMORTAL_FAIL, 1);
+ }
+
+ void JustDied(Unit* killer) override
+ {
+ BossAI::JustDied(killer);
+ Talk(SAY_DEATH);
+ }
+
+ void JustEngagedWith(Unit* who) override
+ {
+ BossAI::JustEngagedWith(who);
+ Talk(SAY_AGGRO);
+ me->SetInCombatWithZone();
+ events.ScheduleEvent(EVENT_HATEFUL_STRIKE, 1500ms);
+ events.ScheduleEvent(EVENT_BERSERK, 6min);
+ events.ScheduleEvent(EVENT_HEALTH_CHECK, 1s);
+ instance->DoStartTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, ACHIEV_TIMED_START_EVENT);
+ }
+
+ void UpdateAI(uint32 diff) override
+ {
+ if (!UpdateVictim())
+ return;
+
+ events.Update(diff);
+ if (me->HasUnitState(UNIT_STATE_CASTING))
+ return;
+
+ switch (events.ExecuteEvent())
+ {
+ case EVENT_HATEFUL_STRIKE:
+ {
+ // Cast Hateful strike on the player with the highest amount of HP within melee distance, and second threat amount
+ std::list meleeRangeTargets;
+ Unit* finalTarget = nullptr;
+ uint8 counter = 0;
+ auto i = me->GetThreatMgr().GetThreatList().begin();
+ for (; i != me->GetThreatMgr().GetThreatList().end(); ++i, ++counter)
+ {
+ // Gather all units with melee range
+ Unit* target = (*i)->getTarget();
+ if (me->IsWithinMeleeRange(target))
+ {
+ meleeRangeTargets.push_back(target);
+ }
+ // and add threat to most hated
+ if (counter < RAID_MODE(2, 3))
+ {
+ me->AddThreat(target, 500.0f);
+ }
+ }
+ counter = 0;
+ std::list>::iterator itr;
+ for (itr = meleeRangeTargets.begin(); itr != meleeRangeTargets.end(); ++itr, ++counter)
+ {
+ // if there is only one target available
+ if (meleeRangeTargets.size() == 1)
+ {
+ finalTarget = (*itr);
+ }
+ else if (counter > 0) // skip first target
+ {
+ if (!finalTarget || (*itr)->GetHealth() > finalTarget->GetHealth())
+ {
+ finalTarget = (*itr);
+ }
+ // third loop
+ if (counter >= 2)
+ break;
+ }
+ }
+ if (finalTarget)
+ {
+ me->CastSpell(finalTarget, SPELL_HATEFUL_STRIKE, false);
+ }
+ events.Repeat(1s);
+ break;
+ }
+ case EVENT_BERSERK:
+ Talk(EMOTE_BERSERK);
+ me->CastSpell(me, SPELL_BERSERK, true);
+ events.ScheduleEvent(EVENT_SLIME_BOLT, 3s);
+ break;
+ case EVENT_SLIME_BOLT:
+ me->CastSpell(me, SPELL_SLIME_BOLT, false);
+ events.Repeat(3s);
+ break;
+ case EVENT_HEALTH_CHECK:
+ if (me->GetHealthPct() <= 5)
+ {
+ Talk(EMOTE_ENRAGE);
+ me->CastSpell(me, SPELL_FRENZY, true);
+ break;
+ }
+ events.Repeat(1s);
+ break;
+ }
+ DoMeleeAttackIfReady();
+ }
+ };
+};
void AddSC_boss_patchwerk()
{
diff --git a/src/server/scripts/Northrend/Naxxramas/boss_patchwerk.h b/src/server/scripts/Northrend/Naxxramas/boss_patchwerk.h
deleted file mode 100644
index d216e16a3..000000000
--- a/src/server/scripts/Northrend/Naxxramas/boss_patchwerk.h
+++ /dev/null
@@ -1,176 +0,0 @@
-#ifndef BOSS_PATCHWERK_H_
-#define BOSS_PATCHWERK_H_
-
-#include "ScriptMgr.h"
-#include "ScriptedCreature.h"
-#include "SpellInfo.h"
-#include "naxxramas.h"
-
-namespace PatchWerk {
-
-enum Yells
-{
- SAY_AGGRO = 0,
- SAY_SLAY = 1,
- SAY_DEATH = 2,
- EMOTE_BERSERK = 3,
- EMOTE_ENRAGE = 4
-};
-
-enum Spells
-{
- SPELL_HATEFUL_STRIKE = 41926,
- SPELL_FRENZY = 28131,
- SPELL_BERSERK = 26662,
- SPELL_SLIME_BOLT = 32309
-};
-
-enum Events
-{
- EVENT_HEALTH_CHECK = 1,
- EVENT_HATEFUL_STRIKE = 2,
- EVENT_SLIME_BOLT = 3,
- EVENT_BERSERK = 4
-};
-
-enum Misc
-{
- ACHIEV_TIMED_START_EVENT = 10286
-};
-
-class boss_patchwerk : public CreatureScript
-{
-public:
- boss_patchwerk() : CreatureScript("boss_patchwerk") { }
-
- CreatureAI* GetAI(Creature* pCreature) const override
- {
- return GetNaxxramasAI(pCreature);
- }
-
- struct boss_patchwerkAI : public BossAI
- {
- explicit boss_patchwerkAI(Creature* c) : BossAI(c, BOSS_PATCHWERK)
- {}
-
- EventMap events;
-
- void Reset() override
- {
- BossAI::Reset();
- events.Reset();
- }
-
- void KilledUnit(Unit* who) override
- {
- if (!who->IsPlayer())
- return;
-
- if (!urand(0, 3))
- Talk(SAY_SLAY);
-
- instance->StorePersistentData(PERSISTENT_DATA_IMMORTAL_FAIL, 1);
- }
-
- void JustDied(Unit* killer) override
- {
- BossAI::JustDied(killer);
- Talk(SAY_DEATH);
- }
-
- void JustEngagedWith(Unit* who) override
- {
- BossAI::JustEngagedWith(who);
- Talk(SAY_AGGRO);
- me->SetInCombatWithZone();
- events.ScheduleEvent(EVENT_HATEFUL_STRIKE, 1500ms);
- events.ScheduleEvent(EVENT_BERSERK, 6min);
- events.ScheduleEvent(EVENT_HEALTH_CHECK, 1s);
- instance->DoStartTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, ACHIEV_TIMED_START_EVENT);
- }
-
- void UpdateAI(uint32 diff) override
- {
- if (!UpdateVictim())
- return;
-
- events.Update(diff);
- if (me->HasUnitState(UNIT_STATE_CASTING))
- return;
-
- switch (events.ExecuteEvent())
- {
- case EVENT_HATEFUL_STRIKE:
- {
- // Cast Hateful strike on the player with the highest amount of HP within melee distance, and second threat amount
- std::list meleeRangeTargets;
- Unit* finalTarget = nullptr;
- uint8 counter = 0;
- auto i = me->GetThreatMgr().GetThreatList().begin();
- for (; i != me->GetThreatMgr().GetThreatList().end(); ++i, ++counter)
- {
- // Gather all units with melee range
- Unit* target = (*i)->getTarget();
- if (me->IsWithinMeleeRange(target))
- {
- meleeRangeTargets.push_back(target);
- }
- // and add threat to most hated
- if (counter < RAID_MODE(2, 3))
- {
- me->AddThreat(target, 500.0f);
- }
- }
- counter = 0;
- std::list>::iterator itr;
- for (itr = meleeRangeTargets.begin(); itr != meleeRangeTargets.end(); ++itr, ++counter)
- {
- // if there is only one target available
- if (meleeRangeTargets.size() == 1)
- {
- finalTarget = (*itr);
- }
- else if (counter > 0) // skip first target
- {
- if (!finalTarget || (*itr)->GetHealth() > finalTarget->GetHealth())
- {
- finalTarget = (*itr);
- }
- // third loop
- if (counter >= 2)
- break;
- }
- }
- if (finalTarget)
- {
- me->CastSpell(finalTarget, SPELL_HATEFUL_STRIKE, false);
- }
- events.Repeat(1s);
- break;
- }
- case EVENT_BERSERK:
- Talk(EMOTE_BERSERK);
- me->CastSpell(me, SPELL_BERSERK, true);
- events.ScheduleEvent(EVENT_SLIME_BOLT, 3s);
- break;
- case EVENT_SLIME_BOLT:
- me->CastSpell(me, SPELL_SLIME_BOLT, false);
- events.Repeat(3s);
- break;
- case EVENT_HEALTH_CHECK:
- if (me->GetHealthPct() <= 5)
- {
- Talk(EMOTE_ENRAGE);
- me->CastSpell(me, SPELL_FRENZY, true);
- break;
- }
- events.Repeat(1s);
- break;
- }
- DoMeleeAttackIfReady();
- }
- };
-};
-
-}
-#endif
\ No newline at end of file
diff --git a/src/server/scripts/Northrend/Naxxramas/boss_razuvious.cpp b/src/server/scripts/Northrend/Naxxramas/boss_razuvious.cpp
index 27d73c469..4aae788f5 100644
--- a/src/server/scripts/Northrend/Naxxramas/boss_razuvious.cpp
+++ b/src/server/scripts/Northrend/Naxxramas/boss_razuvious.cpp
@@ -15,17 +15,372 @@
* with this program. If not, see .
*/
-#include "boss_razuvious.h"
#include "CreatureScript.h"
#include "ScriptedCreature.h"
#include "naxxramas.h"
#include "SpellInfo.h"
+enum Says
+{
+ SAY_AGGRO = 0,
+ SAY_SLAY = 1,
+ SAY_TAUNTED = 2,
+ SAY_DEATH = 3,
+ SAY_PATHETIC = 4,
+ SAY_TARGET_DUMMY = 5,
+ SAY_DEATH_KNIGHT_UNDERSTUDY = 0,
+};
-using namespace Razuvious;
+enum Spells
+{
+ SPELL_UNBALANCING_STRIKE = 26613,
+ SPELL_DISRUPTING_SHOUT = 55543,
+ SPELL_JAGGED_KNIFE = 55550,
+ SPELL_HOPELESS = 29125,
+ SPELL_TAUNT = 29060
+};
-// no custom changes has been made for mod-playerbot other then placing
-// the impl in a header file
+enum Events
+{
+ EVENT_UNBALANCING_STRIKE = 1,
+ EVENT_DISRUPTING_SHOUT = 2,
+ EVENT_JAGGED_KNIFE = 3
+};
+
+enum NPCs
+{
+ NPC_DEATH_KNIGHT_UNDERSTUDY = 16803,
+ NPC_TARGET_DUMMY = 16211,
+};
+
+enum Actions
+{
+ ACTION_FACE_ME = 0,
+ ACTION_TALK = 1,
+ ACTION_EMOTE = 2,
+ ACTION_SALUTE = 3,
+ ACTION_BACK_TO_TRAINING = 4,
+};
+
+enum Misc
+{
+ GROUP_OOC_RP = 0,
+ POINT_DEATH_KNIGHT = 0,
+};
+
+class boss_razuvious : public CreatureScript
+{
+public:
+ boss_razuvious() : CreatureScript("boss_razuvious") { }
+
+ CreatureAI* GetAI(Creature* pCreature) const override
+ {
+ return GetNaxxramasAI(pCreature);
+ }
+
+ struct boss_razuviousAI : public BossAI
+ {
+ explicit boss_razuviousAI(Creature* c) : BossAI(c, BOSS_RAZUVIOUS), summons(me)
+ {}
+
+ EventMap events;
+ SummonList summons;
+
+ void SpawnHelpers()
+ {
+ me->SummonCreature(NPC_DEATH_KNIGHT_UNDERSTUDY, 2762.23f, -3085.07f, 267.685f, 1.95f);
+ me->SummonCreature(NPC_DEATH_KNIGHT_UNDERSTUDY, 2758.24f, -3110.97f, 267.685f, 3.94f);
+ if (Is25ManRaid())
+ {
+ me->SummonCreature(NPC_DEATH_KNIGHT_UNDERSTUDY, 2782.45f, -3088.03f, 267.685f, 0.75f);
+ me->SummonCreature(NPC_DEATH_KNIGHT_UNDERSTUDY, 2778.56f, -3113.74f, 267.685f, 5.28f);
+ }
+ }
+
+ void JustSummoned(Creature* cr) override
+ {
+ summons.Summon(cr);
+ }
+
+ void Reset() override
+ {
+ BossAI::Reset();
+ summons.DespawnAll();
+ events.Reset();
+ SpawnHelpers();
+ ScheduleRP();
+ }
+
+ void ScheduleInteractWithDeathKnight()
+ {
+ if (_rpBuddyGUID)
+ if (Creature* understudy = ObjectAccessor::GetCreature(*me, _rpBuddyGUID))
+ me->SetFacingToObject(understudy);
+
+ scheduler.Schedule(2s, GROUP_OOC_RP, [this](TaskContext /*context*/)
+ {
+ if (roll_chance_i(75))
+ {
+ bool longText = roll_chance_i(50);
+ Talk(longText ? SAY_TARGET_DUMMY : SAY_PATHETIC);
+ scheduler.Schedule(4s, GROUP_OOC_RP, [this](TaskContext /*context*/)
+ {
+ if (_rpBuddyGUID)
+ if (Creature* understudy = ObjectAccessor::GetCreature(*me, _rpBuddyGUID))
+ understudy->AI()->DoAction(ACTION_TALK);
+ });
+ if (longText)
+ scheduler.DelayGroup(GROUP_OOC_RP, 5s);
+ }
+ else
+ {
+ me->HandleEmoteCommand(EMOTE_ONESHOT_EXCLAMATION);
+ scheduler.Schedule(4s, GROUP_OOC_RP, [this](TaskContext /*context*/)
+ {
+ if (_rpBuddyGUID)
+ if (Creature* understudy = ObjectAccessor::GetCreature(*me, _rpBuddyGUID))
+ {
+ if (roll_chance_i(25))
+ understudy->AI()->DoAction(ACTION_EMOTE);
+ else
+ understudy->AI()->DoAction(ACTION_TALK);
+ }
+ });
+ }
+ }).Schedule(4s, GROUP_OOC_RP, [this](TaskContext /*context*/)
+ {
+ if (_rpBuddyGUID)
+ if (Creature* understudy = ObjectAccessor::GetCreature(*me, _rpBuddyGUID))
+ understudy->AI()->DoAction(ACTION_FACE_ME);
+ }).Schedule(10s, GROUP_OOC_RP, [this](TaskContext /*context*/)
+ {
+ if (_rpBuddyGUID)
+ if (Creature* understudy = ObjectAccessor::GetCreature(*me, _rpBuddyGUID))
+ understudy->AI()->DoAction(ACTION_SALUTE);
+ }).Schedule(13s, GROUP_OOC_RP, [this](TaskContext /*context*/)
+ {
+ me->ResumeMovement();
+ }).Schedule(16s, GROUP_OOC_RP, [this](TaskContext /*context*/)
+ {
+ if (_rpBuddyGUID)
+ if (Creature* understudy = ObjectAccessor::GetCreature(*me, _rpBuddyGUID))
+ understudy->AI()->DoAction(ACTION_BACK_TO_TRAINING);
+ ScheduleRP();
+ });
+ }
+
+ void MovementInform(uint32 type, uint32 id) override
+ {
+ if (type == POINT_MOTION_TYPE && id == POINT_DEATH_KNIGHT)
+ {
+ ScheduleInteractWithDeathKnight();
+ }
+ }
+
+ void ScheduleRP()
+ {
+ _rpBuddyGUID = Acore::Containers::SelectRandomContainerElement(summons);
+ scheduler.Schedule(60s, 80s, GROUP_OOC_RP, [this](TaskContext context)
+ {
+ if (_rpBuddyGUID)
+ {
+ if (Creature* understudy = ObjectAccessor::GetCreature(*me, _rpBuddyGUID))
+ {
+ if (me->GetDistance2d(understudy) <= 6.0f)
+ {
+ me->PauseMovement();
+ scheduler.Schedule(500ms, GROUP_OOC_RP, [this](TaskContext /*context*/)
+ {
+ if (_rpBuddyGUID)
+ if (Creature* understudy = ObjectAccessor::GetCreature(*me, _rpBuddyGUID))
+ me->GetMotionMaster()->MovePoint(POINT_DEATH_KNIGHT, understudy->GetNearPosition(3.2f, understudy->GetRelativeAngle(me)));
+ });
+ return;
+ }
+ }
+ }
+ context.Repeat(2s);
+ });
+ }
+
+ void KilledUnit(Unit* who) override
+ {
+ if (roll_chance_i(30))
+ Talk(SAY_SLAY);
+
+ if (who->IsPlayer())
+ instance->StorePersistentData(PERSISTENT_DATA_IMMORTAL_FAIL, 1);
+ }
+
+ void DamageTaken(Unit* who, uint32& damage, DamageEffectType, SpellSchoolMask) override
+ {
+ // Damage done by the controlled Death Knight understudies should also count toward damage done by players
+ if (who && who->IsCreature() && who->GetEntry() == NPC_DEATH_KNIGHT_UNDERSTUDY)
+ {
+ me->LowerPlayerDamageReq(damage);
+ }
+ }
+
+ void JustDied(Unit* killer) override
+ {
+ BossAI::JustDied(killer);
+ Talk(SAY_DEATH);
+ me->CastSpell(me, SPELL_HOPELESS, true);
+ }
+
+ void SpellHit(Unit* caster, SpellInfo const* spell) override
+ {
+ if (spell->Id == SPELL_TAUNT)
+ {
+ Talk(SAY_TAUNTED, caster);
+ }
+ }
+
+ void JustEngagedWith(Unit* who) override
+ {
+ BossAI::JustEngagedWith(who);
+ scheduler.CancelGroup(GROUP_OOC_RP);
+ Talk(SAY_AGGRO);
+ events.ScheduleEvent(EVENT_UNBALANCING_STRIKE, 20s);
+ events.ScheduleEvent(EVENT_DISRUPTING_SHOUT, 15s);
+ events.ScheduleEvent(EVENT_JAGGED_KNIFE, 10s);
+ summons.DoZoneInCombat();
+ }
+
+ void UpdateAI(uint32 diff) override
+ {
+ if (!me->IsInCombat())
+ scheduler.Update(diff);
+
+ if (!UpdateVictim())
+ return;
+
+ events.Update(diff);
+ if (me->HasUnitState(UNIT_STATE_CASTING))
+ return;
+
+ switch (events.ExecuteEvent())
+ {
+ case EVENT_UNBALANCING_STRIKE:
+ me->CastSpell(me->GetVictim(), SPELL_UNBALANCING_STRIKE, false);
+ events.Repeat(20s);
+ break;
+ case EVENT_DISRUPTING_SHOUT:
+ me->CastSpell(me, SPELL_DISRUPTING_SHOUT, false);
+ events.Repeat(15s);
+ break;
+ case EVENT_JAGGED_KNIFE:
+ if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 45.0f))
+ {
+ me->CastSpell(target, SPELL_JAGGED_KNIFE, false);
+ }
+ events.Repeat(10s);
+ break;
+ }
+ DoMeleeAttackIfReady();
+ }
+
+ private:
+ ObjectGuid _rpBuddyGUID;
+ };
+};
+
+class boss_razuvious_minion : public CreatureScript
+{
+public:
+ boss_razuvious_minion() : CreatureScript("boss_razuvious_minion") { }
+
+ CreatureAI* GetAI(Creature* creature) const override
+ {
+ return GetNaxxramasAI(creature);
+ }
+
+ struct boss_razuvious_minionAI : public ScriptedAI
+ {
+ explicit boss_razuvious_minionAI(Creature* creature) : ScriptedAI(creature) { }
+
+ void Reset() override
+ {
+ scheduler.CancelAll();
+ ScheduleAttackDummy();
+ }
+
+ void ScheduleAttackDummy()
+ {
+ me->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_STATE_READY1H);
+ if (Creature* targetDummy = me->FindNearestCreature(NPC_TARGET_DUMMY, 10.0f))
+ {
+ me->SetFacingToObject(targetDummy);
+ }
+ scheduler.Schedule(6s, 9s, GROUP_OOC_RP, [this](TaskContext context)
+ {
+ me->HandleEmoteCommand(EMOTE_ONESHOT_ATTACK1H);
+ context.Repeat(6s, 9s);
+ });
+ }
+
+ void DoAction(int32 action) override
+ {
+ switch (action)
+ {
+ case ACTION_FACE_ME:
+ {
+ scheduler.CancelGroup(GROUP_OOC_RP);
+ me->SetSheath(SHEATH_STATE_UNARMED);
+ me->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_STATE_NONE);
+
+ if (Creature* creature = me->GetInstanceScript()->GetCreature(DATA_RAZUVIOUS_BOSS))
+ me->SetFacingToObject(creature);
+
+ break;
+ }
+ case ACTION_TALK:
+ Talk(SAY_DEATH_KNIGHT_UNDERSTUDY);
+ break;
+ case ACTION_EMOTE:
+ me->HandleEmoteCommand(EMOTE_ONESHOT_TALK);
+ break;
+ case ACTION_SALUTE:
+ me->HandleEmoteCommand(EMOTE_ONESHOT_SALUTE);
+ break;
+ case ACTION_BACK_TO_TRAINING:
+ me->SetSheath(SHEATH_STATE_MELEE);
+ ScheduleAttackDummy();
+ break;
+ }
+ }
+
+ void KilledUnit(Unit* who) override
+ {
+ if (who->IsPlayer())
+ me->GetInstanceScript()->StorePersistentData(PERSISTENT_DATA_IMMORTAL_FAIL, 1);
+ }
+
+ void JustEngagedWith(Unit* who) override
+ {
+ scheduler.CancelGroup(GROUP_OOC_RP);
+
+ if (Creature* creature = me->GetInstanceScript()->GetCreature(DATA_RAZUVIOUS_BOSS))
+ {
+ creature->SetInCombatWithZone();
+ creature->AI()->AttackStart(who);
+ }
+ }
+
+ void UpdateAI(uint32 diff) override
+ {
+ scheduler.Update(diff);
+
+ if (UpdateVictim())
+ {
+ if (!me->HasUnitState(UNIT_STATE_CASTING) || !me->IsCharmed())
+ {
+ DoMeleeAttackIfReady();
+ }
+ }
+ }
+ };
+};
void AddSC_boss_razuvious()
{
diff --git a/src/server/scripts/Northrend/Naxxramas/boss_razuvious.h b/src/server/scripts/Northrend/Naxxramas/boss_razuvious.h
deleted file mode 100644
index 14966a0ac..000000000
--- a/src/server/scripts/Northrend/Naxxramas/boss_razuvious.h
+++ /dev/null
@@ -1,374 +0,0 @@
-#ifndef BOSS_RAZUVIOUS_H_
-#define BOSS_RAZUVIOUS_H_
-
-#include "ScriptMgr.h"
-#include "ScriptedCreature.h"
-#include "SpellInfo.h"
-#include "naxxramas.h"
-
-namespace Razuvious {
-
-enum Says
-{
- SAY_AGGRO = 0,
- SAY_SLAY = 1,
- SAY_TAUNTED = 2,
- SAY_DEATH = 3,
- SAY_PATHETIC = 4,
- SAY_TARGET_DUMMY = 5,
- SAY_DEATH_KNIGHT_UNDERSTUDY = 0,
-};
-
-enum Spells
-{
- SPELL_UNBALANCING_STRIKE = 26613,
- SPELL_DISRUPTING_SHOUT = 55543,
- SPELL_JAGGED_KNIFE = 55550,
- SPELL_HOPELESS = 29125,
- SPELL_TAUNT = 29060
-};
-
-enum Events
-{
- EVENT_UNBALANCING_STRIKE = 1,
- EVENT_DISRUPTING_SHOUT = 2,
- EVENT_JAGGED_KNIFE = 3
-};
-
-enum NPCs
-{
- NPC_DEATH_KNIGHT_UNDERSTUDY = 16803,
- NPC_TARGET_DUMMY = 16211,
-};
-
-enum Actions
-{
- ACTION_FACE_ME = 0,
- ACTION_TALK = 1,
- ACTION_EMOTE = 2,
- ACTION_SALUTE = 3,
- ACTION_BACK_TO_TRAINING = 4,
-};
-
-enum Misc
-{
- GROUP_OOC_RP = 0,
- POINT_DEATH_KNIGHT = 0,
-};
-
-class boss_razuvious : public CreatureScript
-{
-public:
- boss_razuvious() : CreatureScript("boss_razuvious") { }
-
- CreatureAI* GetAI(Creature* pCreature) const override
- {
- return GetNaxxramasAI(pCreature);
- }
-
- struct boss_razuviousAI : public BossAI
- {
- explicit boss_razuviousAI(Creature* c) : BossAI(c, BOSS_RAZUVIOUS), summons(me)
- {}
-
- EventMap events;
- SummonList summons;
-
- void SpawnHelpers()
- {
- me->SummonCreature(NPC_DEATH_KNIGHT_UNDERSTUDY, 2762.23f, -3085.07f, 267.685f, 1.95f);
- me->SummonCreature(NPC_DEATH_KNIGHT_UNDERSTUDY, 2758.24f, -3110.97f, 267.685f, 3.94f);
- if (Is25ManRaid())
- {
- me->SummonCreature(NPC_DEATH_KNIGHT_UNDERSTUDY, 2782.45f, -3088.03f, 267.685f, 0.75f);
- me->SummonCreature(NPC_DEATH_KNIGHT_UNDERSTUDY, 2778.56f, -3113.74f, 267.685f, 5.28f);
- }
- }
-
- void JustSummoned(Creature* cr) override
- {
- summons.Summon(cr);
- }
-
- void Reset() override
- {
- BossAI::Reset();
- summons.DespawnAll();
- events.Reset();
- SpawnHelpers();
- ScheduleRP();
- }
-
- void ScheduleInteractWithDeathKnight()
- {
- if (_rpBuddyGUID)
- if (Creature* understudy = ObjectAccessor::GetCreature(*me, _rpBuddyGUID))
- me->SetFacingToObject(understudy);
-
- scheduler.Schedule(2s, GROUP_OOC_RP, [this](TaskContext /*context*/)
- {
- if (roll_chance_i(75))
- {
- bool longText = roll_chance_i(50);
- Talk(longText ? SAY_TARGET_DUMMY : SAY_PATHETIC);
- scheduler.Schedule(4s, GROUP_OOC_RP, [this](TaskContext /*context*/)
- {
- if (_rpBuddyGUID)
- if (Creature* understudy = ObjectAccessor::GetCreature(*me, _rpBuddyGUID))
- understudy->AI()->DoAction(ACTION_TALK);
- });
- if (longText)
- scheduler.DelayGroup(GROUP_OOC_RP, 5s);
- }
- else
- {
- me->HandleEmoteCommand(EMOTE_ONESHOT_EXCLAMATION);
- scheduler.Schedule(4s, GROUP_OOC_RP, [this](TaskContext /*context*/)
- {
- if (_rpBuddyGUID)
- if (Creature* understudy = ObjectAccessor::GetCreature(*me, _rpBuddyGUID))
- {
- if (roll_chance_i(25))
- understudy->AI()->DoAction(ACTION_EMOTE);
- else
- understudy->AI()->DoAction(ACTION_TALK);
- }
- });
- }
- }).Schedule(4s, GROUP_OOC_RP, [this](TaskContext /*context*/)
- {
- if (_rpBuddyGUID)
- if (Creature* understudy = ObjectAccessor::GetCreature(*me, _rpBuddyGUID))
- understudy->AI()->DoAction(ACTION_FACE_ME);
- }).Schedule(10s, GROUP_OOC_RP, [this](TaskContext /*context*/)
- {
- if (_rpBuddyGUID)
- if (Creature* understudy = ObjectAccessor::GetCreature(*me, _rpBuddyGUID))
- understudy->AI()->DoAction(ACTION_SALUTE);
- }).Schedule(13s, GROUP_OOC_RP, [this](TaskContext /*context*/)
- {
- me->ResumeMovement();
- }).Schedule(16s, GROUP_OOC_RP, [this](TaskContext /*context*/)
- {
- if (_rpBuddyGUID)
- if (Creature* understudy = ObjectAccessor::GetCreature(*me, _rpBuddyGUID))
- understudy->AI()->DoAction(ACTION_BACK_TO_TRAINING);
- ScheduleRP();
- });
- }
-
- void MovementInform(uint32 type, uint32 id) override
- {
- if (type == POINT_MOTION_TYPE && id == POINT_DEATH_KNIGHT)
- {
- ScheduleInteractWithDeathKnight();
- }
- }
-
- void ScheduleRP()
- {
- _rpBuddyGUID = Acore::Containers::SelectRandomContainerElement(summons);
- scheduler.Schedule(60s, 80s, GROUP_OOC_RP, [this](TaskContext context)
- {
- if (_rpBuddyGUID)
- {
- if (Creature* understudy = ObjectAccessor::GetCreature(*me, _rpBuddyGUID))
- {
- if (me->GetDistance2d(understudy) <= 6.0f)
- {
- me->PauseMovement();
- scheduler.Schedule(500ms, GROUP_OOC_RP, [this](TaskContext /*context*/)
- {
- if (_rpBuddyGUID)
- if (Creature* understudy = ObjectAccessor::GetCreature(*me, _rpBuddyGUID))
- me->GetMotionMaster()->MovePoint(POINT_DEATH_KNIGHT, understudy->GetNearPosition(3.2f, understudy->GetRelativeAngle(me)));
- });
- return;
- }
- }
- }
- context.Repeat(2s);
- });
- }
-
- void KilledUnit(Unit* who) override
- {
- if (roll_chance_i(30))
- Talk(SAY_SLAY);
-
- if (who->IsPlayer())
- instance->StorePersistentData(PERSISTENT_DATA_IMMORTAL_FAIL, 1);
- }
-
- void DamageTaken(Unit* who, uint32& damage, DamageEffectType, SpellSchoolMask) override
- {
- // Damage done by the controlled Death Knight understudies should also count toward damage done by players
- if (who && who->IsCreature() && who->GetEntry() == NPC_DEATH_KNIGHT_UNDERSTUDY)
- {
- me->LowerPlayerDamageReq(damage);
- }
- }
-
- void JustDied(Unit* killer) override
- {
- BossAI::JustDied(killer);
- Talk(SAY_DEATH);
- me->CastSpell(me, SPELL_HOPELESS, true);
- }
-
- void SpellHit(Unit* caster, SpellInfo const* spell) override
- {
- if (spell->Id == SPELL_TAUNT)
- {
- Talk(SAY_TAUNTED, caster);
- }
- }
-
- void JustEngagedWith(Unit* who) override
- {
- BossAI::JustEngagedWith(who);
- scheduler.CancelGroup(GROUP_OOC_RP);
- Talk(SAY_AGGRO);
- events.ScheduleEvent(EVENT_UNBALANCING_STRIKE, 20s);
- events.ScheduleEvent(EVENT_DISRUPTING_SHOUT, 15s);
- events.ScheduleEvent(EVENT_JAGGED_KNIFE, 10s);
- summons.DoZoneInCombat();
- }
-
- void UpdateAI(uint32 diff) override
- {
- if (!me->IsInCombat())
- scheduler.Update(diff);
-
- if (!UpdateVictim())
- return;
-
- events.Update(diff);
- if (me->HasUnitState(UNIT_STATE_CASTING))
- return;
-
- switch (events.ExecuteEvent())
- {
- case EVENT_UNBALANCING_STRIKE:
- me->CastSpell(me->GetVictim(), SPELL_UNBALANCING_STRIKE, false);
- events.Repeat(20s);
- break;
- case EVENT_DISRUPTING_SHOUT:
- me->CastSpell(me, SPELL_DISRUPTING_SHOUT, false);
- events.Repeat(15s);
- break;
- case EVENT_JAGGED_KNIFE:
- if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 45.0f))
- {
- me->CastSpell(target, SPELL_JAGGED_KNIFE, false);
- }
- events.Repeat(10s);
- break;
- }
- DoMeleeAttackIfReady();
- }
-
- private:
- ObjectGuid _rpBuddyGUID;
- };
-};
-
-class boss_razuvious_minion : public CreatureScript
-{
-public:
- boss_razuvious_minion() : CreatureScript("boss_razuvious_minion") { }
-
- CreatureAI* GetAI(Creature* creature) const override
- {
- return GetNaxxramasAI(creature);
- }
-
- struct boss_razuvious_minionAI : public ScriptedAI
- {
- explicit boss_razuvious_minionAI(Creature* creature) : ScriptedAI(creature) { }
-
- void Reset() override
- {
- scheduler.CancelAll();
- ScheduleAttackDummy();
- }
-
- void ScheduleAttackDummy()
- {
- me->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_STATE_READY1H);
- if (Creature* targetDummy = me->FindNearestCreature(NPC_TARGET_DUMMY, 10.0f))
- {
- me->SetFacingToObject(targetDummy);
- }
- scheduler.Schedule(6s, 9s, GROUP_OOC_RP, [this](TaskContext context)
- {
- me->HandleEmoteCommand(EMOTE_ONESHOT_ATTACK1H);
- context.Repeat(6s, 9s);
- });
- }
-
- void DoAction(int32 action) override
- {
- switch (action)
- {
- case ACTION_FACE_ME:
- {
- scheduler.CancelGroup(GROUP_OOC_RP);
- me->SetSheath(SHEATH_STATE_UNARMED);
- me->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_STATE_NONE);
-
- if (Creature* creature = me->GetInstanceScript()->GetCreature(DATA_RAZUVIOUS_BOSS))
- me->SetFacingToObject(creature);
-
- break;
- }
- case ACTION_TALK:
- Talk(SAY_DEATH_KNIGHT_UNDERSTUDY);
- break;
- case ACTION_EMOTE:
- me->HandleEmoteCommand(EMOTE_ONESHOT_TALK);
- break;
- case ACTION_SALUTE:
- me->HandleEmoteCommand(EMOTE_ONESHOT_SALUTE);
- break;
- case ACTION_BACK_TO_TRAINING:
- me->SetSheath(SHEATH_STATE_MELEE);
- ScheduleAttackDummy();
- break;
- }
- }
-
- void KilledUnit(Unit* who) override
- {
- if (who->IsPlayer())
- me->GetInstanceScript()->StorePersistentData(PERSISTENT_DATA_IMMORTAL_FAIL, 1);
- }
-
- void JustEngagedWith(Unit* who) override
- {
- scheduler.CancelGroup(GROUP_OOC_RP);
-
- if (Creature* creature = me->GetInstanceScript()->GetCreature(DATA_RAZUVIOUS_BOSS))
- {
- creature->SetInCombatWithZone();
- creature->AI()->AttackStart(who);
- }
- }
-
- void UpdateAI(uint32 diff) override
- {
- scheduler.Update(diff);
-
- if (UpdateVictim())
- {
- if (!me->HasUnitState(UNIT_STATE_CASTING) || !me->IsCharmed())
- {
- DoMeleeAttackIfReady();
- }
- }
- }
- };
-};
-
-}
-#endif
\ No newline at end of file
diff --git a/src/server/scripts/Northrend/Naxxramas/boss_sapphiron.cpp b/src/server/scripts/Northrend/Naxxramas/boss_sapphiron.cpp
index 5e28fbd8f..50c51861e 100644
--- a/src/server/scripts/Northrend/Naxxramas/boss_sapphiron.cpp
+++ b/src/server/scripts/Northrend/Naxxramas/boss_sapphiron.cpp
@@ -15,7 +15,6 @@
* with this program. If not, see .
*/
-#include "boss_sapphiron.h"
#include "CreatureScript.h"
#include "Player.h"
#include "ScriptedCreature.h"
@@ -23,11 +22,423 @@
#include "SpellScriptLoader.h"
#include "naxxramas.h"
+enum Yells
+{
+ EMOTE_AIR_PHASE = 0,
+ EMOTE_GROUND_PHASE = 1,
+ EMOTE_BREATH = 2,
+ EMOTE_ENRAGE = 3
+};
-using namespace Sapphiron;
+enum Spells
+{
+ // Fight
+ SPELL_FROST_AURA = 28531,
+ SPELL_CLEAVE = 19983,
+ SPELL_TAIL_SWEEP = 55697,
+ SPELL_SUMMON_BLIZZARD = 28560,
+ SPELL_LIFE_DRAIN = 28542,
+ SPELL_BERSERK = 26662,
-// no custom changes has been made for mod-playerbot other then placing
-// the impl in a header file
+ // Ice block
+ SPELL_ICEBOLT_CAST = 28526,
+ SPELL_ICEBOLT_TRIGGER = 28522,
+ SPELL_FROST_MISSILE = 30101,
+ SPELL_FROST_EXPLOSION = 28524,
+
+ // Visuals
+ SPELL_SAPPHIRON_DIES = 29357
+};
+
+enum Misc
+{
+ GO_ICE_BLOCK = 181247,
+ NPC_BLIZZARD = 16474,
+
+ POINT_CENTER = 1
+};
+
+enum Events
+{
+ EVENT_BERSERK = 1,
+ EVENT_CLEAVE = 2,
+ EVENT_TAIL_SWEEP = 3,
+ EVENT_LIFE_DRAIN = 4,
+ EVENT_BLIZZARD = 5,
+ EVENT_FLIGHT_START = 6,
+ EVENT_FLIGHT_LIFTOFF = 7,
+ EVENT_FLIGHT_ICEBOLT = 8,
+ EVENT_FLIGHT_BREATH = 9,
+ EVENT_FLIGHT_SPELL_EXPLOSION = 10,
+ EVENT_FLIGHT_START_LAND = 11,
+ EVENT_LAND = 12,
+ EVENT_GROUND = 13,
+ EVENT_HUNDRED_CLUB = 14
+};
+
+class boss_sapphiron : public CreatureScript
+{
+public:
+ boss_sapphiron() : CreatureScript("boss_sapphiron") { }
+
+ CreatureAI* GetAI(Creature* pCreature) const override
+ {
+ return GetNaxxramasAI(pCreature);
+ }
+
+ struct boss_sapphironAI : public BossAI
+ {
+ explicit boss_sapphironAI(Creature* c) : BossAI(c, BOSS_SAPPHIRON)
+ {}
+
+ EventMap events;
+ uint8 iceboltCount{};
+ uint32 spawnTimer{};
+ GuidList blockList;
+ ObjectGuid currentTarget;
+
+ void InitializeAI() override
+ {
+ me->SummonGameObject(GO_SAPPHIRON_BIRTH, me->GetPositionX(), me->GetPositionY(), me->GetPositionZ(), 0, 0, 0, 0, 0, 0);
+ me->SetVisible(false);
+ me->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
+ me->SetReactState(REACT_PASSIVE);
+ ScriptedAI::InitializeAI();
+ }
+
+ bool IsInRoom()
+ {
+ if (me->GetExactDist(3523.5f, -5235.3f, 137.6f) > 100.0f)
+ {
+ EnterEvadeMode();
+ return false;
+ }
+ return true;
+ }
+
+ void Reset() override
+ {
+ BossAI::Reset();
+ if (me->IsVisible())
+ {
+ me->SetReactState(REACT_AGGRESSIVE);
+ }
+ events.Reset();
+ iceboltCount = 0;
+ spawnTimer = 0;
+ currentTarget.Clear();
+ blockList.clear();
+ }
+
+ void EnterCombatSelfFunction()
+ {
+ Map::PlayerList const& PlList = me->GetMap()->GetPlayers();
+ if (PlList.IsEmpty())
+ return;
+
+ for (auto const& i : PlList)
+ {
+ if (Player* player = i.GetSource())
+ {
+ if (player->IsGameMaster())
+ continue;
+
+ if (player->IsAlive() && me->GetDistance(player) < 80.0f)
+ {
+ me->SetInCombatWith(player);
+ player->SetInCombatWith(me);
+ me->AddThreat(player, 0.0f);
+ }
+ }
+ }
+ }
+
+ void JustEngagedWith(Unit* who) override
+ {
+ BossAI::JustEngagedWith(who);
+ EnterCombatSelfFunction();
+ me->CastSpell(me, SPELL_FROST_AURA, true);
+ events.ScheduleEvent(EVENT_BERSERK, 15min);
+ events.ScheduleEvent(EVENT_CLEAVE, 5s);
+ events.ScheduleEvent(EVENT_TAIL_SWEEP, 10s);
+ events.ScheduleEvent(EVENT_LIFE_DRAIN, 17s);
+ events.ScheduleEvent(EVENT_BLIZZARD, 17s);
+ events.ScheduleEvent(EVENT_FLIGHT_START, 45s);
+ events.ScheduleEvent(EVENT_HUNDRED_CLUB, 5s);
+ }
+
+ void JustDied(Unit* killer) override
+ {
+ BossAI::JustDied(killer);
+ me->CastSpell(me, SPELL_SAPPHIRON_DIES, true);
+ }
+
+ void DoAction(int32 param) override
+ {
+ if (param == ACTION_SAPPHIRON_BIRTH)
+ {
+ spawnTimer = 1;
+ }
+ }
+
+ void MovementInform(uint32 type, uint32 id) override
+ {
+ if (type == POINT_MOTION_TYPE && id == POINT_CENTER)
+ {
+ events.ScheduleEvent(EVENT_FLIGHT_LIFTOFF, 500ms);
+ }
+ }
+
+ void SpellHitTarget(Unit* target, SpellInfo const* spellInfo) override
+ {
+ if (spellInfo->Id == SPELL_ICEBOLT_CAST)
+ {
+ me->CastSpell(target, SPELL_ICEBOLT_TRIGGER, true);
+ }
+ }
+
+ bool IsValidExplosionTarget(WorldObject* target)
+ {
+ for (ObjectGuid const& guid : blockList)
+ {
+ if (target->GetGUID() == guid)
+ return false;
+
+ if (Unit* block = ObjectAccessor::GetUnit(*me, guid))
+ {
+ if (block->IsInBetween(me, target, 2.0f) && block->IsWithinDist(target, 10.0f))
+ return false;
+ }
+ }
+ return true;
+ }
+
+ void KilledUnit(Unit* who) override
+ {
+ if (who->IsPlayer())
+ instance->StorePersistentData(PERSISTENT_DATA_IMMORTAL_FAIL, 1);
+ }
+
+ void UpdateAI(uint32 diff) override
+ {
+ if (spawnTimer)
+ {
+ spawnTimer += diff;
+ if (spawnTimer >= 21500)
+ {
+ me->SetVisible(true);
+ me->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
+ me->SetReactState(REACT_AGGRESSIVE);
+ spawnTimer = 0;
+ }
+ return;
+ }
+
+ if (!IsInRoom())
+ return;
+
+ if (!UpdateVictim())
+ return;
+
+ events.Update(diff);
+ if (me->HasUnitState(UNIT_STATE_CASTING))
+ return;
+
+ switch (events.ExecuteEvent())
+ {
+ case EVENT_BERSERK:
+ Talk(EMOTE_ENRAGE);
+ me->CastSpell(me, SPELL_BERSERK, true);
+ return;
+ case EVENT_CLEAVE:
+ me->CastSpell(me->GetVictim(), SPELL_CLEAVE, false);
+ events.Repeat(10s);
+ return;
+ case EVENT_TAIL_SWEEP:
+ me->CastSpell(me, SPELL_TAIL_SWEEP, false);
+ events.Repeat(10s);
+ return;
+ case EVENT_LIFE_DRAIN:
+ me->CastCustomSpell(SPELL_LIFE_DRAIN, SPELLVALUE_MAX_TARGETS, RAID_MODE(2, 5), me, false);
+ events.Repeat(24s);
+ return;
+ case EVENT_BLIZZARD:
+ {
+ Creature* cr;
+ if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 40.0f, true))
+ {
+ cr = me->SummonCreature(NPC_BLIZZARD, *target, TEMPSUMMON_TIMED_DESPAWN, 16000);
+ }
+ else
+ {
+ cr = me->SummonCreature(NPC_BLIZZARD, *me, TEMPSUMMON_TIMED_DESPAWN, 16000);
+ }
+ if (cr)
+ {
+ cr->GetMotionMaster()->MoveRandom(40);
+ }
+ events.Repeat(RAID_MODE(8000ms, 6500ms));
+ return;
+ }
+ case EVENT_FLIGHT_START:
+ if (me->HealthBelowPct(11))
+ {
+ return;
+ }
+ events.Repeat(45s);
+ events.DelayEvents(35s);
+ me->SetReactState(REACT_PASSIVE);
+ me->AttackStop();
+ float x, y, z, o;
+ me->GetHomePosition(x, y, z, o);
+ me->GetMotionMaster()->MovePoint(POINT_CENTER, x, y, z);
+ return;
+ case EVENT_FLIGHT_LIFTOFF:
+ Talk(EMOTE_AIR_PHASE);
+ me->GetMotionMaster()->MoveIdle();
+ me->SendMeleeAttackStop(me->GetVictim());
+ me->HandleEmoteCommand(EMOTE_ONESHOT_LIFTOFF);
+ me->SetDisableGravity(true);
+ currentTarget.Clear();
+ events.ScheduleEvent(EVENT_FLIGHT_ICEBOLT, 3s);
+ iceboltCount = RAID_MODE(2, 3);
+ return;
+ case EVENT_FLIGHT_ICEBOLT:
+ {
+ if (currentTarget)
+ {
+ if (Unit* target = ObjectAccessor::GetUnit(*me, currentTarget))
+ {
+ me->SummonGameObject(GO_ICE_BLOCK, target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), target->GetOrientation(), 0.0f, 0.0f, 0.0f, 0.0f, 0);
+ }
+ }
+
+ std::vector targets;
+ auto i = me->GetThreatMgr().GetThreatList().begin();
+ for (; i != me->GetThreatMgr().GetThreatList().end(); ++i)
+ {
+ if ((*i)->getTarget()->IsPlayer())
+ {
+ bool inList = false;
+ if (!blockList.empty())
+ {
+ for (GuidList::const_iterator itr = blockList.begin(); itr != blockList.end(); ++itr)
+ {
+ if ((*i)->getTarget()->GetGUID() == *itr)
+ {
+ inList = true;
+ break;
+ }
+ }
+ }
+ if (!inList)
+ {
+ targets.push_back((*i)->getTarget());
+ }
+ }
+ }
+
+ if (!targets.empty() && iceboltCount)
+ {
+ auto itr = targets.begin();
+ advance(itr, urand(0, targets.size() - 1));
+ me->CastSpell(*itr, SPELL_ICEBOLT_CAST, false);
+ blockList.push_back((*itr)->GetGUID());
+ currentTarget = (*itr)->GetGUID();
+ --iceboltCount;
+ events.ScheduleEvent(EVENT_FLIGHT_ICEBOLT, Seconds(uint32(me->GetExactDist(*itr) / 13.0f)));
+ }
+ else
+ {
+ events.ScheduleEvent(EVENT_FLIGHT_BREATH, 1s);
+ }
+ return;
+ }
+ case EVENT_FLIGHT_BREATH:
+ currentTarget.Clear();
+ Talk(EMOTE_BREATH);
+ me->CastSpell(me, SPELL_FROST_MISSILE, false);
+ events.ScheduleEvent(EVENT_FLIGHT_SPELL_EXPLOSION, 8500ms);
+ return;
+ case EVENT_FLIGHT_SPELL_EXPLOSION:
+ me->CastSpell(me, SPELL_FROST_EXPLOSION, true);
+ events.ScheduleEvent(EVENT_FLIGHT_START_LAND, 3s);
+ return;
+ case EVENT_FLIGHT_START_LAND:
+ if (!blockList.empty())
+ {
+ for (GuidList::const_iterator itr = blockList.begin(); itr != blockList.end(); ++itr)
+ {
+ if (Unit* block = ObjectAccessor::GetUnit(*me, *itr))
+ {
+ block->RemoveAurasDueToSpell(SPELL_ICEBOLT_TRIGGER);
+ }
+ }
+ }
+ blockList.clear();
+ me->RemoveAllGameObjects();
+ events.ScheduleEvent(EVENT_LAND, 1s);
+ return;
+ case EVENT_LAND:
+ me->HandleEmoteCommand(EMOTE_ONESHOT_LAND);
+ me->SetDisableGravity(false);
+ events.ScheduleEvent(EVENT_GROUND, 1500ms);
+ return;
+ case EVENT_GROUND:
+ Talk(EMOTE_GROUND_PHASE);
+ me->SetReactState(REACT_AGGRESSIVE);
+ me->SetInCombatWithZone();
+ return;
+ case EVENT_HUNDRED_CLUB:
+ {
+ Map::PlayerList const& pList = me->GetMap()->GetPlayers();
+ for (auto const& itr : pList)
+ {
+ if (itr.GetSource()->GetResistance(SPELL_SCHOOL_FROST) > 100)
+ {
+ instance->SetData(DATA_HUNDRED_CLUB, 0);
+ return;
+ }
+ }
+ events.Repeat(5s);
+ return;
+ }
+ }
+ DoMeleeAttackIfReady();
+ }
+ };
+};
+
+class spell_sapphiron_frost_explosion : public SpellScript
+{
+ PrepareSpellScript(spell_sapphiron_frost_explosion);
+
+ void FilterTargets(std::list& targets)
+ {
+ Unit* caster = GetCaster();
+ if (!caster || !caster->ToCreature())
+ return;
+
+ std::list tmplist;
+ for (auto& target : targets)
+ {
+ if (CAST_AI(boss_sapphiron::boss_sapphironAI, caster->ToCreature()->AI())->IsValidExplosionTarget(target))
+ {
+ tmplist.push_back(target);
+ }
+ }
+ targets.clear();
+ for (auto& itr : tmplist)
+ {
+ targets.push_back(itr);
+ }
+ }
+
+ void Register() override
+ {
+ OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_sapphiron_frost_explosion::FilterTargets, EFFECT_0, TARGET_UNIT_DEST_AREA_ENEMY);
+ }
+};
void AddSC_boss_sapphiron()
{
diff --git a/src/server/scripts/Northrend/Naxxramas/boss_sapphiron.h b/src/server/scripts/Northrend/Naxxramas/boss_sapphiron.h
deleted file mode 100644
index c26180087..000000000
--- a/src/server/scripts/Northrend/Naxxramas/boss_sapphiron.h
+++ /dev/null
@@ -1,433 +0,0 @@
-#ifndef BOSS_SAPPHIRON_H_
-#define BOSS_SAPPHIRON_H_
-
-#include "Player.h"
-#include "ScriptMgr.h"
-#include "ScriptedCreature.h"
-#include "SpellScript.h"
-#include "SpellInfo.h"
-#include "naxxramas.h"
-
-namespace Sapphiron {
-
-enum Yells
-{
- EMOTE_AIR_PHASE = 0,
- EMOTE_GROUND_PHASE = 1,
- EMOTE_BREATH = 2,
- EMOTE_ENRAGE = 3
-};
-
-enum Spells
-{
- // Fight
- SPELL_FROST_AURA = 28531,
- SPELL_CLEAVE = 19983,
- SPELL_TAIL_SWEEP = 55697,
- SPELL_SUMMON_BLIZZARD = 28560,
- SPELL_LIFE_DRAIN = 28542,
- SPELL_BERSERK = 26662,
-
- // Ice block
- SPELL_ICEBOLT_CAST = 28526,
- SPELL_ICEBOLT_TRIGGER = 28522,
- SPELL_FROST_MISSILE = 30101,
- SPELL_FROST_EXPLOSION = 28524,
-
- // Visuals
- SPELL_SAPPHIRON_DIES = 29357
-};
-
-enum Misc
-{
- GO_ICE_BLOCK = 181247,
- NPC_BLIZZARD = 16474,
-
- POINT_CENTER = 1
-};
-
-enum Events
-{
- EVENT_BERSERK = 1,
- EVENT_CLEAVE = 2,
- EVENT_TAIL_SWEEP = 3,
- EVENT_LIFE_DRAIN = 4,
- EVENT_BLIZZARD = 5,
- EVENT_FLIGHT_START = 6,
- EVENT_FLIGHT_LIFTOFF = 7,
- EVENT_FLIGHT_ICEBOLT = 8,
- EVENT_FLIGHT_BREATH = 9,
- EVENT_FLIGHT_SPELL_EXPLOSION = 10,
- EVENT_FLIGHT_START_LAND = 11,
- EVENT_LAND = 12,
- EVENT_GROUND = 13,
- EVENT_HUNDRED_CLUB = 14
-};
-
-class boss_sapphiron : public CreatureScript
-{
-public:
- boss_sapphiron() : CreatureScript("boss_sapphiron") { }
-
- CreatureAI* GetAI(Creature* pCreature) const override
- {
- return GetNaxxramasAI(pCreature);
- }
-
- struct boss_sapphironAI : public BossAI
- {
- explicit boss_sapphironAI(Creature* c) : BossAI(c, BOSS_SAPPHIRON)
- {}
-
- EventMap events;
- uint8 iceboltCount{};
- uint32 spawnTimer{};
- GuidList blockList;
- ObjectGuid currentTarget;
-
- void InitializeAI() override
- {
- me->SummonGameObject(GO_SAPPHIRON_BIRTH, me->GetPositionX(), me->GetPositionY(), me->GetPositionZ(), 0, 0, 0, 0, 0, 0);
- me->SetVisible(false);
- me->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
- me->SetReactState(REACT_PASSIVE);
- ScriptedAI::InitializeAI();
- }
-
- bool IsInRoom()
- {
- if (me->GetExactDist(3523.5f, -5235.3f, 137.6f) > 100.0f)
- {
- EnterEvadeMode();
- return false;
- }
- return true;
- }
-
- void Reset() override
- {
- BossAI::Reset();
- if (me->IsVisible())
- {
- me->SetReactState(REACT_AGGRESSIVE);
- }
- events.Reset();
- iceboltCount = 0;
- spawnTimer = 0;
- currentTarget.Clear();
- blockList.clear();
- }
-
- void EnterCombatSelfFunction()
- {
- Map::PlayerList const& PlList = me->GetMap()->GetPlayers();
- if (PlList.IsEmpty())
- return;
-
- for (auto const& i : PlList)
- {
- if (Player* player = i.GetSource())
- {
- if (player->IsGameMaster())
- continue;
-
- if (player->IsAlive() && me->GetDistance(player) < 80.0f)
- {
- me->SetInCombatWith(player);
- player->SetInCombatWith(me);
- me->AddThreat(player, 0.0f);
- }
- }
- }
- }
-
- void JustEngagedWith(Unit* who) override
- {
- BossAI::JustEngagedWith(who);
- EnterCombatSelfFunction();
- me->CastSpell(me, SPELL_FROST_AURA, true);
- events.ScheduleEvent(EVENT_BERSERK, 15min);
- events.ScheduleEvent(EVENT_CLEAVE, 5s);
- events.ScheduleEvent(EVENT_TAIL_SWEEP, 10s);
- events.ScheduleEvent(EVENT_LIFE_DRAIN, 17s);
- events.ScheduleEvent(EVENT_BLIZZARD, 17s);
- events.ScheduleEvent(EVENT_FLIGHT_START, 45s);
- events.ScheduleEvent(EVENT_HUNDRED_CLUB, 5s);
- }
-
- void JustDied(Unit* killer) override
- {
- BossAI::JustDied(killer);
- me->CastSpell(me, SPELL_SAPPHIRON_DIES, true);
- }
-
- void DoAction(int32 param) override
- {
- if (param == ACTION_SAPPHIRON_BIRTH)
- {
- spawnTimer = 1;
- }
- }
-
- void MovementInform(uint32 type, uint32 id) override
- {
- if (type == POINT_MOTION_TYPE && id == POINT_CENTER)
- {
- events.ScheduleEvent(EVENT_FLIGHT_LIFTOFF, 500ms);
- }
- }
-
- void SpellHitTarget(Unit* target, SpellInfo const* spellInfo) override
- {
- if (spellInfo->Id == SPELL_ICEBOLT_CAST)
- {
- me->CastSpell(target, SPELL_ICEBOLT_TRIGGER, true);
- }
- }
-
- bool IsValidExplosionTarget(WorldObject* target)
- {
- for (ObjectGuid const& guid : blockList)
- {
- if (target->GetGUID() == guid)
- return false;
-
- if (Unit* block = ObjectAccessor::GetUnit(*me, guid))
- {
- if (block->IsInBetween(me, target, 2.0f) && block->IsWithinDist(target, 10.0f))
- return false;
- }
- }
- return true;
- }
-
- void KilledUnit(Unit* who) override
- {
- if (who->IsPlayer())
- instance->StorePersistentData(PERSISTENT_DATA_IMMORTAL_FAIL, 1);
- }
-
- void UpdateAI(uint32 diff) override
- {
- if (spawnTimer)
- {
- spawnTimer += diff;
- if (spawnTimer >= 21500)
- {
- me->SetVisible(true);
- me->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
- me->SetReactState(REACT_AGGRESSIVE);
- spawnTimer = 0;
- }
- return;
- }
-
- if (!IsInRoom())
- return;
-
- if (!UpdateVictim())
- return;
-
- events.Update(diff);
- if (me->HasUnitState(UNIT_STATE_CASTING))
- return;
-
- switch (events.ExecuteEvent())
- {
- case EVENT_BERSERK:
- Talk(EMOTE_ENRAGE);
- me->CastSpell(me, SPELL_BERSERK, true);
- return;
- case EVENT_CLEAVE:
- me->CastSpell(me->GetVictim(), SPELL_CLEAVE, false);
- events.Repeat(10s);
- return;
- case EVENT_TAIL_SWEEP:
- me->CastSpell(me, SPELL_TAIL_SWEEP, false);
- events.Repeat(10s);
- return;
- case EVENT_LIFE_DRAIN:
- me->CastCustomSpell(SPELL_LIFE_DRAIN, SPELLVALUE_MAX_TARGETS, RAID_MODE(2, 5), me, false);
- events.Repeat(24s);
- return;
- case EVENT_BLIZZARD:
- {
- Creature* cr;
- if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 40.0f, true))
- {
- cr = me->SummonCreature(NPC_BLIZZARD, *target, TEMPSUMMON_TIMED_DESPAWN, 16000);
- }
- else
- {
- cr = me->SummonCreature(NPC_BLIZZARD, *me, TEMPSUMMON_TIMED_DESPAWN, 16000);
- }
- if (cr)
- {
- cr->GetMotionMaster()->MoveRandom(40);
- }
- events.Repeat(RAID_MODE(8000ms, 6500ms));
- return;
- }
- case EVENT_FLIGHT_START:
- if (me->HealthBelowPct(11))
- {
- return;
- }
- events.Repeat(45s);
- events.DelayEvents(35s);
- me->SetReactState(REACT_PASSIVE);
- me->AttackStop();
- float x, y, z, o;
- me->GetHomePosition(x, y, z, o);
- me->GetMotionMaster()->MovePoint(POINT_CENTER, x, y, z);
- return;
- case EVENT_FLIGHT_LIFTOFF:
- Talk(EMOTE_AIR_PHASE);
- me->GetMotionMaster()->MoveIdle();
- me->SendMeleeAttackStop(me->GetVictim());
- me->HandleEmoteCommand(EMOTE_ONESHOT_LIFTOFF);
- me->SetDisableGravity(true);
- currentTarget.Clear();
- events.ScheduleEvent(EVENT_FLIGHT_ICEBOLT, 3s);
- iceboltCount = RAID_MODE(2, 3);
- return;
- case EVENT_FLIGHT_ICEBOLT:
- {
- if (currentTarget)
- {
- if (Unit* target = ObjectAccessor::GetUnit(*me, currentTarget))
- {
- me->SummonGameObject(GO_ICE_BLOCK, target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), target->GetOrientation(), 0.0f, 0.0f, 0.0f, 0.0f, 0);
- }
- }
-
- std::vector targets;
- auto i = me->GetThreatMgr().GetThreatList().begin();
- for (; i != me->GetThreatMgr().GetThreatList().end(); ++i)
- {
- if ((*i)->getTarget()->IsPlayer())
- {
- bool inList = false;
- if (!blockList.empty())
- {
- for (GuidList::const_iterator itr = blockList.begin(); itr != blockList.end(); ++itr)
- {
- if ((*i)->getTarget()->GetGUID() == *itr)
- {
- inList = true;
- break;
- }
- }
- }
- if (!inList)
- {
- targets.push_back((*i)->getTarget());
- }
- }
- }
-
- if (!targets.empty() && iceboltCount)
- {
- auto itr = targets.begin();
- advance(itr, urand(0, targets.size() - 1));
- me->CastSpell(*itr, SPELL_ICEBOLT_CAST, false);
- blockList.push_back((*itr)->GetGUID());
- currentTarget = (*itr)->GetGUID();
- --iceboltCount;
- events.ScheduleEvent(EVENT_FLIGHT_ICEBOLT, Seconds(uint32(me->GetExactDist(*itr) / 13.0f)));
- }
- else
- {
- events.ScheduleEvent(EVENT_FLIGHT_BREATH, 1s);
- }
- return;
- }
- case EVENT_FLIGHT_BREATH:
- currentTarget.Clear();
- Talk(EMOTE_BREATH);
- me->CastSpell(me, SPELL_FROST_MISSILE, false);
- events.ScheduleEvent(EVENT_FLIGHT_SPELL_EXPLOSION, 8500ms);
- return;
- case EVENT_FLIGHT_SPELL_EXPLOSION:
- me->CastSpell(me, SPELL_FROST_EXPLOSION, true);
- events.ScheduleEvent(EVENT_FLIGHT_START_LAND, 3s);
- return;
- case EVENT_FLIGHT_START_LAND:
- if (!blockList.empty())
- {
- for (GuidList::const_iterator itr = blockList.begin(); itr != blockList.end(); ++itr)
- {
- if (Unit* block = ObjectAccessor::GetUnit(*me, *itr))
- {
- block->RemoveAurasDueToSpell(SPELL_ICEBOLT_TRIGGER);
- }
- }
- }
- blockList.clear();
- me->RemoveAllGameObjects();
- events.ScheduleEvent(EVENT_LAND, 1s);
- return;
- case EVENT_LAND:
- me->HandleEmoteCommand(EMOTE_ONESHOT_LAND);
- me->SetDisableGravity(false);
- events.ScheduleEvent(EVENT_GROUND, 1500ms);
- return;
- case EVENT_GROUND:
- Talk(EMOTE_GROUND_PHASE);
- me->SetReactState(REACT_AGGRESSIVE);
- me->SetInCombatWithZone();
- return;
- case EVENT_HUNDRED_CLUB:
- {
- Map::PlayerList const& pList = me->GetMap()->GetPlayers();
- for (auto const& itr : pList)
- {
- if (itr.GetSource()->GetResistance(SPELL_SCHOOL_FROST) > 100)
- {
- instance->SetData(DATA_HUNDRED_CLUB, 0);
- return;
- }
- }
- events.Repeat(5s);
- return;
- }
- }
- DoMeleeAttackIfReady();
- }
- };
-};
-
-class spell_sapphiron_frost_explosion : public SpellScript
-{
- PrepareSpellScript(spell_sapphiron_frost_explosion);
-
- void FilterTargets(std::list& targets)
- {
- Unit* caster = GetCaster();
- if (!caster || !caster->ToCreature())
- return;
-
- std::list tmplist;
- for (auto& target : targets)
- {
- if (CAST_AI(boss_sapphiron::boss_sapphironAI, caster->ToCreature()->AI())->IsValidExplosionTarget(target))
- {
- tmplist.push_back(target);
- }
- }
- targets.clear();
- for (auto& itr : tmplist)
- {
- targets.push_back(itr);
- }
- }
-
- void Register() override
- {
- OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_sapphiron_frost_explosion::FilterTargets, EFFECT_0, TARGET_UNIT_DEST_AREA_ENEMY);
- }
-};
-
-}
-
-#endif
\ No newline at end of file
diff --git a/src/server/scripts/Northrend/Naxxramas/boss_thaddius.h b/src/server/scripts/Northrend/Naxxramas/boss_thaddius.h
deleted file mode 100644
index 0acf9e171..000000000
--- a/src/server/scripts/Northrend/Naxxramas/boss_thaddius.h
+++ /dev/null
@@ -1,690 +0,0 @@
-#ifndef BOSS_THADDIUS_H_
-#define BOSS_THADDIUS_H_
-
-#include "Player.h"
-#include "ScriptMgr.h"
-#include "ScriptedCreature.h"
-#include "SpellScript.h"
-#include "SpellInfo.h"
-#include "naxxramas.h"
-
-namespace Thaddius {
-
-enum Says
-{
- // Stalagg
- SAY_STAL_AGGRO = 0,
- SAY_STAL_SLAY = 1,
- SAY_STAL_DEATH = 2,
- EMOTE_STAL_DEATH = 3,
- EMOTE_STAL_REVIVE = 4,
-
- // Feugen
- SAY_FEUG_AGGRO = 0,
- SAY_FEUG_SLAY = 1,
- SAY_FEUG_DEATH = 2,
- EMOTE_FEUG_DEATH = 3,
- EMOTE_FEUG_REVIVE = 4,
-
- // Thaddius
- SAY_GREET = 0,
- SAY_AGGRO = 1,
- SAY_SLAY = 2,
- SAY_ELECT = 3,
- SAY_DEATH = 4,
- EMOTE_POLARITY_SHIFTED = 6,
-
- // Tesla Coil
- EMOTE_TESLA_LINK_BREAKS = 0,
- EMOTE_TESLA_OVERLOAD = 1
-};
-
-enum Spells
-{
- SPELL_MAGNETIC_PULL = 28337,
- SPELL_TESLA_SHOCK = 28099,
- SPELL_SHOCK_VISUAL = 28159,
-
- // Stalagg
- SPELL_POWER_SURGE = 54529,
- SPELL_STALAGG_CHAIN = 28096,
-
- // Feugen
- SPELL_STATIC_FIELD = 28135,
- SPELL_FEUGEN_CHAIN = 28111,
-
- // Thaddius
- SPELL_POLARITY_SHIFT = 28089,
- SPELL_BALL_LIGHTNING = 28299,
- SPELL_CHAIN_LIGHTNING = 28167,
- SPELL_BERSERK = 27680,
- SPELL_THADDIUS_VISUAL_LIGHTNING = 28136,
- SPELL_THADDIUS_SPAWN_STUN = 28160,
-
- SPELL_POSITIVE_CHARGE = 28062,
- SPELL_POSITIVE_CHARGE_STACK = 29659,
- SPELL_NEGATIVE_CHARGE = 28085,
- SPELL_NEGATIVE_CHARGE_STACK = 29660,
- SPELL_POSITIVE_POLARITY = 28059,
- SPELL_NEGATIVE_POLARITY = 28084
-};
-
-enum Events
-{
- EVENT_MINION_POWER_SURGE = 1,
- EVENT_MINION_MAGNETIC_PULL = 2,
- EVENT_MINION_CHECK_DISTANCE = 3,
- EVENT_MINION_STATIC_FIELD = 4,
-
- EVENT_THADDIUS_INIT = 5,
- EVENT_THADDIUS_ENTER_COMBAT = 6,
- EVENT_THADDIUS_CHAIN_LIGHTNING = 7,
- EVENT_THADDIUS_BERSERK = 8,
- EVENT_THADDIUS_POLARITY_SHIFT = 9,
- EVENT_ALLOW_BALL_LIGHTNING = 10
-};
-
-enum Misc
-{
- ACTION_MAGNETIC_PULL = 1,
- ACTION_SUMMON_DIED = 2,
- ACTION_RESTORE = 3,
- GO_TESLA_COIL_LEFT = 181478,
- GO_TESLA_COIL_RIGHT = 181477,
- NPC_TESLA_COIL = 16218
-};
-
-class boss_thaddius : public CreatureScript
-{
-public:
- boss_thaddius() : CreatureScript("boss_thaddius") { }
-
- CreatureAI* GetAI(Creature* pCreature) const override
- {
- return GetNaxxramasAI(pCreature);
- }
-
- struct boss_thaddiusAI : public BossAI
- {
- explicit boss_thaddiusAI(Creature* c) : BossAI(c, BOSS_THADDIUS), summons(me), ballLightningEnabled(false)
- {}
-
- EventMap events;
- SummonList summons;
- uint32 summonTimer{};
- uint32 reviveTimer{};
- uint32 resetTimer{};
- bool ballLightningEnabled;
-
- void DoAction(int32 param) override
- {
- if (param == ACTION_SUMMON_DIED)
- {
- if (summonTimer)
- {
- summonTimer = 0;
- reviveTimer = 1;
- return;
- }
- summonTimer = 1;
- }
- }
-
- void Reset() override
- {
- BossAI::Reset();
- events.Reset();
- summons.DespawnAll();
- me->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
- me->SetControlled(true, UNIT_STATE_ROOT);
- summonTimer = 0;
- reviveTimer = 0;
- resetTimer = 1;
- me->SetPosition(me->GetHomePosition());
- ballLightningEnabled = false;
-
- me->SummonCreature(NPC_STALAGG, 3450.45f, -2931.42f, 312.091f, 5.49779f);
- me->SummonCreature(NPC_FEUGEN, 3508.14f, -2988.65f, 312.092f, 2.37365f);
- if (Creature* cr = me->SummonCreature(NPC_TESLA_COIL, 3527.34f, -2951.56f, 318.75f, 0.0f))
- {
- cr->RemoveAllAuras();
- cr->InterruptNonMeleeSpells(true);
- cr->CastSpell(cr, SPELL_FEUGEN_CHAIN, false);
- cr->SetDisableGravity(true);
- cr->SetImmuneToPC(false);
- cr->SetControlled(true, UNIT_STATE_ROOT);
- }
- if (Creature* cr = me->SummonCreature(NPC_TESLA_COIL, 3487.04f, -2911.68f, 318.75f, 0.0f))
- {
- cr->RemoveAllAuras();
- cr->InterruptNonMeleeSpells(true);
- cr->CastSpell(cr, SPELL_STALAGG_CHAIN, false);
- cr->SetDisableGravity(true);
- cr->SetImmuneToPC(false);
- cr->SetControlled(true, UNIT_STATE_ROOT);
- }
-
- if (GameObject* go = me->FindNearestGameObject(GO_TESLA_COIL_LEFT, 100.0f))
- go->SetGoState(GO_STATE_ACTIVE);
-
- if (GameObject* go = me->FindNearestGameObject(GO_TESLA_COIL_RIGHT, 100.0f))
- go->SetGoState(GO_STATE_ACTIVE);
-
- instance->DoRemoveAurasDueToSpellOnPlayers(SPELL_POSITIVE_POLARITY);
- instance->DoRemoveAurasDueToSpellOnPlayers(SPELL_POSITIVE_CHARGE_STACK);
- instance->DoRemoveAurasDueToSpellOnPlayers(SPELL_NEGATIVE_POLARITY);
- instance->DoRemoveAurasDueToSpellOnPlayers(SPELL_NEGATIVE_CHARGE_STACK);
- }
-
- void KilledUnit(Unit* who) override
- {
- if (!who->IsPlayer())
- return;
-
- Talk(SAY_SLAY);
- instance->StorePersistentData(PERSISTENT_DATA_IMMORTAL_FAIL, 1);
- }
-
- void JustDied(Unit* killer) override
- {
- BossAI::JustDied(killer);
- Talk(SAY_DEATH);
- instance->DoRemoveAurasDueToSpellOnPlayers(SPELL_POSITIVE_POLARITY);
- instance->DoRemoveAurasDueToSpellOnPlayers(SPELL_POSITIVE_CHARGE_STACK);
- instance->DoRemoveAurasDueToSpellOnPlayers(SPELL_NEGATIVE_POLARITY);
- instance->DoRemoveAurasDueToSpellOnPlayers(SPELL_NEGATIVE_CHARGE_STACK);
- }
-
- void JustSummoned(Creature* cr) override
- {
- summons.Summon(cr);
- }
-
- void JustEngagedWith(Unit* who) override
- {
- BossAI::JustEngagedWith(who);
- me->SetInCombatWithZone();
- summons.DoZoneInCombat(NPC_FEUGEN);
- summons.DoZoneInCombat(NPC_STALAGG);
- }
-
- void UpdateAI(uint32 diff) override
- {
- if (resetTimer)
- {
- resetTimer += diff;
- if (resetTimer > 1000)
- {
- resetTimer = 0;
- me->CastSpell(me, SPELL_THADDIUS_SPAWN_STUN, true);
- }
- return;
- }
- if (reviveTimer)
- {
- reviveTimer += diff;
- if (reviveTimer >= 12000)
- {
- for (SummonList::const_iterator itr = summons.begin(); itr != summons.end(); ++itr)
- {
- if (Creature* cr = ObjectAccessor::GetCreature(*me, (*itr)))
- {
- if (cr->GetEntry() == NPC_TESLA_COIL)
- {
- cr->AI()->Talk(EMOTE_TESLA_OVERLOAD);
- cr->CastSpell(me, SPELL_SHOCK_VISUAL, true);
- }
- }
- }
- reviveTimer = 0;
- events.ScheduleEvent(EVENT_THADDIUS_INIT, 750ms);
- }
- return;
- }
-
- if (!UpdateVictim())
- return;
-
- events.Update(diff);
- if (me->HasUnitState(UNIT_STATE_CASTING))
- return;
-
- if (summonTimer) // Revive
- {
- summonTimer += diff;
- if (summonTimer >= 5000)
- {
- summons.DoAction(ACTION_RESTORE);
- summonTimer = 0;
- }
- }
-
- switch (events.ExecuteEvent())
- {
- case EVENT_THADDIUS_INIT:
- {
- me->RemoveAllAuras();
- me->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
- for (SummonList::const_iterator itr = summons.begin(); itr != summons.end(); ++itr)
- {
- if (Creature* cr = ObjectAccessor::GetCreature(*me, (*itr)))
- {
- if (cr->GetEntry() == NPC_TESLA_COIL)
- {
- Unit::Kill(cr, cr);
- }
- }
- }
- if (GameObject* go = me->FindNearestGameObject(GO_TESLA_COIL_LEFT, 100.0f))
- {
- go->SetGoState(GO_STATE_READY);
- }
- if (GameObject* go = me->FindNearestGameObject(GO_TESLA_COIL_RIGHT, 100.0f))
- {
- go->SetGoState(GO_STATE_READY);
- }
- me->CastSpell(me, SPELL_THADDIUS_VISUAL_LIGHTNING, true);
- events.ScheduleEvent(EVENT_THADDIUS_ENTER_COMBAT, 1s);
- break;
- }
- case EVENT_THADDIUS_ENTER_COMBAT:
- Talk(SAY_AGGRO);
- me->SetReactState(REACT_AGGRESSIVE);
- me->SetControlled(false, UNIT_STATE_STUNNED);
- me->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
- me->SetControlled(false, UNIT_STATE_ROOT);
- events.ScheduleEvent(EVENT_THADDIUS_CHAIN_LIGHTNING, 14s);
- events.ScheduleEvent(EVENT_THADDIUS_BERSERK, 6min);
- events.ScheduleEvent(EVENT_THADDIUS_POLARITY_SHIFT, 20s);
- events.ScheduleEvent(EVENT_ALLOW_BALL_LIGHTNING, 5s);
- return;
- case EVENT_THADDIUS_BERSERK:
- me->CastSpell(me, SPELL_BERSERK, true);
- break;
- case EVENT_THADDIUS_CHAIN_LIGHTNING:
- me->CastSpell(me->GetVictim(), SPELL_CHAIN_LIGHTNING, false);
- events.Repeat(15s);
- break;
- case EVENT_THADDIUS_POLARITY_SHIFT:
- me->CastSpell(me, SPELL_POLARITY_SHIFT, false);
- events.Repeat(30s);
- break;
- case EVENT_ALLOW_BALL_LIGHTNING:
- ballLightningEnabled = true;
- break;
- }
-
- if (me->IsWithinMeleeRange(me->GetVictim()))
- {
- DoMeleeAttackIfReady();
- }
- else if (ballLightningEnabled)
- {
- if (Unit* target = SelectTarget(SelectTargetMethod::MaxThreat))
- {
- me->CastSpell(target, SPELL_BALL_LIGHTNING, false);
- }
- }
- }
- };
-};
-
-class boss_thaddius_summon : public CreatureScript
-{
-public:
- boss_thaddius_summon() : CreatureScript("boss_thaddius_summon") { }
-
- CreatureAI* GetAI(Creature* pCreature) const override
- {
- return GetNaxxramasAI(pCreature);
- }
-
- struct boss_thaddius_summonAI : public ScriptedAI
- {
- explicit boss_thaddius_summonAI(Creature* c) : ScriptedAI(c)
- {
- overload = false;
- }
-
- EventMap events;
- uint32 pullTimer{};
- uint32 visualTimer{};
- bool overload;
- ObjectGuid myCoil;
-
- void Reset() override
- {
- pullTimer = 0;
- visualTimer = 1;
- overload = false;
- events.Reset();
- me->SetControlled(false, UNIT_STATE_STUNNED);
- if (Creature* cr = me->FindNearestCreature(NPC_TESLA_COIL, 150.0f))
- {
- cr->CastSpell(cr, me->GetEntry() == NPC_STALAGG ? SPELL_STALAGG_CHAIN : SPELL_FEUGEN_CHAIN, false);
- cr->SetImmuneToPC(false);
- myCoil = cr->GetGUID();
- }
- }
-
- void EnterEvadeMode(EvadeReason why) override
- {
- me->SetControlled(false, UNIT_STATE_STUNNED);
- ScriptedAI::EnterEvadeMode(why);
- }
-
- void JustEngagedWith(Unit* pWho) override
- {
- me->SetInCombatWithZone();
- if (Creature* cr = me->FindNearestCreature(NPC_TESLA_COIL, 150.f, true))
- {
- myCoil = cr->GetGUID();
- }
- if (me->GetEntry() == NPC_STALAGG)
- {
- events.ScheduleEvent(EVENT_MINION_POWER_SURGE, 10s);
- Talk(SAY_STAL_AGGRO);
- }
- else
- {
- events.ScheduleEvent(EVENT_MINION_STATIC_FIELD, 5s);
- Talk(SAY_FEUG_AGGRO);
- }
- events.ScheduleEvent(EVENT_MINION_CHECK_DISTANCE, 5s);
-
- if (me->GetEntry() == NPC_STALAGG) // This event needs synchronisation, called for stalagg only
- {
- events.ScheduleEvent(EVENT_MINION_MAGNETIC_PULL, 20s);
- }
-
- if (Creature* cr = me->GetInstanceScript()->GetCreature(DATA_THADDIUS_BOSS))
- {
- cr->AI()->AttackStart(pWho);
- cr->AddThreat(pWho, 10.0f);
- }
- }
-
- void DoAction(int32 param) override
- {
- if (param == ACTION_MAGNETIC_PULL)
- {
- pullTimer = 1;
- me->SetControlled(true, UNIT_STATE_STUNNED);
- }
- else if (param == ACTION_RESTORE)
- {
- if (!me->IsAlive())
- {
- me->Respawn();
- me->SetInCombatWithZone();
- Talk(me->GetEntry() == NPC_STALAGG ? EMOTE_STAL_REVIVE : EMOTE_FEUG_REVIVE);
- }
- else
- {
- me->SetHealth(me->GetMaxHealth());
- }
- }
- }
-
- void JustDied(Unit* /*killer*/) override
- {
- Talk(me->GetEntry() == NPC_STALAGG ? SAY_STAL_DEATH : SAY_FEUG_DEATH);
- Talk(me->GetEntry() == NPC_STALAGG ? EMOTE_STAL_DEATH : EMOTE_FEUG_DEATH);
-
- if (Creature* cr = me->GetInstanceScript()->GetCreature(DATA_THADDIUS_BOSS))
- cr->AI()->DoAction(ACTION_SUMMON_DIED);
- }
-
- void KilledUnit(Unit* who) override
- {
- if (!who->IsPlayer())
- return;
-
- if (!urand(0, 2))
- Talk(me->GetEntry() == NPC_STALAGG ? SAY_STAL_SLAY : SAY_FEUG_SLAY);
-
- me->GetInstanceScript()->StorePersistentData(PERSISTENT_DATA_IMMORTAL_FAIL, 1);
- }
-
- void UpdateAI(uint32 diff) override
- {
- if (visualTimer)
- {
- visualTimer += diff;
- if (visualTimer >= 3000)
- {
- visualTimer = 0;
- if (Creature* cr = me->FindNearestCreature(NPC_TESLA_COIL, 150.0f))
- {
- cr->CastSpell(cr, me->GetEntry() == NPC_STALAGG ? SPELL_STALAGG_CHAIN : SPELL_FEUGEN_CHAIN, false);
- }
- }
- }
-
- if (!UpdateVictim())
- return;
-
- if (pullTimer) // Disable AI during pull
- {
- pullTimer += diff;
- if (pullTimer >= 3000)
- {
- me->SetControlled(false, UNIT_STATE_STUNNED);
- pullTimer = 0;
- }
- return;
- }
-
- events.Update(diff);
- if (me->HasUnitState(UNIT_STATE_CASTING))
- return;
-
- switch (events.ExecuteEvent())
- {
- case EVENT_MINION_POWER_SURGE:
- me->CastSpell(me, SPELL_POWER_SURGE, false);
- events.Repeat(19s);
- break;
- case EVENT_MINION_STATIC_FIELD:
- me->CastSpell(me, SPELL_STATIC_FIELD, false);
- events.Repeat(3s);
- break;
- case EVENT_MINION_MAGNETIC_PULL:
- {
- events.Repeat(20s);
- if (Creature* feugen = me->GetInstanceScript()->GetCreature(DATA_FEUGEN_BOSS))
- {
- if (!feugen->IsAlive() || !feugen->GetVictim() || !me->GetVictim())
- return;
-
- float threatFeugen = feugen->GetThreatMgr().GetThreat(feugen->GetVictim());
- float threatStalagg = me->GetThreatMgr().GetThreat(me->GetVictim());
- Unit* tankFeugen = feugen->GetVictim();
- Unit* tankStalagg = me->GetVictim();
-
- feugen->GetThreatMgr().ModifyThreatByPercent(tankFeugen, -100);
- feugen->AddThreat(tankStalagg, threatFeugen);
- feugen->CastSpell(tankStalagg, SPELL_MAGNETIC_PULL, true);
- feugen->AI()->DoAction(ACTION_MAGNETIC_PULL);
-
- me->GetThreatMgr().ModifyThreatByPercent(tankStalagg, -100);
- me->AddThreat(tankFeugen, threatStalagg);
- me->CastSpell(tankFeugen, SPELL_MAGNETIC_PULL, true);
- DoAction(ACTION_MAGNETIC_PULL);
- }
- break;
- }
- case EVENT_MINION_CHECK_DISTANCE:
- if (Creature* cr = ObjectAccessor::GetCreature(*me, myCoil))
- {
- if (!me->GetHomePosition().IsInDist(me, 28) && me->IsInCombat())
- {
- if (!overload)
- {
- overload = true;
- cr->AI()->Talk(EMOTE_TESLA_LINK_BREAKS);
- me->RemoveAurasDueToSpell(me->GetEntry() == NPC_STALAGG ? SPELL_STALAGG_CHAIN : SPELL_FEUGEN_CHAIN);
- cr->InterruptNonMeleeSpells(true);
- }
- if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 1000.f, true))
- {
- cr->CastStop(SPELL_TESLA_SHOCK);
- cr->CastSpell(target, SPELL_TESLA_SHOCK, true);
- }
- events.Repeat(1500ms);
- break;
- }
- else
- {
- overload = false;
- cr->CastSpell(cr, me->GetEntry() == NPC_STALAGG ? SPELL_STALAGG_CHAIN : SPELL_FEUGEN_CHAIN, false);
- }
- }
- events.Repeat(5s);
- break;
- }
- DoMeleeAttackIfReady();
- }
- };
-};
-
-class spell_thaddius_pos_neg_charge : public SpellScript
-{
- PrepareSpellScript(spell_thaddius_pos_neg_charge);
-
- bool Validate(SpellInfo const* /*spellInfo*/) override
- {
- return ValidateSpellInfo({ SPELL_POSITIVE_CHARGE, SPELL_POSITIVE_CHARGE_STACK });
- }
-
- void HandleTargets(std::list& targets)
- {
- uint8 count = 0;
- for (auto& ihit : targets)
- {
- if (ihit->GetGUID() != GetCaster()->GetGUID())
- {
- if (Player* target = ihit->ToPlayer())
- {
- if (target->HasAura(GetTriggeringSpell()->Id))
- {
- ++count;
- }
- }
- }
- }
-
- if (count)
- {
- uint32 spellId = GetSpellInfo()->Id == SPELL_POSITIVE_CHARGE ? SPELL_POSITIVE_CHARGE_STACK : SPELL_NEGATIVE_CHARGE_STACK;
- GetCaster()->SetAuraStack(spellId, GetCaster(), count);
- }
- }
-
- void HandleDamage(SpellEffIndex /*effIndex*/)
- {
- if (!GetTriggeringSpell())
- return;
-
- Unit* target = GetHitUnit();
- if (!target)
- return;
-
- if (target->HasAura(GetTriggeringSpell()->Id) || !target->IsPlayer())
- {
- SetHitDamage(0);
- }
- else if (InstanceScript* instance = target->GetInstanceScript())
- {
- instance->SetData(DATA_CHARGES_CROSSED, 0);
- }
- }
-
- void Register() override
- {
- OnEffectHitTarget += SpellEffectFn(spell_thaddius_pos_neg_charge::HandleDamage, EFFECT_0, SPELL_EFFECT_SCHOOL_DAMAGE);
- OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_thaddius_pos_neg_charge::HandleTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ALLY);
- }
-};
-
-class spell_thaddius_polarity_shift : public SpellScript
-{
- PrepareSpellScript(spell_thaddius_polarity_shift);
-
- bool Validate(SpellInfo const* /*spell*/) override
- {
- return ValidateSpellInfo({ SPELL_POSITIVE_POLARITY, SPELL_NEGATIVE_POLARITY });
- }
-
- void HandleDummy(SpellEffIndex /* effIndex */)
- {
- Unit* caster = GetCaster();
- if (Unit* target = GetHitUnit())
- {
- target->RemoveAurasDueToSpell(SPELL_POSITIVE_CHARGE_STACK);
- target->RemoveAurasDueToSpell(SPELL_NEGATIVE_CHARGE_STACK);
- target->CastSpell(target, roll_chance_i(50) ? SPELL_POSITIVE_POLARITY : SPELL_NEGATIVE_POLARITY, true, nullptr, nullptr, caster->GetGUID());
- }
- }
-
- void HandleAfterCast()
- {
- if (GetCaster())
- {
- if (Creature* caster = GetCaster()->ToCreature())
- {
- if (caster->GetEntry() == NPC_THADDIUS)
- {
- caster->AI()->Talk(SAY_ELECT);
- caster->AI()->Talk(EMOTE_POLARITY_SHIFTED);
- }
- }
- }
- }
-
- void Register() override
- {
- OnEffectHitTarget += SpellEffectFn(spell_thaddius_polarity_shift::HandleDummy, EFFECT_0, SPELL_EFFECT_DUMMY);
- AfterCast += SpellCastFn(spell_thaddius_polarity_shift::HandleAfterCast);
- }
-};
-
-class npc_tesla : public CreatureScript
-{
-public:
- npc_tesla() : CreatureScript("npc_tesla") { }
-
- CreatureAI* GetAI(Creature* creature) const override
- {
- return GetNaxxramasAI(creature);
- }
-
- struct npc_teslaAI : public ScriptedAI
- {
- public:
- npc_teslaAI(Creature* creature) : ScriptedAI(creature) { }
- void EnterEvadeMode(EvadeReason /*why*/) override { } // never stop casting due to evade
- void UpdateAI(uint32 /*diff*/) override { } // never do anything unless told
- void JustEngagedWith(Unit* /*who*/) override { }
- void DamageTaken(Unit* /*who*/, uint32& damage, DamageEffectType, SpellSchoolMask) override { damage = 0; } // no, you can't kill it
- };
-};
-
-class at_thaddius_entrance : public OnlyOnceAreaTriggerScript
-{
-public:
- at_thaddius_entrance() : OnlyOnceAreaTriggerScript("at_thaddius_entrance") { }
-
- bool _OnTrigger(Player* player, const AreaTrigger* /*trigger*/) override
- {
- if (InstanceScript* instance = player->GetInstanceScript())
- if (instance->GetBossState(BOSS_THADDIUS) != DONE)
- if (Creature* thaddius = instance->GetCreature(DATA_THADDIUS_BOSS))
- thaddius->AI()->Talk(SAY_GREET);
- return false;
- }
-};
-
-}
-
-#endif
\ No newline at end of file