aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/server/game/Scripting/ScriptMgr.h68
-rw-r--r--src/server/scripts/Northrend/Naxxramas/boss_thaddius.cpp532
-rw-r--r--src/server/scripts/Northrend/Naxxramas/naxxramas.h1
-rw-r--r--src/server/scripts/Spells/spell_item.cpp53
4 files changed, 348 insertions, 306 deletions
diff --git a/src/server/game/Scripting/ScriptMgr.h b/src/server/game/Scripting/ScriptMgr.h
index 020df6d54ac..eea4d7cc39c 100644
--- a/src/server/game/Scripting/ScriptMgr.h
+++ b/src/server/game/Scripting/ScriptMgr.h
@@ -205,10 +205,10 @@ class TC_GAME_API SpellScriptLoader : public ScriptObject
public:
// Should return a fully valid SpellScript pointer.
- virtual SpellScript* GetSpellScript() const { return NULL; }
+ virtual SpellScript* GetSpellScript() const { return nullptr; }
// Should return a fully valid AuraScript pointer.
- virtual AuraScript* GetAuraScript() const { return NULL; }
+ virtual AuraScript* GetAuraScript() const { return nullptr; }
};
class TC_GAME_API ServerScript : public ScriptObject
@@ -1175,6 +1175,70 @@ class TC_GAME_API ScriptMgr
std::string _currentContext;
};
+template <class S>
+class GenericSpellScriptLoader : public SpellScriptLoader
+{
+ public:
+ GenericSpellScriptLoader(char const* name) : SpellScriptLoader(name) { }
+ SpellScript* GetSpellScript() const override { return new S(); }
+};
+#define RegisterSpellScript(spell_script) new GenericSpellScriptLoader<spell_script>(#spell_script)
+
+template <class A>
+class GenericAuraScriptLoader : public SpellScriptLoader
+{
+ public:
+ GenericAuraScriptLoader(char const* name) : SpellScriptLoader(name) { }
+ AuraScript* GetAuraScript() const override { return new A(); }
+};
+#define RegisterAuraScript(aura_script) new GenericAuraScriptLoader<aura_script>(#aura_script)
+
+template <class S, class A>
+class GenericSpellAndAuraScriptLoader : public SpellScriptLoader
+{
+ public:
+ GenericSpellAndAuraScriptLoader(char const* name) : SpellScriptLoader(name) { }
+ SpellScript* GetSpellScript() const override { return new S(); }
+ AuraScript* GetAuraScript() const override { return new A(); }
+};
+#define RegisterSpellAndAuraScriptPair(spell_script, aura_script) new GenericSpellAndAuraScriptLoader<spell_script, aura_script>(#spell_script)
+
+template <class AI>
+class GenericCreatureScript : public CreatureScript
+{
+ public:
+ GenericCreatureScript(char const* name) : CreatureScript(name) { }
+ CreatureAI* GetAI(Creature* me) const override { return new AI(me); }
+};
+#define RegisterCreatureAI(ai_name) new GenericCreatureScript<ai_name>(#ai_name)
+
+template <class AI, AI*(*AIFactory)(Creature*)>
+class FactoryCreatureScript : public CreatureScript
+{
+ public:
+ FactoryCreatureScript(char const* name) : CreatureScript(name) { }
+ CreatureAI* GetAI(Creature* me) const override { return AIFactory(me); }
+};
+#define RegisterCreatureAIWithFactory(ai_name, factory_fn) new FactoryCreatureScript<ai_name, &factory_fn>(#ai_name)
+
+template <class AI>
+class GenericGameObjectScript : public GameObjectScript
+{
+ public:
+ GenericGameObjectScript(char const* name) : GameObjectScript(name) { }
+ GameObjectAI* GetAI(GameObject* go) const override { return new AI(go); }
+};
+#define RegisterGameObjectAI(ai_name) new GenericGameObjectScript<ai_name>(#ai_name)
+
+template <class AI>
+class GenericAreaTriggerEntityScript : public AreaTriggerEntityScript
+{
+ public:
+ GenericAreaTriggerEntityScript(char const* name) : AreaTriggerEntityScript(name) { }
+ AreaTriggerAI* GetAI(AreaTrigger* at) const override { return new AI(at); }
+};
+#define RegisterAreaTriggerAI(ai_name) new GenericAreaTriggerEntityScript<ai_name>(#ai_name)
+
#define sScriptMgr ScriptMgr::instance()
#endif
diff --git a/src/server/scripts/Northrend/Naxxramas/boss_thaddius.cpp b/src/server/scripts/Northrend/Naxxramas/boss_thaddius.cpp
index 7bddb692a98..ba52ecb0439 100644
--- a/src/server/scripts/Northrend/Naxxramas/boss_thaddius.cpp
+++ b/src/server/scripts/Northrend/Naxxramas/boss_thaddius.cpp
@@ -160,320 +160,308 @@ enum ThaddiusSpells
SPELL_NEGATIVE_CHARGE_AMP = 29660,
};
-class boss_thaddius : public CreatureScript
+struct boss_thaddius : public BossAI
{
-public:
- boss_thaddius() : CreatureScript("boss_thaddius") { }
-
- CreatureAI* GetAI(Creature* creature) const override
- {
- return GetNaxxramasAI<boss_thaddiusAI>(creature);
- }
-
- struct boss_thaddiusAI : public BossAI
- {
- public:
- boss_thaddiusAI(Creature* creature) : BossAI(creature, BOSS_THADDIUS), stalaggAlive(true), feugenAlive(true), ballLightningUnlocked(false), ballLightningEnabled(false), shockingEligibility(true) {}
+ public:
+ boss_thaddius(Creature* creature) : BossAI(creature, BOSS_THADDIUS), stalaggAlive(true), feugenAlive(true), ballLightningUnlocked(false), ballLightningEnabled(false), shockingEligibility(true) {}
- void InitializeAI() override
+ void InitializeAI() override
+ {
+ if (instance->GetBossState(BOSS_THADDIUS) != DONE)
{
- if (instance->GetBossState(BOSS_THADDIUS) != DONE)
- {
- events.SetPhase(PHASE_NOT_ENGAGED);
- SetCombatMovement(false);
+ events.SetPhase(PHASE_NOT_ENGAGED);
+ SetCombatMovement(false);
- // initialize everything properly, and ensure that the coils are loaded by the time we initialize
- BeginResetEncounter(true);
- }
+ // initialize everything properly, and ensure that the coils are loaded by the time we initialize
+ BeginResetEncounter(true);
}
+ }
- void KilledUnit(Unit* victim) override
- {
- if (victim->GetTypeId() == TYPEID_PLAYER)
- Talk(SAY_SLAY);
- }
+ void KilledUnit(Unit* victim) override
+ {
+ if (victim->GetTypeId() == TYPEID_PLAYER)
+ Talk(SAY_SLAY);
+ }
- void Reset() override { }
+ void Reset() override { }
- void EnterEvadeMode(EvadeReason why) override
+ void EnterEvadeMode(EvadeReason why) override
+ {
+ if (!ballLightningEnabled && why == EVADE_REASON_NO_HOSTILES)
{
- if (!ballLightningEnabled && why == EVADE_REASON_NO_HOSTILES)
- {
- ballLightningEnabled = true;
- return; // try again
- }
- if (events.IsInPhase(PHASE_TRANSITION) || (events.IsInPhase(PHASE_THADDIUS) && me->IsAlive()))
- BeginResetEncounter();
+ ballLightningEnabled = true;
+ return; // try again
}
+ if (events.IsInPhase(PHASE_TRANSITION) || (events.IsInPhase(PHASE_THADDIUS) && me->IsAlive()))
+ BeginResetEncounter();
+ }
- bool CanAIAttack(Unit const* who) const override
- {
- if (ballLightningEnabled || me->IsWithinMeleeRange(who))
- return BossAI::CanAIAttack(who);
- else
- return false;
- }
+ bool CanAIAttack(Unit const* who) const override
+ {
+ if (ballLightningEnabled || me->IsWithinMeleeRange(who))
+ return BossAI::CanAIAttack(who);
+ else
+ return false;
+ }
- void JustRespawned() override
- {
- if (events.IsInPhase(PHASE_RESETTING))
- ResetEncounter();
- }
+ void JustRespawned() override
+ {
+ if (events.IsInPhase(PHASE_RESETTING))
+ ResetEncounter();
+ }
- void JustDied(Unit* /*killer*/) override
- {
- _JustDied();
- me->setActive(false);
- if (Creature* stalagg = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_STALAGG)))
- stalagg->setActive(false);
- if (Creature* feugen = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_FEUGEN)))
- feugen->setActive(false);
- Talk(SAY_DEATH);
- }
+ void JustDied(Unit* /*killer*/) override
+ {
+ _JustDied();
+ me->setActive(false);
+ if (Creature* stalagg = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_STALAGG)))
+ stalagg->setActive(false);
+ if (Creature* feugen = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_FEUGEN)))
+ feugen->setActive(false);
+ Talk(SAY_DEATH);
+ }
- void DoAction(int32 action) override
+ void DoAction(int32 action) override
+ {
+ switch (action)
{
- switch (action)
- {
- case ACTION_RESET_ENCOUNTER_TIMER:
- if (events.IsInPhase(PHASE_RESETTING))
- ResetEncounter();
- break;
- case ACTION_FEUGEN_RESET:
- case ACTION_STALAGG_RESET:
- if (!events.IsInPhase(PHASE_NOT_ENGAGED) && !events.IsInPhase(PHASE_RESETTING))
- BeginResetEncounter();
- break;
- case ACTION_FEUGEN_AGGRO:
- case ACTION_STALAGG_AGGRO:
- if (events.IsInPhase(PHASE_RESETTING))
- {
- BeginResetEncounter();
- return;
- }
- if (!events.IsInPhase(PHASE_NOT_ENGAGED))
- return;
- events.SetPhase(PHASE_PETS);
-
- shockingEligibility = true;
-
- if (!instance->CheckRequiredBosses(BOSS_THADDIUS))
- {
- BeginResetEncounter();
- return;
- }
- instance->SetBossState(BOSS_THADDIUS, IN_PROGRESS);
-
- me->setActive(true);
- DoZoneInCombat();
- if (Creature* stalagg = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_STALAGG)))
- stalagg->setActive(true);
- if (Creature* feugen = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_FEUGEN)))
- feugen->setActive(true);
- break;
- case ACTION_FEUGEN_DIED:
- if (Creature* feugen = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_FEUGEN)))
- feugen->AI()->DoAction(ACTION_FEUGEN_REVIVING_FX);
- feugenAlive = false;
- if (stalaggAlive)
- events.ScheduleEvent(EVENT_REVIVE_FEUGEN, Seconds(5), 0, PHASE_PETS);
- else
- Transition();
+ case ACTION_RESET_ENCOUNTER_TIMER:
+ if (events.IsInPhase(PHASE_RESETTING))
+ ResetEncounter();
+ break;
+ case ACTION_FEUGEN_RESET:
+ case ACTION_STALAGG_RESET:
+ if (!events.IsInPhase(PHASE_NOT_ENGAGED) && !events.IsInPhase(PHASE_RESETTING))
+ BeginResetEncounter();
+ break;
+ case ACTION_FEUGEN_AGGRO:
+ case ACTION_STALAGG_AGGRO:
+ if (events.IsInPhase(PHASE_RESETTING))
+ {
+ BeginResetEncounter();
+ return;
+ }
+ if (!events.IsInPhase(PHASE_NOT_ENGAGED))
+ return;
+ events.SetPhase(PHASE_PETS);
- break;
- case ACTION_STALAGG_DIED:
- if (Creature* stalagg = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_STALAGG)))
- stalagg->AI()->DoAction(ACTION_STALAGG_REVIVING_FX);
- stalaggAlive = false;
- if (feugenAlive)
- events.ScheduleEvent(EVENT_REVIVE_STALAGG, Seconds(5), 0, PHASE_PETS);
- else
- Transition();
+ shockingEligibility = true;
- break;
+ if (!instance->CheckRequiredBosses(BOSS_THADDIUS))
+ {
+ BeginResetEncounter();
+ return;
+ }
+ instance->SetBossState(BOSS_THADDIUS, IN_PROGRESS);
+
+ me->setActive(true);
+ DoZoneInCombat();
+ if (Creature* stalagg = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_STALAGG)))
+ stalagg->setActive(true);
+ if (Creature* feugen = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_FEUGEN)))
+ feugen->setActive(true);
+ break;
+ case ACTION_FEUGEN_DIED:
+ if (Creature* feugen = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_FEUGEN)))
+ feugen->AI()->DoAction(ACTION_FEUGEN_REVIVING_FX);
+ feugenAlive = false;
+ if (stalaggAlive)
+ events.ScheduleEvent(EVENT_REVIVE_FEUGEN, Seconds(5), 0, PHASE_PETS);
+ else
+ Transition();
+
+ break;
+ case ACTION_STALAGG_DIED:
+ if (Creature* stalagg = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_STALAGG)))
+ stalagg->AI()->DoAction(ACTION_STALAGG_REVIVING_FX);
+ stalaggAlive = false;
+ if (feugenAlive)
+ events.ScheduleEvent(EVENT_REVIVE_STALAGG, Seconds(5), 0, PHASE_PETS);
+ else
+ Transition();
- case ACTION_POLARITY_CROSSED:
- shockingEligibility = false;
- break;
- default:
- break;
- }
- }
+ break;
- uint32 GetData(uint32 id) const override
- {
- return (id == DATA_POLARITY_CROSSED && shockingEligibility) ? 1u : 0u;
+ case ACTION_POLARITY_CROSSED:
+ shockingEligibility = false;
+ break;
+ default:
+ break;
}
+ }
- void Transition() // initiate transition between pet phase and thaddius phase
- {
- events.SetPhase(PHASE_TRANSITION);
-
- me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
-
- events.ScheduleEvent(EVENT_TRANSITION_1, Seconds(10), 0, PHASE_TRANSITION);
- events.ScheduleEvent(EVENT_TRANSITION_2, Seconds(12), 0, PHASE_TRANSITION);
- events.ScheduleEvent(EVENT_TRANSITION_3, Seconds(14), 0, PHASE_TRANSITION);
- }
+ uint32 GetData(uint32 id) const override
+ {
+ return (id == DATA_POLARITY_CROSSED && shockingEligibility) ? 1u : 0u;
+ }
- void BeginResetEncounter(bool initial = false)
- {
- if (instance->GetBossState(BOSS_THADDIUS) == DONE)
- return;
- if (events.IsInPhase(PHASE_RESETTING))
- return;
+ void Transition() // initiate transition between pet phase and thaddius phase
+ {
+ events.SetPhase(PHASE_TRANSITION);
- // remove polarity shift debuffs on reset
- instance->DoRemoveAurasDueToSpellOnPlayers(SPELL_POSITIVE_CHARGE_APPLY);
- instance->DoRemoveAurasDueToSpellOnPlayers(SPELL_NEGATIVE_CHARGE_APPLY);
+ me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
- me->DespawnOrUnsummon();
- me->SetRespawnTime(initial ? 5 : 30);
+ events.ScheduleEvent(EVENT_TRANSITION_1, Seconds(10), 0, PHASE_TRANSITION);
+ events.ScheduleEvent(EVENT_TRANSITION_2, Seconds(12), 0, PHASE_TRANSITION);
+ events.ScheduleEvent(EVENT_TRANSITION_3, Seconds(14), 0, PHASE_TRANSITION);
+ }
- me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC | UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_STUNNED);
- events.SetPhase(PHASE_RESETTING);
- if (Creature* feugen = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_FEUGEN)))
- feugen->AI()->DoAction(ACTION_BEGIN_RESET_ENCOUNTER);
- if (Creature* stalagg = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_STALAGG)))
- stalagg->AI()->DoAction(ACTION_BEGIN_RESET_ENCOUNTER);
+ void BeginResetEncounter(bool initial = false)
+ {
+ if (instance->GetBossState(BOSS_THADDIUS) == DONE)
+ return;
+ if (events.IsInPhase(PHASE_RESETTING))
+ return;
+
+ // remove polarity shift debuffs on reset
+ instance->DoRemoveAurasDueToSpellOnPlayers(SPELL_POSITIVE_CHARGE_APPLY);
+ instance->DoRemoveAurasDueToSpellOnPlayers(SPELL_NEGATIVE_CHARGE_APPLY);
+
+ me->DespawnOrUnsummon();
+ me->SetRespawnTime(initial ? 5 : 30);
+
+ me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC | UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_STUNNED);
+ events.SetPhase(PHASE_RESETTING);
+ if (Creature* feugen = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_FEUGEN)))
+ feugen->AI()->DoAction(ACTION_BEGIN_RESET_ENCOUNTER);
+ if (Creature* stalagg = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_STALAGG)))
+ stalagg->AI()->DoAction(ACTION_BEGIN_RESET_ENCOUNTER);
+
+ me->setActive(false);
+ }
- me->setActive(false);
- }
+ void ResetEncounter()
+ {
+ feugenAlive = true;
+ stalaggAlive = true;
- void ResetEncounter()
- {
- feugenAlive = true;
- stalaggAlive = true;
+ _Reset();
+ events.SetPhase(PHASE_NOT_ENGAGED);
+ me->SetReactState(REACT_PASSIVE);
- _Reset();
- events.SetPhase(PHASE_NOT_ENGAGED);
- me->SetReactState(REACT_PASSIVE);
+ if (Creature* feugen = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_FEUGEN)))
+ feugen->AI()->DoAction(ACTION_RESET_ENCOUNTER);
+ if (Creature* stalagg = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_STALAGG)))
+ stalagg->AI()->DoAction(ACTION_RESET_ENCOUNTER);
+ }
- if (Creature* feugen = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_FEUGEN)))
- feugen->AI()->DoAction(ACTION_RESET_ENCOUNTER);
- if (Creature* stalagg = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_STALAGG)))
- stalagg->AI()->DoAction(ACTION_RESET_ENCOUNTER);
- }
+ void UpdateAI(uint32 diff) override
+ {
+ if (events.IsInPhase(PHASE_NOT_ENGAGED))
+ return;
+ if (events.IsInPhase(PHASE_THADDIUS) && !UpdateVictim())
+ return;
- void UpdateAI(uint32 diff) override
+ events.Update(diff);
+ while (uint32 eventId = events.ExecuteEvent())
{
- if (events.IsInPhase(PHASE_NOT_ENGAGED))
- return;
- if (events.IsInPhase(PHASE_THADDIUS) && !UpdateVictim())
- return;
-
- events.Update(diff);
- while (uint32 eventId = events.ExecuteEvent())
+ switch (eventId)
{
- switch (eventId)
- {
- case EVENT_REVIVE_FEUGEN:
- feugenAlive = true;
- if (Creature* feugen = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_FEUGEN)))
- feugen->AI()->DoAction(ACTION_FEUGEN_REVIVED);
- break;
- case EVENT_REVIVE_STALAGG:
- stalaggAlive = true;
- if (Creature* stalagg = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_STALAGG)))
- stalagg->AI()->DoAction(ACTION_STALAGG_REVIVED);
- break;
- case EVENT_TRANSITION_1: // tesla coils overload
- if (Creature* feugen = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_FEUGEN)))
- feugen->AI()->DoAction(ACTION_TRANSITION);
- if (Creature* stalagg = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_STALAGG)))
- stalagg->AI()->DoAction(ACTION_TRANSITION);
- break;
- case EVENT_TRANSITION_2: // tesla coils shock thaddius
- me->CastSpell(me, SPELL_THADDIUS_SPARK_VISUAL, true);
- if (Creature* feugen = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_FEUGEN)))
- feugen->AI()->DoAction(ACTION_TRANSITION_2);
- if (Creature* stalagg = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_STALAGG)))
- stalagg->AI()->DoAction(ACTION_TRANSITION_2);
- break;
- case EVENT_TRANSITION_3: // thaddius becomes active
- me->CastSpell(me, SPELL_THADDIUS_SPARK_VISUAL, true);
- ballLightningUnlocked = false;
- me->RemoveAura(SPELL_THADDIUS_INACTIVE_VISUAL);
- me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_STUNNED);
- me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC);
- me->SetReactState(REACT_AGGRESSIVE);
-
- DoZoneInCombat();
- if (Unit* closest = SelectTarget(SELECT_TARGET_NEAREST, 0, 500.0f))
- AttackStart(closest);
- else // if there is no nearest target, then there is no target, meaning we should reset
- {
- BeginResetEncounter();
- return;
- }
+ case EVENT_REVIVE_FEUGEN:
+ feugenAlive = true;
+ if (Creature* feugen = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_FEUGEN)))
+ feugen->AI()->DoAction(ACTION_FEUGEN_REVIVED);
+ break;
+ case EVENT_REVIVE_STALAGG:
+ stalaggAlive = true;
+ if (Creature* stalagg = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_STALAGG)))
+ stalagg->AI()->DoAction(ACTION_STALAGG_REVIVED);
+ break;
+ case EVENT_TRANSITION_1: // tesla coils overload
+ if (Creature* feugen = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_FEUGEN)))
+ feugen->AI()->DoAction(ACTION_TRANSITION);
+ if (Creature* stalagg = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_STALAGG)))
+ stalagg->AI()->DoAction(ACTION_TRANSITION);
+ break;
+ case EVENT_TRANSITION_2: // tesla coils shock thaddius
+ me->CastSpell(me, SPELL_THADDIUS_SPARK_VISUAL, true);
+ if (Creature* feugen = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_FEUGEN)))
+ feugen->AI()->DoAction(ACTION_TRANSITION_2);
+ if (Creature* stalagg = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_STALAGG)))
+ stalagg->AI()->DoAction(ACTION_TRANSITION_2);
+ break;
+ case EVENT_TRANSITION_3: // thaddius becomes active
+ me->CastSpell(me, SPELL_THADDIUS_SPARK_VISUAL, true);
+ ballLightningUnlocked = false;
+ me->RemoveAura(SPELL_THADDIUS_INACTIVE_VISUAL);
+ me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_STUNNED);
+ me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC);
+ me->SetReactState(REACT_AGGRESSIVE);
+
+ DoZoneInCombat();
+ if (Unit* closest = SelectTarget(SELECT_TARGET_NEAREST, 0, 500.0f))
+ AttackStart(closest);
+ else // if there is no nearest target, then there is no target, meaning we should reset
+ {
+ BeginResetEncounter();
+ return;
+ }
- if (Creature* feugen = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_FEUGEN)))
- feugen->AI()->DoAction(ACTION_TRANSITION_3);
- if (Creature* stalagg = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_STALAGG)))
- stalagg->AI()->DoAction(ACTION_TRANSITION_3);
+ if (Creature* feugen = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_FEUGEN)))
+ feugen->AI()->DoAction(ACTION_TRANSITION_3);
+ if (Creature* stalagg = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_STALAGG)))
+ stalagg->AI()->DoAction(ACTION_TRANSITION_3);
- events.SetPhase(PHASE_THADDIUS);
+ events.SetPhase(PHASE_THADDIUS);
- Talk(SAY_AGGRO);
+ Talk(SAY_AGGRO);
- events.ScheduleEvent(EVENT_ENABLE_BALL_LIGHTNING, Seconds(5), 0, PHASE_THADDIUS);
- events.ScheduleEvent(EVENT_SHIFT, Seconds(10), 0, PHASE_THADDIUS);
- events.ScheduleEvent(EVENT_CHAIN, randtime(Seconds(10), Seconds(20)), 0, PHASE_THADDIUS);
- events.ScheduleEvent(EVENT_BERSERK, Minutes(6), 0, PHASE_THADDIUS);
+ events.ScheduleEvent(EVENT_ENABLE_BALL_LIGHTNING, Seconds(5), 0, PHASE_THADDIUS);
+ events.ScheduleEvent(EVENT_SHIFT, Seconds(10), 0, PHASE_THADDIUS);
+ events.ScheduleEvent(EVENT_CHAIN, randtime(Seconds(10), Seconds(20)), 0, PHASE_THADDIUS);
+ events.ScheduleEvent(EVENT_BERSERK, Minutes(6), 0, PHASE_THADDIUS);
- break;
- case EVENT_ENABLE_BALL_LIGHTNING:
- ballLightningUnlocked = true;
- break;
- case EVENT_SHIFT:
- me->CastStop(); // shift overrides all other spells
- DoCastAOE(SPELL_POLARITY_SHIFT);
- events.ScheduleEvent(EVENT_SHIFT_TALK, Seconds(3), PHASE_THADDIUS);
- events.ScheduleEvent(EVENT_SHIFT, Seconds(30), PHASE_THADDIUS);
- break;
- case EVENT_SHIFT_TALK:
- Talk(SAY_ELECT);
- Talk(EMOTE_POLARITY_SHIFTED);
- break;
- case EVENT_CHAIN:
- if (me->FindCurrentSpellBySpellId(SPELL_POLARITY_SHIFT)) // delay until shift is over
- events.Repeat(Seconds(3));
- else
- {
- me->CastStop();
- DoCastVictim(SPELL_CHAIN_LIGHTNING);
- events.Repeat(randtime(Seconds(10), Seconds(20)));
- }
- break;
- case EVENT_BERSERK:
+ break;
+ case EVENT_ENABLE_BALL_LIGHTNING:
+ ballLightningUnlocked = true;
+ break;
+ case EVENT_SHIFT:
+ me->CastStop(); // shift overrides all other spells
+ DoCastAOE(SPELL_POLARITY_SHIFT);
+ events.ScheduleEvent(EVENT_SHIFT_TALK, Seconds(3), PHASE_THADDIUS);
+ events.ScheduleEvent(EVENT_SHIFT, Seconds(30), PHASE_THADDIUS);
+ break;
+ case EVENT_SHIFT_TALK:
+ Talk(SAY_ELECT);
+ Talk(EMOTE_POLARITY_SHIFTED);
+ break;
+ case EVENT_CHAIN:
+ if (me->FindCurrentSpellBySpellId(SPELL_POLARITY_SHIFT)) // delay until shift is over
+ events.Repeat(Seconds(3));
+ else
+ {
me->CastStop();
- DoCast(me, SPELL_BERSERK);
- break;
- default:
- break;
- }
+ DoCastVictim(SPELL_CHAIN_LIGHTNING);
+ events.Repeat(randtime(Seconds(10), Seconds(20)));
+ }
+ break;
+ case EVENT_BERSERK:
+ me->CastStop();
+ DoCast(me, SPELL_BERSERK);
+ break;
+ default:
+ break;
}
- if (events.IsInPhase(PHASE_THADDIUS) && !me->HasUnitState(UNIT_STATE_CASTING) && me->isAttackReady())
+ }
+ if (events.IsInPhase(PHASE_THADDIUS) && !me->HasUnitState(UNIT_STATE_CASTING) && me->isAttackReady())
+ {
+ if (me->IsWithinMeleeRange(me->GetVictim()))
{
- if (me->IsWithinMeleeRange(me->GetVictim()))
- {
- ballLightningEnabled = false;
- DoMeleeAttackIfReady();
- }
- else if (ballLightningUnlocked)
- if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM))
- DoCast(target, SPELL_BALL_LIGHTNING);
+ ballLightningEnabled = false;
+ DoMeleeAttackIfReady();
}
+ else if (ballLightningUnlocked)
+ if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM))
+ DoCast(target, SPELL_BALL_LIGHTNING);
}
+ }
- private:
- bool stalaggAlive;
- bool feugenAlive;
- bool ballLightningUnlocked; // whether the initial ball lightning grace period has expired and we should proceed to exterminate with extreme prejudice
- bool ballLightningEnabled; // switch that is flipped to true if we try to evade due to no eligible targets in melee range
- bool shockingEligibility;
- };
-
+ private:
+ bool stalaggAlive;
+ bool feugenAlive;
+ bool ballLightningUnlocked; // whether the initial ball lightning grace period has expired and we should proceed to exterminate with extreme prejudice
+ bool ballLightningEnabled; // switch that is flipped to true if we try to evade due to no eligible targets in melee range
+ bool shockingEligibility;
};
class npc_stalagg : public CreatureScript
@@ -1307,7 +1295,7 @@ class achievement_thaddius_shocking : public AchievementCriteriaScript
void AddSC_boss_thaddius()
{
- new boss_thaddius();
+ RegisterNaxxramasCreatureAI(boss_thaddius);
new npc_stalagg();
new npc_feugen();
new npc_tesla();
diff --git a/src/server/scripts/Northrend/Naxxramas/naxxramas.h b/src/server/scripts/Northrend/Naxxramas/naxxramas.h
index 3b6d257f7cf..997d40be2e0 100644
--- a/src/server/scripts/Northrend/Naxxramas/naxxramas.h
+++ b/src/server/scripts/Northrend/Naxxramas/naxxramas.h
@@ -223,5 +223,6 @@ inline AI* GetNaxxramasAI(T* obj)
{
return GetInstanceAI<AI>(obj, NaxxramasScriptName);
}
+#define RegisterNaxxramasCreatureAI(ai_name) RegisterCreatureAIWithFactory(ai_name, GetNaxxramasAI)
#endif
diff --git a/src/server/scripts/Spells/spell_item.cpp b/src/server/scripts/Spells/spell_item.cpp
index 1a721521ae0..1c229714dd5 100644
--- a/src/server/scripts/Spells/spell_item.cpp
+++ b/src/server/scripts/Spells/spell_item.cpp
@@ -3305,43 +3305,32 @@ enum TeachLanguage
SPELL_LEARN_GOBLIN_BINARY = 50246,
};
-class spell_item_teach_language : public SpellScriptLoader
+class spell_item_teach_language : public SpellScript
{
- public:
- spell_item_teach_language() : SpellScriptLoader("spell_item_teach_language") { }
-
- class spell_item_teach_language_SpellScript : public SpellScript
- {
- PrepareSpellScript(spell_item_teach_language_SpellScript);
-
- bool Load() override
- {
- return GetCaster()->GetTypeId() == TYPEID_PLAYER;
- }
+ PrepareSpellScript(spell_item_teach_language);
- bool Validate(SpellInfo const* /*spell*/) override
- {
- return ValidateSpellInfo({ SPELL_LEARN_GNOMISH_BINARY, SPELL_LEARN_GOBLIN_BINARY });
- }
+ bool Load() override
+ {
+ return GetCaster()->GetTypeId() == TYPEID_PLAYER;
+ }
- void HandleDummy(SpellEffIndex /* effIndex */)
- {
- Player* caster = GetCaster()->ToPlayer();
+ bool Validate(SpellInfo const* /*spell*/) override
+ {
+ return ValidateSpellInfo({ SPELL_LEARN_GNOMISH_BINARY, SPELL_LEARN_GOBLIN_BINARY });
+ }
- if (roll_chance_i(34))
- caster->CastSpell(caster, caster->GetTeam() == ALLIANCE ? SPELL_LEARN_GNOMISH_BINARY : SPELL_LEARN_GOBLIN_BINARY, true);
- }
+ void HandleDummy(SpellEffIndex /* effIndex */)
+ {
+ Player* caster = GetCaster()->ToPlayer();
- void Register() override
- {
- OnEffectHitTarget += SpellEffectFn(spell_item_teach_language_SpellScript::HandleDummy, EFFECT_0, SPELL_EFFECT_DUMMY);
- }
- };
+ if (roll_chance_i(34))
+ caster->CastSpell(caster, caster->GetTeam() == ALLIANCE ? SPELL_LEARN_GNOMISH_BINARY : SPELL_LEARN_GOBLIN_BINARY, true);
+ }
- SpellScript* GetSpellScript() const override
- {
- return new spell_item_teach_language_SpellScript();
- }
+ void Register() override
+ {
+ OnEffectHitTarget += SpellEffectFn(spell_item_teach_language::HandleDummy, EFFECT_0, SPELL_EFFECT_DUMMY);
+ }
};
enum RocketBoots
@@ -4608,7 +4597,7 @@ void AddSC_item_spell_scripts()
new spell_item_impale_leviroth();
new spell_item_brewfest_mount_transformation();
new spell_item_nitro_boots();
- new spell_item_teach_language();
+ RegisterSpellScript(spell_item_teach_language);
new spell_item_rocket_boots();
new spell_item_pygmy_oil();
new spell_item_unusual_compass();