diff options
author | offl <11556157+offl@users.noreply.github.com> | 2021-04-13 10:33:36 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-04-13 09:33:36 +0200 |
commit | 07fe74b2333567d0c51b22e587396ddc70da1ffb (patch) | |
tree | 029a74004d58138a5be55e493fd47432257facf1 | |
parent | 2cbfb784e047f5711bb543de38c9760ff84b9dd7 (diff) |
Scripts/Naxxramas: Update Thaddius to new model (#26391)
Co-authored-by: offl <offl@users.noreply.github.com>
-rw-r--r-- | src/server/scripts/Northrend/Naxxramas/boss_thaddius.cpp | 1693 |
1 files changed, 813 insertions, 880 deletions
diff --git a/src/server/scripts/Northrend/Naxxramas/boss_thaddius.cpp b/src/server/scripts/Northrend/Naxxramas/boss_thaddius.cpp index 516a3b6aa92..4fc258739a7 100644 --- a/src/server/scripts/Northrend/Naxxramas/boss_thaddius.cpp +++ b/src/server/scripts/Northrend/Naxxramas/boss_thaddius.cpp @@ -159,1057 +159,990 @@ enum ThaddiusSpells struct boss_thaddius : public BossAI { - public: - boss_thaddius(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); } + } - 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 JustAppeared() override + void JustAppeared() override + { + if (instance->GetBossState(BOSS_THADDIUS) != DONE) + ResetEncounter(); + } + + void JustDied(Unit* /*killer*/) override + { + _JustDied(); + me->setActive(false); + me->SetFarVisible(false); + if (Creature* stalagg = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_STALAGG))) { - if (instance->GetBossState(BOSS_THADDIUS) != DONE) - ResetEncounter(); + stalagg->setActive(false); + stalagg->SetFarVisible(false); } - - void JustDied(Unit* /*killer*/) override + if (Creature* feugen = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_FEUGEN))) { - _JustDied(); - me->setActive(false); - me->SetFarVisible(false); - if (Creature* stalagg = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_STALAGG))) - { - stalagg->setActive(false); - stalagg->SetFarVisible(false); - } - if (Creature* feugen = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_FEUGEN))) - { - feugen->setActive(false); - feugen->SetFarVisible(false); - } - Talk(SAY_DEATH); + feugen->setActive(false); + feugen->SetFarVisible(false); } + Talk(SAY_DEATH); + } - void DoAction(int32 action) override + void DoAction(int32 action) override + { + switch (action) { - switch (action) - { - case ACTION_FEUGEN_RESET: - case ACTION_STALAGG_RESET: - if (!events.IsInPhase(PHASE_NOT_ENGAGED)) - BeginResetEncounter(); - break; - case ACTION_FEUGEN_AGGRO: - case ACTION_STALAGG_AGGRO: - if (!events.IsInPhase(PHASE_NOT_ENGAGED)) - return; - events.SetPhase(PHASE_PETS); + case ACTION_FEUGEN_RESET: + case ACTION_STALAGG_RESET: + if (!events.IsInPhase(PHASE_NOT_ENGAGED)) + BeginResetEncounter(); + break; + case ACTION_FEUGEN_AGGRO: + case ACTION_STALAGG_AGGRO: + if (!events.IsInPhase(PHASE_NOT_ENGAGED)) + return; + events.SetPhase(PHASE_PETS); - shockingEligibility = true; + shockingEligibility = true; - if (!instance->CheckRequiredBosses(BOSS_THADDIUS)) - { - BeginResetEncounter(); - return; - } - instance->SetBossState(BOSS_THADDIUS, IN_PROGRESS); + if (!instance->CheckRequiredBosses(BOSS_THADDIUS)) + { + BeginResetEncounter(); + return; + } + instance->SetBossState(BOSS_THADDIUS, IN_PROGRESS); - me->setActive(true); - me->SetFarVisible(true); - DoZoneInCombat(); - if (Creature* stalagg = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_STALAGG))) - { - stalagg->setActive(true); - stalagg->SetFarVisible(true); - } - if (Creature* feugen = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_FEUGEN))) - { - feugen->setActive(true); - feugen->SetFarVisible(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, 5s, 0, PHASE_PETS); - else - Transition(); + me->setActive(true); + me->SetFarVisible(true); + DoZoneInCombat(); + if (Creature* stalagg = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_STALAGG))) + { + stalagg->setActive(true); + stalagg->SetFarVisible(true); + } + if (Creature* feugen = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_FEUGEN))) + { + feugen->setActive(true); + feugen->SetFarVisible(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, 5s, 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, 5s, 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, 5s, 0, PHASE_PETS); + else + Transition(); - break; + break; - case ACTION_POLARITY_CROSSED: - shockingEligibility = false; - break; - default: - break; - } + case ACTION_POLARITY_CROSSED: + shockingEligibility = false; + break; + default: + break; } + } - uint32 GetData(uint32 id) const override - { - return (id == DATA_POLARITY_CROSSED && shockingEligibility) ? 1u : 0u; - } + uint32 GetData(uint32 id) const override + { + return (id == DATA_POLARITY_CROSSED && shockingEligibility) ? 1u : 0u; + } - void Transition() // initiate transition between pet phase and thaddius phase - { - events.SetPhase(PHASE_TRANSITION); + void Transition() // initiate transition between pet phase and thaddius phase + { + events.SetPhase(PHASE_TRANSITION); - me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - events.ScheduleEvent(EVENT_TRANSITION_1, 10s, 0, PHASE_TRANSITION); - events.ScheduleEvent(EVENT_TRANSITION_2, 12s, 0, PHASE_TRANSITION); - events.ScheduleEvent(EVENT_TRANSITION_3, 14s, 0, PHASE_TRANSITION); - } + events.ScheduleEvent(EVENT_TRANSITION_1, 10s, 0, PHASE_TRANSITION); + events.ScheduleEvent(EVENT_TRANSITION_2, 12s, 0, PHASE_TRANSITION); + events.ScheduleEvent(EVENT_TRANSITION_3, 14s, 0, PHASE_TRANSITION); + } - void BeginResetEncounter() - { - if (instance->GetBossState(BOSS_THADDIUS) == DONE) - return; + void BeginResetEncounter() + { + if (instance->GetBossState(BOSS_THADDIUS) == DONE) + return; + + // remove polarity shift debuffs on reset + instance->DoRemoveAurasDueToSpellOnPlayers(SPELL_POSITIVE_CHARGE_APPLY); + instance->DoRemoveAurasDueToSpellOnPlayers(SPELL_NEGATIVE_CHARGE_APPLY); + + me->DespawnOrUnsummon(0s, 30s); + + me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_STUNNED); + me->SetImmuneToPC(true); + me->setActive(false); + me->SetFarVisible(false); + 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); + } - // remove polarity shift debuffs on reset - instance->DoRemoveAurasDueToSpellOnPlayers(SPELL_POSITIVE_CHARGE_APPLY); - instance->DoRemoveAurasDueToSpellOnPlayers(SPELL_NEGATIVE_CHARGE_APPLY); + void ResetEncounter() + { + feugenAlive = true; + stalaggAlive = true; - me->DespawnOrUnsummon(0s, 30s); + _Reset(); + events.SetPhase(PHASE_NOT_ENGAGED); + me->SetReactState(REACT_PASSIVE); - me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_STUNNED); - me->SetImmuneToPC(true); - me->setActive(false); - me->SetFarVisible(false); - 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); - } + // @todo these guys should really be moved to a summon group - this is merely a hack to make them work in dynamic_spawning + instance->instance->Respawn(SPAWN_TYPE_CREATURE, 130958); // Stalagg + instance->instance->Respawn(SPAWN_TYPE_CREATURE, 130959); // Feugen + } + + void UpdateAI(uint32 diff) override + { + if (events.IsInPhase(PHASE_NOT_ENGAGED)) + return; + if (events.IsInPhase(PHASE_THADDIUS) && !UpdateVictim()) + return; - void ResetEncounter() + events.Update(diff); + while (uint32 eventId = events.ExecuteEvent()) { - feugenAlive = true; - stalaggAlive = true; + 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->SetImmuneToPC(false); + DoZoneInCombat(); - _Reset(); - events.SetPhase(PHASE_NOT_ENGAGED); - me->SetReactState(REACT_PASSIVE); + 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); - // @todo these guys should really be moved to a summon group - this is merely a hack to make them work in dynamic_spawning - instance->instance->Respawn(SPAWN_TYPE_CREATURE, 130958); // Stalagg - instance->instance->Respawn(SPAWN_TYPE_CREATURE, 130959); // Feugen - } + events.SetPhase(PHASE_THADDIUS); - void UpdateAI(uint32 diff) override - { - if (events.IsInPhase(PHASE_NOT_ENGAGED)) - return; - if (events.IsInPhase(PHASE_THADDIUS) && !UpdateVictim()) - return; + Talk(SAY_AGGRO); - events.Update(diff); - while (uint32 eventId = events.ExecuteEvent()) - { - 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->SetImmuneToPC(false); - DoZoneInCombat(); - - 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); - - Talk(SAY_AGGRO); - - events.ScheduleEvent(EVENT_ENGAGE, 2s, 0, PHASE_THADDIUS); - events.ScheduleEvent(EVENT_ENABLE_BALL_LIGHTNING, 5s, 0, PHASE_THADDIUS); - events.ScheduleEvent(EVENT_SHIFT, 10s, 0, PHASE_THADDIUS); - events.ScheduleEvent(EVENT_CHAIN, 10s, 20s, 0, PHASE_THADDIUS); - events.ScheduleEvent(EVENT_BERSERK, 6min, 0, PHASE_THADDIUS); - - break; - case EVENT_ENABLE_BALL_LIGHTNING: - ballLightningUnlocked = true; - break; - case EVENT_ENGAGE: - me->SetReactState(REACT_AGGRESSIVE); - break; - case EVENT_SHIFT: - me->CastStop(); // shift overrides all other spells - DoCastAOE(SPELL_POLARITY_SHIFT); - events.ScheduleEvent(EVENT_SHIFT_TALK, 3s, PHASE_THADDIUS); - events.ScheduleEvent(EVENT_SHIFT, 30s, 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: + events.ScheduleEvent(EVENT_ENGAGE, 2s, 0, PHASE_THADDIUS); + events.ScheduleEvent(EVENT_ENABLE_BALL_LIGHTNING, 5s, 0, PHASE_THADDIUS); + events.ScheduleEvent(EVENT_SHIFT, 10s, 0, PHASE_THADDIUS); + events.ScheduleEvent(EVENT_CHAIN, 10s, 20s, 0, PHASE_THADDIUS); + events.ScheduleEvent(EVENT_BERSERK, 6min, 0, PHASE_THADDIUS); + + break; + case EVENT_ENABLE_BALL_LIGHTNING: + ballLightningUnlocked = true; + break; + case EVENT_ENGAGE: + me->SetReactState(REACT_AGGRESSIVE); + break; + case EVENT_SHIFT: + me->CastStop(); // shift overrides all other spells + DoCastAOE(SPELL_POLARITY_SHIFT); + events.ScheduleEvent(EVENT_SHIFT_TALK, 3s, PHASE_THADDIUS); + events.ScheduleEvent(EVENT_SHIFT, 30s, 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(SelectTargetMethod::Random)) - DoCast(target, SPELL_BALL_LIGHTNING); + ballLightningEnabled = false; + DoMeleeAttackIfReady(); } + else if (ballLightningUnlocked) + if (Unit* target = SelectTarget(SelectTargetMethod::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 +struct npc_stalagg : public ScriptedAI { public: - npc_stalagg() : CreatureScript("npc_stalagg") { } + npc_stalagg(Creature* creature) : ScriptedAI(creature), + instance(creature->GetInstanceScript()), powerSurgeTimer(), _myCoil(ObjectGuid::Empty), _myCoilGO(ObjectGuid::Empty), isOverloading(false), refreshBeam(false), isFeignDeath(false) + { + instance = creature->GetInstanceScript(); + SetBoundary(instance->GetBossBoundary(BOSS_THADDIUS)); + } - CreatureAI* GetAI(Creature* creature) const override + void InitializeAI() override { - return GetNaxxramasAI<npc_stalaggAI>(creature); + if (GameObject* coil = myCoilGO()) + coil->SetGoState(GO_STATE_ACTIVE); + + powerSurgeTimer = 10 * IN_MILLISECONDS; + + // force tesla coil state refresh + refreshBeam = true; } - struct npc_stalaggAI : public ScriptedAI + void EnterEvadeMode(EvadeReason /*reason*/) override { - public: - npc_stalaggAI(Creature* creature) : ScriptedAI(creature), - instance(creature->GetInstanceScript()), powerSurgeTimer(), _myCoil(ObjectGuid::Empty), _myCoilGO(ObjectGuid::Empty), isOverloading(false), refreshBeam(false), isFeignDeath(false) - { - instance = creature->GetInstanceScript(); - SetBoundary(instance->GetBossBoundary(BOSS_THADDIUS)); - } + if (Creature* thaddius = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_THADDIUS))) + thaddius->AI()->DoAction(ACTION_STALAGG_RESET); + } - void InitializeAI() override - { - if (GameObject* coil = myCoilGO()) - coil->SetGoState(GO_STATE_ACTIVE); + void BeginResetEncounter() + { + if (GameObject* coil = myCoilGO()) + coil->SetGoState(GO_STATE_READY); + me->DespawnOrUnsummon(0s, 7_days); // will be force respawned by thaddius + } - powerSurgeTimer = 10 * IN_MILLISECONDS; + void DoAction(int32 action) override + { + switch (action) + { + case ACTION_BEGIN_RESET_ENCOUNTER: + BeginResetEncounter(); + break; + case ACTION_STALAGG_REVIVING_FX: + break; + case ACTION_STALAGG_REVIVED: + if (!isFeignDeath) + break; - // force tesla coil state refresh - refreshBeam = true; - } + me->SetFullHealth(); + me->SetStandState(UNIT_STAND_STATE_STAND); + me->SetReactState(REACT_AGGRESSIVE); + me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + me->SetControlled(false, UNIT_STATE_ROOT); + Talk(EMOTE_FEIGN_REVIVE); + isFeignDeath = false; - void EnterEvadeMode(EvadeReason /*reason*/) override - { - if (Creature* thaddius = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_THADDIUS))) - thaddius->AI()->DoAction(ACTION_STALAGG_RESET); - } + refreshBeam = true; // force beam refresh - void BeginResetEncounter() - { - if (GameObject* coil = myCoilGO()) - coil->SetGoState(GO_STATE_READY); - me->DespawnOrUnsummon(0s, 7_days); // will be force respawned by thaddius - } + DoZoneInCombat(); + if (!me->IsEngaged()) + BeginResetEncounter(); + break; + case ACTION_TRANSITION: + me->KillSelf(); // true death - void DoAction(int32 action) override - { - switch (action) + if (Creature* coil = myCoil()) { - case ACTION_BEGIN_RESET_ENCOUNTER: - BeginResetEncounter(); - break; - case ACTION_STALAGG_REVIVING_FX: - break; - case ACTION_STALAGG_REVIVED: - if (!isFeignDeath) - break; - - me->SetFullHealth(); - me->SetStandState(UNIT_STAND_STATE_STAND); - me->SetReactState(REACT_AGGRESSIVE); - me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - me->SetControlled(false, UNIT_STATE_ROOT); - Talk(EMOTE_FEIGN_REVIVE); - isFeignDeath = false; - - refreshBeam = true; // force beam refresh - - DoZoneInCombat(); - if (!me->IsEngaged()) - BeginResetEncounter(); - break; - case ACTION_TRANSITION: - me->KillSelf(); // true death - - if (Creature* coil = myCoil()) - { - coil->CastStop(); - coil->AI()->Talk(EMOTE_TESLA_OVERLOAD); - } - break; - case ACTION_TRANSITION_2: - if (Creature* coil = myCoil()) - if (Creature* thaddius = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_THADDIUS))) - coil->CastSpell(thaddius, SPELL_SHOCK_VISUAL); - break; - case ACTION_TRANSITION_3: - if (GameObject* coil = myCoilGO()) - coil->SetGoState(GO_STATE_READY); - me->DespawnOrUnsummon(0s, 7_days); - break; - default: - break; + coil->CastStop(); + coil->AI()->Talk(EMOTE_TESLA_OVERLOAD); } - } + break; + case ACTION_TRANSITION_2: + if (Creature* coil = myCoil()) + if (Creature* thaddius = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_THADDIUS))) + coil->CastSpell(thaddius, SPELL_SHOCK_VISUAL); + break; + case ACTION_TRANSITION_3: + if (GameObject* coil = myCoilGO()) + coil->SetGoState(GO_STATE_READY); + me->DespawnOrUnsummon(0s, 7_days); + break; + default: + break; + } + } - void KilledUnit(Unit* victim) override - { - if (victim->GetTypeId() == TYPEID_PLAYER) - Talk(SAY_STALAGG_SLAY); - } + void KilledUnit(Unit* victim) override + { + if (victim->GetTypeId() == TYPEID_PLAYER) + Talk(SAY_STALAGG_SLAY); + } - void JustEngagedWith(Unit* who) override - { - Talk(SAY_STALAGG_AGGRO); + void JustEngagedWith(Unit* who) override + { + Talk(SAY_STALAGG_AGGRO); - if (Creature* thaddius = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_THADDIUS))) - thaddius->AI()->DoAction(ACTION_STALAGG_AGGRO); + if (Creature* thaddius = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_THADDIUS))) + thaddius->AI()->DoAction(ACTION_STALAGG_AGGRO); - if (Creature* feugen = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_FEUGEN))) - if (!feugen->IsEngaged()) - AddThreat(who, 0.0f, feugen); - } + if (Creature* feugen = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_FEUGEN))) + if (!feugen->IsEngaged()) + AddThreat(who, 0.0f, feugen); + } - void DamageTaken(Unit* /*who*/, uint32& damage) override - { - if (damage < me->GetHealth()) - return; + void DamageTaken(Unit* /*who*/, uint32& damage) override + { + if (damage < me->GetHealth()) + return; - if (isFeignDeath) // don't take damage while feigning death - { - damage = 0; - return; - } + if (isFeignDeath) // don't take damage while feigning death + { + damage = 0; + return; + } - isFeignDeath = true; - isOverloading = false; + isFeignDeath = true; + isOverloading = false; - Talk(EMOTE_FEIGN_DEATH); - if (Creature* thaddius = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_THADDIUS))) - thaddius->AI()->DoAction(ACTION_STALAGG_DIED); + Talk(EMOTE_FEIGN_DEATH); + if (Creature* thaddius = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_THADDIUS))) + thaddius->AI()->DoAction(ACTION_STALAGG_DIED); - me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - me->RemoveAllAuras(); - me->SetReactState(REACT_PASSIVE); - me->AttackStop(); - me->SetControlled(true, UNIT_STATE_ROOT); - me->SetStandState(UNIT_STAND_STATE_DEAD); + me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + me->RemoveAllAuras(); + me->SetReactState(REACT_PASSIVE); + me->AttackStop(); + me->SetControlled(true, UNIT_STATE_ROOT); + me->SetStandState(UNIT_STAND_STATE_DEAD); - damage = me->GetHealth()-1; + damage = me->GetHealth()-1; - // force beam refresh as we just removed auras - refreshBeam = true; - } + // force beam refresh as we just removed auras + refreshBeam = true; + } - void SpellHit(WorldObject* caster, SpellInfo const* spellInfo) override - { - Creature* creatureCaster = caster->ToCreature(); - if (!creatureCaster) - return; + void SpellHit(WorldObject* caster, SpellInfo const* spellInfo) override + { + Creature* creatureCaster = caster->ToCreature(); + if (!creatureCaster) + return; - if (spellInfo->Id != SPELL_STALAGG_TESLA_PERIODIC) - return; - if (!isFeignDeath && me->IsInCombat() && !me->GetHomePosition().IsInDist(me, OVERLOAD_DISTANCE)) - { - if (!isOverloading) - { - isOverloading = true; - creatureCaster->SetImmuneToPC(false); - creatureCaster->AI()->Talk(EMOTE_TESLA_LINK_BREAKS); - me->RemoveAura(SPELL_STALAGG_CHAIN_VISUAL); - } - if (Unit* target = SelectTarget(SelectTargetMethod::Random)) - { - creatureCaster->CastStop(SPELL_TESLA_SHOCK); - creatureCaster->CastSpell(target, SPELL_TESLA_SHOCK,true); - } - } - else if (isOverloading || refreshBeam) - { - isOverloading = false; - refreshBeam = false; - creatureCaster->CastStop(); - creatureCaster->CastSpell(me, SPELL_STALAGG_CHAIN_VISUAL, true); - creatureCaster->SetImmuneToPC(true); - } + if (spellInfo->Id != SPELL_STALAGG_TESLA_PERIODIC) + return; + if (!isFeignDeath && me->IsInCombat() && !me->GetHomePosition().IsInDist(me, OVERLOAD_DISTANCE)) + { + if (!isOverloading) + { + isOverloading = true; + creatureCaster->SetImmuneToPC(false); + creatureCaster->AI()->Talk(EMOTE_TESLA_LINK_BREAKS); + me->RemoveAura(SPELL_STALAGG_CHAIN_VISUAL); } - - void UpdateAI(uint32 uiDiff) override + if (Unit* target = SelectTarget(SelectTargetMethod::Random)) { - if (!isFeignDeath) - if (!UpdateVictim()) - return; - - if (powerSurgeTimer <= uiDiff) - { - if (isFeignDeath) // delay until potential revive - powerSurgeTimer = 0u; - else - { - DoCast(me, SPELL_STALAGG_POWERSURGE); - powerSurgeTimer = urandms(25, 30); - } - } - else - powerSurgeTimer -= uiDiff; - - if (!isFeignDeath) - DoMeleeAttackIfReady(); + creatureCaster->CastStop(SPELL_TESLA_SHOCK); + creatureCaster->CastSpell(target, SPELL_TESLA_SHOCK,true); } + } + else if (isOverloading || refreshBeam) + { + isOverloading = false; + refreshBeam = false; + creatureCaster->CastStop(); + creatureCaster->CastSpell(me, SPELL_STALAGG_CHAIN_VISUAL, true); + creatureCaster->SetImmuneToPC(true); + } + } + + void UpdateAI(uint32 uiDiff) override + { + if (!isFeignDeath) + if (!UpdateVictim()) + return; - private: - Creature* myCoil() + if (powerSurgeTimer <= uiDiff) + { + if (isFeignDeath) // delay until potential revive + powerSurgeTimer = 0u; + else { - Creature* coil = nullptr; - if (_myCoil) - coil = ObjectAccessor::GetCreature(*me, _myCoil); - if (!coil) - { - coil = me->FindNearestCreature(NPC_TESLA, 1000.0f, true); - if (coil) - { - _myCoil = coil->GetGUID(); - coil->SetReactState(REACT_PASSIVE); - } - } - return coil; + DoCast(me, SPELL_STALAGG_POWERSURGE); + powerSurgeTimer = urandms(25, 30); } + } + else + powerSurgeTimer -= uiDiff; + + if (!isFeignDeath) + DoMeleeAttackIfReady(); + } - GameObject* myCoilGO() +private: + Creature* myCoil() + { + Creature* coil = nullptr; + if (_myCoil) + coil = ObjectAccessor::GetCreature(*me, _myCoil); + if (!coil) + { + coil = me->FindNearestCreature(NPC_TESLA, 1000.0f, true); + if (coil) { - GameObject* coil = nullptr; - if (_myCoilGO) - coil = ObjectAccessor::GetGameObject(*me, _myCoilGO); - if (!coil) - { - coil = me->FindNearestGameObject(GO_CONS_NOX_TESLA_STALAGG, 1000.0f); - if (coil) - _myCoilGO = coil->GetGUID(); - } - return coil; + _myCoil = coil->GetGUID(); + coil->SetReactState(REACT_PASSIVE); } + } + return coil; + } - InstanceScript* instance; + GameObject* myCoilGO() + { + GameObject* coil = nullptr; + if (_myCoilGO) + coil = ObjectAccessor::GetGameObject(*me, _myCoilGO); + if (!coil) + { + coil = me->FindNearestGameObject(GO_CONS_NOX_TESLA_STALAGG, 1000.0f); + if (coil) + _myCoilGO = coil->GetGUID(); + } + return coil; + } - uint32 powerSurgeTimer; + InstanceScript* instance; - ObjectGuid _myCoil; - ObjectGuid _myCoilGO; - bool isOverloading; - bool refreshBeam; - bool isFeignDeath; - }; + uint32 powerSurgeTimer; + ObjectGuid _myCoil; + ObjectGuid _myCoilGO; + bool isOverloading; + bool refreshBeam; + bool isFeignDeath; }; -class npc_feugen : public CreatureScript +struct npc_feugen : public ScriptedAI { public: - npc_feugen() : CreatureScript("npc_feugen") { } - - CreatureAI* GetAI(Creature* creature) const override + npc_feugen(Creature* creature) : ScriptedAI(creature), + instance(creature->GetInstanceScript()), magneticPullTimer(), staticFieldTimer(), _myCoil(ObjectGuid::Empty), _myCoilGO(ObjectGuid::Empty), isOverloading(false), refreshBeam(false), isFeignDeath(false) { - return GetNaxxramasAI<npc_feugenAI>(creature); + instance = creature->GetInstanceScript(); + SetBoundary(instance->GetBossBoundary(BOSS_THADDIUS)); } - struct npc_feugenAI : public ScriptedAI + void InitializeAI() override { - public: - npc_feugenAI(Creature* creature) : ScriptedAI(creature), - instance(creature->GetInstanceScript()), magneticPullTimer(), staticFieldTimer(), _myCoil(ObjectGuid::Empty), _myCoilGO(ObjectGuid::Empty), isOverloading(false), refreshBeam(false), isFeignDeath(false) - { - instance = creature->GetInstanceScript(); - SetBoundary(instance->GetBossBoundary(BOSS_THADDIUS)); - } + if (GameObject* coil = myCoilGO()) + coil->SetGoState(GO_STATE_ACTIVE); - void InitializeAI() override - { - if (GameObject* coil = myCoilGO()) - coil->SetGoState(GO_STATE_ACTIVE); - - staticFieldTimer = 6 * IN_MILLISECONDS; - magneticPullTimer = 20 * IN_MILLISECONDS; + staticFieldTimer = 6 * IN_MILLISECONDS; + magneticPullTimer = 20 * IN_MILLISECONDS; - // force coil state to refresh - refreshBeam = true; - } - - void EnterEvadeMode(EvadeReason /*why*/) override - { - if (Creature* thaddius = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_THADDIUS))) - thaddius->AI()->DoAction(ACTION_FEUGEN_RESET); - } + // force coil state to refresh + refreshBeam = true; + } - void BeginResetEncounter() - { - if (GameObject* coil = myCoilGO()) - coil->SetGoState(GO_STATE_READY); - me->DespawnOrUnsummon(0s, 7_days); // will be force respawned by thaddius - } + void EnterEvadeMode(EvadeReason /*why*/) override + { + if (Creature* thaddius = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_THADDIUS))) + thaddius->AI()->DoAction(ACTION_FEUGEN_RESET); + } - void DoAction(int32 action) override - { - switch (action) - { - case ACTION_BEGIN_RESET_ENCOUNTER: - BeginResetEncounter(); - break; - case ACTION_FEUGEN_REVIVING_FX: - break; - case ACTION_FEUGEN_REVIVED: - if (!isFeignDeath) - break; - - me->SetFullHealth(); - me->SetStandState(UNIT_STAND_STATE_STAND); - me->SetReactState(REACT_AGGRESSIVE); - me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - me->SetControlled(false, UNIT_STATE_ROOT); - Talk(EMOTE_FEIGN_REVIVE); - isFeignDeath = false; - - refreshBeam = true; // force beam refresh - - if (Creature* stalagg = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_STALAGG))) - if (stalagg->GetVictim()) - { - AddThreat(stalagg->EnsureVictim(), 0.0f); - me->SetInCombatWith(stalagg->EnsureVictim()); - } - staticFieldTimer = 6 * IN_MILLISECONDS; - magneticPullTimer = 30 * IN_MILLISECONDS; - break; - case ACTION_TRANSITION: - me->KillSelf(); // true death this time around - - if (Creature* coil = myCoil()) - { - coil->CastStop(); - coil->AI()->Talk(EMOTE_TESLA_OVERLOAD); - } - break; - case ACTION_TRANSITION_2: - if (Creature* coil = myCoil()) - if (Creature* thaddius = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_THADDIUS))) - coil->CastSpell(thaddius, SPELL_SHOCK_VISUAL); - break; - case ACTION_TRANSITION_3: - if (GameObject* coil = myCoilGO()) - coil->SetGoState(GO_STATE_READY); - me->DespawnOrUnsummon(0s, 7_days); - break; - default: - break; - } - } + void BeginResetEncounter() + { + if (GameObject* coil = myCoilGO()) + coil->SetGoState(GO_STATE_READY); + me->DespawnOrUnsummon(0s, 7_days); // will be force respawned by thaddius + } - void KilledUnit(Unit* victim) override - { - if (victim->GetTypeId() == TYPEID_PLAYER) - Talk(SAY_FEUGEN_SLAY); - } + void DoAction(int32 action) override + { + switch (action) + { + case ACTION_BEGIN_RESET_ENCOUNTER: + BeginResetEncounter(); + break; + case ACTION_FEUGEN_REVIVING_FX: + break; + case ACTION_FEUGEN_REVIVED: + if (!isFeignDeath) + break; - void JustEngagedWith(Unit* who) override - { - Talk(SAY_FEUGEN_AGGRO); + me->SetFullHealth(); + me->SetStandState(UNIT_STAND_STATE_STAND); + me->SetReactState(REACT_AGGRESSIVE); + me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + me->SetControlled(false, UNIT_STATE_ROOT); + Talk(EMOTE_FEIGN_REVIVE); + isFeignDeath = false; - if (Creature* thaddius = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_THADDIUS))) - thaddius->AI()->DoAction(ACTION_FEUGEN_AGGRO); + refreshBeam = true; // force beam refresh if (Creature* stalagg = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_STALAGG))) - if (!stalagg->IsInCombat()) - AddThreat(who, 0.0f, stalagg); - } - - void DamageTaken(Unit* /*who*/, uint32& damage) override - { - if (damage < me->GetHealth()) - return; + if (stalagg->GetVictim()) + { + AddThreat(stalagg->EnsureVictim(), 0.0f); + me->SetInCombatWith(stalagg->EnsureVictim()); + } + staticFieldTimer = 6 * IN_MILLISECONDS; + magneticPullTimer = 30 * IN_MILLISECONDS; + break; + case ACTION_TRANSITION: + me->KillSelf(); // true death this time around - if (isFeignDeath) // don't take damage while feigning death + if (Creature* coil = myCoil()) { - damage = 0; - return; + coil->CastStop(); + coil->AI()->Talk(EMOTE_TESLA_OVERLOAD); } + break; + case ACTION_TRANSITION_2: + if (Creature* coil = myCoil()) + if (Creature* thaddius = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_THADDIUS))) + coil->CastSpell(thaddius, SPELL_SHOCK_VISUAL); + break; + case ACTION_TRANSITION_3: + if (GameObject* coil = myCoilGO()) + coil->SetGoState(GO_STATE_READY); + me->DespawnOrUnsummon(0s, 7_days); + break; + default: + break; + } + } - isFeignDeath = true; - isOverloading = false; + void KilledUnit(Unit* victim) override + { + if (victim->GetTypeId() == TYPEID_PLAYER) + Talk(SAY_FEUGEN_SLAY); + } - Talk(EMOTE_FEIGN_DEATH); - if (Creature* thaddius = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_THADDIUS))) - thaddius->AI()->DoAction(ACTION_FEUGEN_DIED); + void JustEngagedWith(Unit* who) override + { + Talk(SAY_FEUGEN_AGGRO); - me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - me->RemoveAllAuras(); - me->SetReactState(REACT_PASSIVE); - me->AttackStop(); - me->SetControlled(true, UNIT_STATE_ROOT); - me->SetStandState(UNIT_STAND_STATE_DEAD); + if (Creature* thaddius = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_THADDIUS))) + thaddius->AI()->DoAction(ACTION_FEUGEN_AGGRO); - damage = me->GetHealth()-1; + if (Creature* stalagg = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_STALAGG))) + if (!stalagg->IsInCombat()) + AddThreat(who, 0.0f, stalagg); + } - // force beam refresh as we just removed auras - refreshBeam = true; - } + void DamageTaken(Unit* /*who*/, uint32& damage) override + { + if (damage < me->GetHealth()) + return; - void SpellHit(WorldObject* caster, SpellInfo const* spellInfo) override - { - Creature* creatureCaster = caster->ToCreature(); - if (!creatureCaster) - return; + if (isFeignDeath) // don't take damage while feigning death + { + damage = 0; + return; + } - if (spellInfo->Id != SPELL_FEUGEN_TESLA_PERIODIC) - return; + isFeignDeath = true; + isOverloading = false; - if (!isFeignDeath && me->IsInCombat() && !me->GetHomePosition().IsInDist(me, OVERLOAD_DISTANCE)) - { - if (!isOverloading) - { - isOverloading = true; - creatureCaster->SetImmuneToPC(false); - creatureCaster->AI()->Talk(EMOTE_TESLA_LINK_BREAKS); - me->RemoveAura(SPELL_STALAGG_CHAIN_VISUAL); - } - if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0)) - { - creatureCaster->CastStop(SPELL_TESLA_SHOCK); - creatureCaster->CastSpell(target, SPELL_TESLA_SHOCK,true); - } - } - else if (isOverloading || refreshBeam) - { - isOverloading = false; - refreshBeam = false; - creatureCaster->CastStop(); - creatureCaster->CastSpell(me, SPELL_FEUGEN_CHAIN_VISUAL, true); - creatureCaster->SetImmuneToPC(true); - } - } + Talk(EMOTE_FEIGN_DEATH); + if (Creature* thaddius = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_THADDIUS))) + thaddius->AI()->DoAction(ACTION_FEUGEN_DIED); - void UpdateAI(uint32 uiDiff) override - { - if (isFeignDeath) - return; - if (!UpdateVictim()) - return; + me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + me->RemoveAllAuras(); + me->SetReactState(REACT_PASSIVE); + me->AttackStop(); + me->SetControlled(true, UNIT_STATE_ROOT); + me->SetStandState(UNIT_STAND_STATE_DEAD); - if (magneticPullTimer <= uiDiff) - { - DoCast(me, SPELL_MAGNETIC_PULL); - magneticPullTimer = 20 * IN_MILLISECONDS; - } - else magneticPullTimer -= uiDiff; + damage = me->GetHealth()-1; - if (staticFieldTimer <= uiDiff) - { - DoCast(me, SPELL_FEUGEN_STATICFIELD); - staticFieldTimer = 6 * IN_MILLISECONDS; - } - else staticFieldTimer -= uiDiff; + // force beam refresh as we just removed auras + refreshBeam = true; + } - DoMeleeAttackIfReady(); - } + void SpellHit(WorldObject* caster, SpellInfo const* spellInfo) override + { + Creature* creatureCaster = caster->ToCreature(); + if (!creatureCaster) + return; - private: - Creature* myCoil() + if (spellInfo->Id != SPELL_FEUGEN_TESLA_PERIODIC) + return; + + if (!isFeignDeath && me->IsInCombat() && !me->GetHomePosition().IsInDist(me, OVERLOAD_DISTANCE)) + { + if (!isOverloading) { - Creature* coil = nullptr; - if (_myCoil) - coil = ObjectAccessor::GetCreature(*me, _myCoil); - if (!coil) - { - coil = me->FindNearestCreature(NPC_TESLA, 1000.0f, true); - if (coil) - { - _myCoil = coil->GetGUID(); - coil->SetReactState(REACT_PASSIVE); - } - } - return coil; + isOverloading = true; + creatureCaster->SetImmuneToPC(false); + creatureCaster->AI()->Talk(EMOTE_TESLA_LINK_BREAKS); + me->RemoveAura(SPELL_STALAGG_CHAIN_VISUAL); } - - GameObject* myCoilGO() + if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0)) { - GameObject* coil = nullptr; - if (_myCoilGO) - coil = ObjectAccessor::GetGameObject(*me, _myCoilGO); - if (!coil) - { - coil = me->FindNearestGameObject(GO_CONS_NOX_TESLA_FEUGEN, 1000.0f); - if (coil) - _myCoilGO = coil->GetGUID(); - } - return coil; + creatureCaster->CastStop(SPELL_TESLA_SHOCK); + creatureCaster->CastSpell(target, SPELL_TESLA_SHOCK,true); } - InstanceScript* instance; - - uint32 magneticPullTimer; - uint32 staticFieldTimer; + } + else if (isOverloading || refreshBeam) + { + isOverloading = false; + refreshBeam = false; + creatureCaster->CastStop(); + creatureCaster->CastSpell(me, SPELL_FEUGEN_CHAIN_VISUAL, true); + creatureCaster->SetImmuneToPC(true); + } + } - ObjectGuid _myCoil; - ObjectGuid _myCoilGO; + void UpdateAI(uint32 uiDiff) override + { + if (isFeignDeath) + return; + if (!UpdateVictim()) + return; - bool isOverloading; - bool refreshBeam; - bool isFeignDeath; - }; -}; + if (magneticPullTimer <= uiDiff) + { + DoCast(me, SPELL_MAGNETIC_PULL); + magneticPullTimer = 20 * IN_MILLISECONDS; + } + else magneticPullTimer -= uiDiff; -class npc_tesla : public CreatureScript -{ -public: - npc_tesla() : CreatureScript("npc_tesla") { } + if (staticFieldTimer <= uiDiff) + { + DoCast(me, SPELL_FEUGEN_STATICFIELD); + staticFieldTimer = 6 * IN_MILLISECONDS; + } + else staticFieldTimer -= uiDiff; - CreatureAI* GetAI(Creature* creature) const override - { - return GetNaxxramasAI<npc_teslaAI>(creature); + DoMeleeAttackIfReady(); } - struct npc_teslaAI : public ScriptedAI +private: + Creature* myCoil() { - 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) override { damage = 0; } // no, you can't kill it - }; -}; - -class spell_thaddius_polarity_charge : public SpellScriptLoader -{ - public: - spell_thaddius_polarity_charge() : SpellScriptLoader("spell_thaddius_polarity_charge") { } - - class spell_thaddius_polarity_charge_SpellScript : public SpellScript + Creature* coil = nullptr; + if (_myCoil) + coil = ObjectAccessor::GetCreature(*me, _myCoil); + if (!coil) { - PrepareSpellScript(spell_thaddius_polarity_charge_SpellScript); - - bool Validate(SpellInfo const* /*spell*/) override + coil = me->FindNearestCreature(NPC_TESLA, 1000.0f, true); + if (coil) { - return ValidateSpellInfo( - { - SPELL_POLARITY_SHIFT, - SPELL_POSITIVE_CHARGE_APPLY, - SPELL_POSITIVE_CHARGE_TICK, - SPELL_POSITIVE_CHARGE_AMP, - SPELL_NEGATIVE_CHARGE_APPLY, - SPELL_NEGATIVE_CHARGE_TICK, - SPELL_NEGATIVE_CHARGE_AMP - }); + _myCoil = coil->GetGUID(); + coil->SetReactState(REACT_PASSIVE); } + } + return coil; + } - void HandleTargets(std::list<WorldObject*>& targetList) - { - if (!GetTriggeringSpell()) - return; - - uint32 triggeringId = GetTriggeringSpell()->Id; - uint32 ampId; - switch (triggeringId) - { - case SPELL_POSITIVE_CHARGE_APPLY: - ampId = SPELL_POSITIVE_CHARGE_AMP; - break; - case SPELL_NEGATIVE_CHARGE_APPLY: - ampId = SPELL_NEGATIVE_CHARGE_AMP; - break; - default: - return; - } + GameObject* myCoilGO() + { + GameObject* coil = nullptr; + if (_myCoilGO) + coil = ObjectAccessor::GetGameObject(*me, _myCoilGO); + if (!coil) + { + coil = me->FindNearestGameObject(GO_CONS_NOX_TESLA_FEUGEN, 1000.0f); + if (coil) + _myCoilGO = coil->GetGUID(); + } + return coil; + } + InstanceScript* instance; - uint8 maxStacks = 0; - if (GetCaster()) - switch (GetCaster()->GetMap()->GetDifficulty()) - { - case RAID_DIFFICULTY_10MAN_NORMAL: - maxStacks = MAX_POLARITY_10M; - break; - case RAID_DIFFICULTY_25MAN_NORMAL: - maxStacks = MAX_POLARITY_25M; - break; - default: - break; - } + uint32 magneticPullTimer; + uint32 staticFieldTimer; - uint8 stacksCount = 1; // do we get a stack for our own debuff? - std::list<WorldObject*>::iterator it = targetList.begin(); - while(it != targetList.end()) - { - if ((*it)->GetTypeId() != TYPEID_PLAYER) - { - it = targetList.erase(it); - continue; - } - if ((*it)->ToPlayer()->HasAura(triggeringId)) - { - it = targetList.erase(it); - if (stacksCount < maxStacks) - stacksCount++; - continue; - } + ObjectGuid _myCoil; + ObjectGuid _myCoilGO; - // this guy will get hit - achievement failure trigger - if (Creature* thaddius = (*it)->FindNearestCreature(NPC_THADDIUS, 200.0f)) - thaddius->AI()->DoAction(ACTION_POLARITY_CROSSED); + bool isOverloading; + bool refreshBeam; + bool isFeignDeath; +}; - ++it; - } +struct npc_tesla : public ScriptedAI +{ + npc_tesla(Creature* creature) : ScriptedAI(creature) { } - if (GetCaster() && GetCaster()->ToPlayer()) - { - if (!GetCaster()->ToPlayer()->HasAura(ampId)) - GetCaster()->ToPlayer()->AddAura(ampId, GetCaster()); - GetCaster()->ToPlayer()->SetAuraStack(ampId, GetCaster(), stacksCount); - } - } + 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) override { damage = 0; } // no, you can't kill it +}; - void Register() override - { - OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_thaddius_polarity_charge_SpellScript::HandleTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ALLY); - } - }; +class spell_thaddius_polarity_charge : public SpellScript +{ + PrepareSpellScript(spell_thaddius_polarity_charge); - SpellScript* GetSpellScript() const override + bool Validate(SpellInfo const* /*spell*/) override + { + return ValidateSpellInfo( { - return new spell_thaddius_polarity_charge_SpellScript(); - } -}; + SPELL_POLARITY_SHIFT, + SPELL_POSITIVE_CHARGE_APPLY, + SPELL_POSITIVE_CHARGE_TICK, + SPELL_POSITIVE_CHARGE_AMP, + SPELL_NEGATIVE_CHARGE_APPLY, + SPELL_NEGATIVE_CHARGE_TICK, + SPELL_NEGATIVE_CHARGE_AMP + }); + } -class spell_thaddius_polarity_shift : public SpellScriptLoader -{ - public: - spell_thaddius_polarity_shift() : SpellScriptLoader("spell_thaddius_polarity_shift") { } + void HandleTargets(std::list<WorldObject*>& targetList) + { + if (!GetTriggeringSpell()) + return; - class spell_thaddius_polarity_shift_SpellScript : public SpellScript + uint32 triggeringId = GetTriggeringSpell()->Id; + uint32 ampId; + switch (triggeringId) { - PrepareSpellScript(spell_thaddius_polarity_shift_SpellScript); + case SPELL_POSITIVE_CHARGE_APPLY: + ampId = SPELL_POSITIVE_CHARGE_AMP; + break; + case SPELL_NEGATIVE_CHARGE_APPLY: + ampId = SPELL_NEGATIVE_CHARGE_AMP; + break; + default: + return; + } - bool Validate(SpellInfo const* /*spell*/) override + uint8 maxStacks = 0; + if (GetCaster()) + switch (GetCaster()->GetMap()->GetDifficulty()) { - return ValidateSpellInfo( - { - SPELL_POLARITY_SHIFT, - SPELL_POSITIVE_CHARGE_APPLY, - SPELL_POSITIVE_CHARGE_TICK, - SPELL_POSITIVE_CHARGE_AMP, - SPELL_NEGATIVE_CHARGE_APPLY, - SPELL_NEGATIVE_CHARGE_TICK, - SPELL_NEGATIVE_CHARGE_AMP - }); + case RAID_DIFFICULTY_10MAN_NORMAL: + maxStacks = MAX_POLARITY_10M; + break; + case RAID_DIFFICULTY_25MAN_NORMAL: + maxStacks = MAX_POLARITY_25M; + break; + default: + break; } - void HandleDummy(SpellEffIndex /*effIndex*/) + uint8 stacksCount = 1; // do we get a stack for our own debuff? + std::list<WorldObject*>::iterator it = targetList.begin(); + while(it != targetList.end()) + { + if ((*it)->GetTypeId() != TYPEID_PLAYER) { - if (Unit* target = GetHitUnit()) - if (target->GetTypeId() == TYPEID_PLAYER) - { - if (roll_chance_i(50)) - { // positive - target->CastSpell(target, SPELL_POSITIVE_CHARGE_APPLY, true); - target->RemoveAura(SPELL_POSITIVE_CHARGE_AMP); - } - else - { // negative - target->CastSpell(target, SPELL_NEGATIVE_CHARGE_APPLY, true); - target->RemoveAura(SPELL_NEGATIVE_CHARGE_AMP); - } - } + it = targetList.erase(it); + continue; } - - void Register() override + if ((*it)->ToPlayer()->HasAura(triggeringId)) { - OnEffectHitTarget += SpellEffectFn(spell_thaddius_polarity_shift_SpellScript::HandleDummy, EFFECT_0, SPELL_EFFECT_DUMMY); + it = targetList.erase(it); + if (stacksCount < maxStacks) + stacksCount++; + continue; } - }; - SpellScript* GetSpellScript() const override + // this guy will get hit - achievement failure trigger + if (Creature* thaddius = (*it)->FindNearestCreature(NPC_THADDIUS, 200.0f)) + thaddius->AI()->DoAction(ACTION_POLARITY_CROSSED); + + ++it; + } + + if (GetCaster() && GetCaster()->ToPlayer()) { - return new spell_thaddius_polarity_shift_SpellScript(); + if (!GetCaster()->ToPlayer()->HasAura(ampId)) + GetCaster()->ToPlayer()->AddAura(ampId, GetCaster()); + GetCaster()->ToPlayer()->SetAuraStack(ampId, GetCaster(), stacksCount); } + } + + void Register() override + { + OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_thaddius_polarity_charge::HandleTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ALLY); + } }; -class spell_thaddius_magnetic_pull : public SpellScriptLoader +class spell_thaddius_polarity_shift : public SpellScript { - public: - spell_thaddius_magnetic_pull() : SpellScriptLoader("spell_thaddius_magnetic_pull") { }; + PrepareSpellScript(spell_thaddius_polarity_shift); - class spell_thaddius_magnetic_pull_SpellScript : public SpellScript + bool Validate(SpellInfo const* /*spell*/) override + { + return ValidateSpellInfo( { - PrepareSpellScript(spell_thaddius_magnetic_pull_SpellScript); + SPELL_POLARITY_SHIFT, + SPELL_POSITIVE_CHARGE_APPLY, + SPELL_POSITIVE_CHARGE_TICK, + SPELL_POSITIVE_CHARGE_AMP, + SPELL_NEGATIVE_CHARGE_APPLY, + SPELL_NEGATIVE_CHARGE_TICK, + SPELL_NEGATIVE_CHARGE_AMP + }); + } - bool Validate(SpellInfo const* /*spell*/) override + void HandleDummy(SpellEffIndex /*effIndex*/) + { + if (Unit* target = GetHitUnit()) + if (target->GetTypeId() == TYPEID_PLAYER) { - return ValidateSpellInfo({ SPELL_MAGNETIC_PULL }); + if (roll_chance_i(50)) + { // positive + target->CastSpell(target, SPELL_POSITIVE_CHARGE_APPLY, true); + target->RemoveAura(SPELL_POSITIVE_CHARGE_AMP); + } + else + { // negative + target->CastSpell(target, SPELL_NEGATIVE_CHARGE_APPLY, true); + target->RemoveAura(SPELL_NEGATIVE_CHARGE_AMP); + } } + } - void HandleCast() // only feugen ever casts this according to wowhead data - { - Unit* feugen = GetCaster(); - if (!feugen || feugen->GetEntry() != NPC_FEUGEN) - return; + void Register() override + { + OnEffectHitTarget += SpellEffectFn(spell_thaddius_polarity_shift::HandleDummy, EFFECT_0, SPELL_EFFECT_DUMMY); + } +}; - Unit* stalagg = ObjectAccessor::GetCreature(*feugen, feugen->GetInstanceScript()->GetGuidData(DATA_STALAGG)); - if (!stalagg) - return; +class spell_thaddius_magnetic_pull : public SpellScript +{ + PrepareSpellScript(spell_thaddius_magnetic_pull); - ThreatManager& feugenThreat = feugen->GetThreatManager(); - ThreatManager& stalaggThreat = stalagg->GetThreatManager(); + bool Validate(SpellInfo const* /*spell*/) override + { + return ValidateSpellInfo({ SPELL_MAGNETIC_PULL }); + } - Unit* feugenTank = feugenThreat.GetCurrentVictim(); - Unit* stalaggTank = stalaggThreat.GetCurrentVictim(); + void HandleCast() // only feugen ever casts this according to wowhead data + { + Unit* feugen = GetCaster(); + if (!feugen || feugen->GetEntry() != NPC_FEUGEN) + return; - if (!feugenTank || !stalaggTank) - return; + Unit* stalagg = ObjectAccessor::GetCreature(*feugen, feugen->GetInstanceScript()->GetGuidData(DATA_STALAGG)); + if (!stalagg) + return; - if (feugenTank == stalaggTank) // special behavior if the tanks are the same (taken from retail) - { - float feugenTankThreat = feugenThreat.GetThreat(feugenTank); - float stalaggTankThreat = stalaggThreat.GetThreat(stalaggTank); + ThreatManager& feugenThreat = feugen->GetThreatManager(); + ThreatManager& stalaggThreat = stalagg->GetThreatManager(); - feugen->GetThreatManager().AddThreat(feugenTank, stalaggTankThreat - feugenTankThreat, nullptr, true, true); - stalagg->GetThreatManager().AddThreat(stalaggTank, feugenTankThreat - stalaggTankThreat, nullptr, true, true); + Unit* feugenTank = feugenThreat.GetCurrentVictim(); + Unit* stalaggTank = stalaggThreat.GetCurrentVictim(); - feugen->CastSpell(stalaggTank, SPELL_MAGNETIC_PULL_EFFECT, true); - } - else // normal case, two tanks - { - float feugenTankThreat = feugenThreat.GetThreat(feugenTank); - float feugenOtherThreat = feugenThreat.GetThreat(stalaggTank); - float stalaggTankThreat = stalaggThreat.GetThreat(stalaggTank); - float stalaggOtherThreat = stalaggThreat.GetThreat(feugenTank); - - // set the two entries in feugen's threat table to be equal to the ones in stalagg's - feugen->GetThreatManager().AddThreat(stalaggTank, stalaggTankThreat - feugenOtherThreat, nullptr, true, true); - feugen->GetThreatManager().AddThreat(feugenTank, stalaggOtherThreat - feugenTankThreat, nullptr, true, true); - - // set the two entries in stalagg's threat table to be equal to the ones in feugen's - stalagg->GetThreatManager().AddThreat(feugenTank, feugenTankThreat - stalaggOtherThreat, nullptr, true, true); - stalagg->GetThreatManager().AddThreat(stalaggTank, feugenOtherThreat - stalaggTankThreat, nullptr, true, true); - - // pull the two tanks across - feugenTank->CastSpell(stalaggTank, SPELL_MAGNETIC_PULL_EFFECT, true); - stalaggTank->CastSpell(feugenTank, SPELL_MAGNETIC_PULL_EFFECT, true); - - // @hack prevent mmaps clusterfucks from breaking tesla while tanks are midair - feugen->AddAura(SPELL_ROOT_SELF, feugen); - stalagg->AddAura(SPELL_ROOT_SELF, stalagg); - - // and make both attack their respective new tanks - if (feugen->GetAI()) - feugen->GetAI()->AttackStart(stalaggTank); - if (stalagg->GetAI()) - stalagg->GetAI()->AttackStart(feugenTank); - } - } + if (!feugenTank || !stalaggTank) + return; - void Register() override - { - OnCast += SpellCastFn(spell_thaddius_magnetic_pull_SpellScript::HandleCast); - } - }; + if (feugenTank == stalaggTank) // special behavior if the tanks are the same (taken from retail) + { + float feugenTankThreat = feugenThreat.GetThreat(feugenTank); + float stalaggTankThreat = stalaggThreat.GetThreat(stalaggTank); - SpellScript* GetSpellScript() const override + feugen->GetThreatManager().AddThreat(feugenTank, stalaggTankThreat - feugenTankThreat, nullptr, true, true); + stalagg->GetThreatManager().AddThreat(stalaggTank, feugenTankThreat - stalaggTankThreat, nullptr, true, true); + + feugen->CastSpell(stalaggTank, SPELL_MAGNETIC_PULL_EFFECT, true); + } + else // normal case, two tanks { - return new spell_thaddius_magnetic_pull_SpellScript(); + float feugenTankThreat = feugenThreat.GetThreat(feugenTank); + float feugenOtherThreat = feugenThreat.GetThreat(stalaggTank); + float stalaggTankThreat = stalaggThreat.GetThreat(stalaggTank); + float stalaggOtherThreat = stalaggThreat.GetThreat(feugenTank); + + // set the two entries in feugen's threat table to be equal to the ones in stalagg's + feugen->GetThreatManager().AddThreat(stalaggTank, stalaggTankThreat - feugenOtherThreat, nullptr, true, true); + feugen->GetThreatManager().AddThreat(feugenTank, stalaggOtherThreat - feugenTankThreat, nullptr, true, true); + + // set the two entries in stalagg's threat table to be equal to the ones in feugen's + stalagg->GetThreatManager().AddThreat(feugenTank, feugenTankThreat - stalaggOtherThreat, nullptr, true, true); + stalagg->GetThreatManager().AddThreat(stalaggTank, feugenOtherThreat - stalaggTankThreat, nullptr, true, true); + + // pull the two tanks across + feugenTank->CastSpell(stalaggTank, SPELL_MAGNETIC_PULL_EFFECT, true); + stalaggTank->CastSpell(feugenTank, SPELL_MAGNETIC_PULL_EFFECT, true); + + // @hack prevent mmaps clusterfucks from breaking tesla while tanks are midair + feugen->AddAura(SPELL_ROOT_SELF, feugen); + stalagg->AddAura(SPELL_ROOT_SELF, stalagg); + + // and make both attack their respective new tanks + if (feugen->GetAI()) + feugen->GetAI()->AttackStart(stalaggTank); + if (stalagg->GetAI()) + stalagg->GetAI()->AttackStart(feugenTank); } + } + + void Register() override + { + OnCast += SpellCastFn(spell_thaddius_magnetic_pull::HandleCast); + } }; class at_thaddius_entrance : public OnlyOnceAreaTriggerScript @@ -1244,13 +1177,13 @@ class achievement_thaddius_shocking : public AchievementCriteriaScript void AddSC_boss_thaddius() { RegisterNaxxramasCreatureAI(boss_thaddius); - new npc_stalagg(); - new npc_feugen(); - new npc_tesla(); + RegisterNaxxramasCreatureAI(npc_stalagg); + RegisterNaxxramasCreatureAI(npc_feugen); + RegisterNaxxramasCreatureAI(npc_tesla); - new spell_thaddius_polarity_charge(); - new spell_thaddius_polarity_shift(); - new spell_thaddius_magnetic_pull(); + RegisterSpellScript(spell_thaddius_polarity_charge); + RegisterSpellScript(spell_thaddius_polarity_shift); + RegisterSpellScript(spell_thaddius_magnetic_pull); new at_thaddius_entrance(); |