TrinityCore
Loading...
Searching...
No Matches
boss_thaddius.cpp
Go to the documentation of this file.
1/*
2 * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License as published by the
6 * Free Software Foundation; either version 2 of the License, or (at your
7 * option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 *
14 * You should have received a copy of the GNU General Public License along
15 * with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18#include "ScriptMgr.h"
19#include "GameObject.h"
20#include "InstanceScript.h"
21#include "Map.h"
22#include "naxxramas.h"
23#include "ObjectAccessor.h"
24#include "Player.h"
25#include "ScriptedCreature.h"
26#include "SpellInfo.h"
27#include "SpellScript.h"
28
36
38{
39 ACTION_BEGIN_RESET_ENCOUNTER = 0, // sent from thaddius to pets to trigger despawn and encounter reset
40 ACTION_FEUGEN_DIED, // sent from respective pet to thaddius to indicate death
42 ACTION_FEUGEN_RESET, // pet to thaddius
44 ACTION_FEUGEN_AGGRO, // pet to thaddius on combat start
46 ACTION_FEUGEN_REVIVING_FX, // thaddius to pet when pet reports its death
48 ACTION_FEUGEN_REVIVED, // thaddius to pet when pet should revive
50 ACTION_TRANSITION, // thaddius to pets when transition starts (coil overload anim)
51 ACTION_TRANSITION_2, // thaddius to pets to make the coils shock him
52 ACTION_TRANSITION_3, // thaddius to pets to disable coil GO after spawn
53
54 ACTION_POLARITY_CROSSED // triggers achievement failure, sent from spellscript
55};
56
58{
59 EVENT_SHIFT = 1, // polarity shift
60 EVENT_SHIFT_TALK, // polarity shift yell (hack? couldn't find any event for cast finish)
61 EVENT_CHAIN, // chain lightning
62 EVENT_BERSERK, // enrage timer
63 EVENT_REVIVE_FEUGEN, // timer until feugen is revived (if stalagg still lives)
64 EVENT_REVIVE_STALAGG, // timer until stalagg is revived (if feugen still lives)
65 EVENT_TRANSITION_1, // timer until overload emote
66 EVENT_TRANSITION_2, // timer until thaddius gets zapped by the coils
67 EVENT_TRANSITION_3, // timer until thaddius becomes attackable
68 EVENT_ENGAGE, // timer until thaddius engages
69 EVENT_ENABLE_BALL_LIGHTNING // grace period after thaddius aggro after which he starts tossing ball lightning at out of range targets
70};
71
79
80// Feugen & Stalagg
97
99{
101 //SPELL_STALAGG_TESLA = 28097,
104
106 //SPELL_FEUGEN_TESLA = 28109,
109
112
113 // @hack feugen/stalagg use this in P1 after gripping tanks to prevent mmaps from pathing them off the platform once they approach the ramp
114 // developer from the future, if you read this and mmaps in the room has been fixed, then get rid of the hackfix, please
116
117 SPELL_TESLA_SHOCK = 28099
119
121{
124
125//Thaddius
137
159
160struct boss_thaddius : public BossAI
161{
162public:
164
165 void InitializeAI() override
166 {
168 {
170 SetCombatMovement(false);
171 }
172 }
173
174 void KilledUnit(Unit* victim) override
175 {
176 if (victim->GetTypeId() == TYPEID_PLAYER)
177 Talk(SAY_SLAY);
178 }
179
180 void Reset() override { }
181
182 void EnterEvadeMode(EvadeReason why) override
183 {
185 {
187 return; // try again
188 }
191 }
192
193 bool CanAIAttack(Unit const* who) const override
194 {
196 return BossAI::CanAIAttack(who);
197 else
198 return false;
199 }
200
201 void JustAppeared() override
202 {
205 }
206
207 void JustDied(Unit* /*killer*/) override
208 {
209 _JustDied();
210 me->setActive(false);
211 me->SetFarVisible(false);
213 {
214 stalagg->setActive(false);
215 stalagg->SetFarVisible(false);
216 }
218 {
219 feugen->setActive(false);
220 feugen->SetFarVisible(false);
221 }
223 }
224
225 void DoAction(int32 action) override
226 {
227 switch (action)
228 {
233 break;
237 return;
239
240 shockingEligibility = true;
241
243 {
245 return;
246 }
248
249 me->setActive(true);
250 me->SetFarVisible(true);
253 {
254 stalagg->setActive(true);
255 stalagg->SetFarVisible(true);
256 }
258 {
259 feugen->setActive(true);
260 feugen->SetFarVisible(true);
261 }
262 break;
265 feugen->AI()->DoAction(ACTION_FEUGEN_REVIVING_FX);
266 feugenAlive = false;
267 if (stalaggAlive)
269 else
270 Transition();
271
272 break;
275 stalagg->AI()->DoAction(ACTION_STALAGG_REVIVING_FX);
276 stalaggAlive = false;
277 if (feugenAlive)
279 else
280 Transition();
281
282 break;
283
285 shockingEligibility = false;
286 break;
287 default:
288 break;
289 }
290 }
291
292 uint32 GetData(uint32 id) const override
293 {
294 return (id == DATA_POLARITY_CROSSED && shockingEligibility) ? 1u : 0u;
295 }
296
297 void Transition() // initiate transition between pet phase and thaddius phase
298 {
300
302
306 }
307
328
330 {
331 feugenAlive = true;
332 stalaggAlive = true;
333
334 _Reset();
337
338 // @todo these guys should really be moved to a summon group - this is merely a hack to make them work in dynamic_spawning
339 instance->instance->Respawn(SPAWN_TYPE_CREATURE, 130958); // Stalagg
340 instance->instance->Respawn(SPAWN_TYPE_CREATURE, 130959); // Feugen
341 }
342
343 void UpdateAI(uint32 diff) override
344 {
346 return;
348 return;
349
350 events.Update(diff);
351 while (uint32 eventId = events.ExecuteEvent())
352 {
353 switch (eventId)
354 {
356 feugenAlive = true;
358 feugen->AI()->DoAction(ACTION_FEUGEN_REVIVED);
359 break;
361 stalaggAlive = true;
363 stalagg->AI()->DoAction(ACTION_STALAGG_REVIVED);
364 break;
365 case EVENT_TRANSITION_1: // tesla coils overload
367 feugen->AI()->DoAction(ACTION_TRANSITION);
369 stalagg->AI()->DoAction(ACTION_TRANSITION);
370 break;
371 case EVENT_TRANSITION_2: // tesla coils shock thaddius
374 feugen->AI()->DoAction(ACTION_TRANSITION_2);
376 stalagg->AI()->DoAction(ACTION_TRANSITION_2);
377 break;
378 case EVENT_TRANSITION_3: // thaddius becomes active
380 ballLightningUnlocked = false;
382 me->SetImmuneToPC(false);
384
386 feugen->AI()->DoAction(ACTION_TRANSITION_3);
388 stalagg->AI()->DoAction(ACTION_TRANSITION_3);
389
391
393
399
400 break;
403 break;
404 case EVENT_ENGAGE:
406 break;
407 case EVENT_SHIFT:
408 me->CastStop(); // shift overrides all other spells
412 break;
413 case EVENT_SHIFT_TALK:
416 break;
417 case EVENT_CHAIN:
418 if (me->FindCurrentSpellBySpellId(SPELL_POLARITY_SHIFT)) // delay until shift is over
420 else
421 {
422 me->CastStop();
425 }
426 break;
427 case EVENT_BERSERK:
428 me->CastStop();
430 break;
431 default:
432 break;
433 }
434 }
435
437 {
439 {
440 ballLightningEnabled = false;
442 }
443 else if (ballLightningUnlocked)
446 }
447 }
448
449private:
452 bool ballLightningUnlocked; // whether the initial ball lightning grace period has expired and we should proceed to exterminate with extreme prejudice
453 bool ballLightningEnabled; // switch that is flipped to true if we try to evade due to no eligible targets in melee range
455};
456
457struct npc_stalagg : public ScriptedAI
458{
459public:
460 npc_stalagg(Creature* creature) : ScriptedAI(creature),
461 instance(creature->GetInstanceScript()), powerSurgeTimer(), _myCoil(ObjectGuid::Empty), _myCoilGO(ObjectGuid::Empty), isOverloading(false), refreshBeam(false), isFeignDeath(false)
462 {
463 instance = creature->GetInstanceScript();
465 }
466
467 void InitializeAI() override
468 {
469 if (GameObject* coil = myCoilGO())
470 coil->SetGoState(GO_STATE_ACTIVE);
471
473
474 // force tesla coil state refresh
475 refreshBeam = true;
476 }
477
478 void EnterEvadeMode(EvadeReason /*reason*/) override
479 {
481 thaddius->AI()->DoAction(ACTION_STALAGG_RESET);
482 }
483
485 {
486 if (GameObject* coil = myCoilGO())
487 coil->SetGoState(GO_STATE_READY);
488 me->DespawnOrUnsummon(0s, 7_days); // will be force respawned by thaddius
489 }
490
491 void DoAction(int32 action) override
492 {
493 switch (action)
494 {
497 break;
499 break;
501 if (!isFeignDeath)
502 break;
503
504 me->SetFullHealth();
510 isFeignDeath = false;
511
512 refreshBeam = true; // force beam refresh
513
515 if (!me->IsEngaged())
517 break;
519 me->KillSelf(); // true death
520
521 if (Creature* coil = myCoil())
522 {
523 coil->CastStop();
524 coil->AI()->Talk(EMOTE_TESLA_OVERLOAD);
525 }
526 break;
528 if (Creature* coil = myCoil())
530 coil->CastSpell(thaddius, SPELL_SHOCK_VISUAL);
531 break;
533 if (GameObject* coil = myCoilGO())
534 coil->SetGoState(GO_STATE_READY);
535 me->DespawnOrUnsummon(0s, 7_days);
536 break;
537 default:
538 break;
539 }
540 }
541
542 void KilledUnit(Unit* victim) override
543 {
544 if (victim->GetTypeId() == TYPEID_PLAYER)
546 }
547
548 void JustEngagedWith(Unit* who) override
549 {
551
553 thaddius->AI()->DoAction(ACTION_STALAGG_AGGRO);
554
556 if (!feugen->IsEngaged())
557 AddThreat(who, 0.0f, feugen);
558 }
559
560 void DamageTaken(Unit* /*who*/, uint32& damage, DamageEffectType /*damageType*/, SpellInfo const* /*spellInfo = nullptr*/) override
561 {
562 if (damage < me->GetHealth())
563 return;
564
565 if (isFeignDeath) // don't take damage while feigning death
566 {
567 damage = 0;
568 return;
569 }
570
571 isFeignDeath = true;
572 isOverloading = false;
573
576 thaddius->AI()->DoAction(ACTION_STALAGG_DIED);
577
581 me->AttackStop();
584
585 damage = me->GetHealth()-1;
586
587 // force beam refresh as we just removed auras
588 refreshBeam = true;
589 }
590
591 void SpellHit(WorldObject* caster, SpellInfo const* spellInfo) override
592 {
593 Creature* creatureCaster = caster->ToCreature();
594 if (!creatureCaster)
595 return;
596
597 if (spellInfo->Id != SPELL_STALAGG_TESLA_PERIODIC)
598 return;
599 if (!isFeignDeath && me->IsInCombat() && !me->GetHomePosition().IsInDist(me, OVERLOAD_DISTANCE))
600 {
601 if (!isOverloading)
602 {
603 isOverloading = true;
604 creatureCaster->SetImmuneToPC(false);
605 creatureCaster->AI()->Talk(EMOTE_TESLA_LINK_BREAKS);
607 }
609 {
610 creatureCaster->CastStop(SPELL_TESLA_SHOCK);
611 creatureCaster->CastSpell(target, SPELL_TESLA_SHOCK,true);
612 }
613 }
614 else if (isOverloading || refreshBeam)
615 {
616 isOverloading = false;
617 refreshBeam = false;
618 creatureCaster->CastStop();
619 creatureCaster->CastSpell(me, SPELL_STALAGG_CHAIN_VISUAL, true);
620 creatureCaster->SetImmuneToPC(true);
621 }
622 }
623
624 void UpdateAI(uint32 uiDiff) override
625 {
626 if (!isFeignDeath)
627 if (!UpdateVictim())
628 return;
629
630 if (powerSurgeTimer <= uiDiff)
631 {
632 if (isFeignDeath) // delay until potential revive
633 powerSurgeTimer = 0u;
634 else
635 {
637 powerSurgeTimer = urandms(25, 30);
638 }
639 }
640 else
641 powerSurgeTimer -= uiDiff;
642
643 if (!isFeignDeath)
645 }
646
647private:
649 {
650 Creature* coil = nullptr;
651 if (!_myCoil.IsEmpty())
653 if (!coil)
654 {
655 coil = me->FindNearestCreature(NPC_TESLA, 1000.0f, true);
656 if (coil)
657 {
658 _myCoil = coil->GetGUID();
660 }
661 }
662 return coil;
663 }
664
666 {
667 GameObject* coil = nullptr;
668 if (!_myCoilGO.IsEmpty())
670 if (!coil)
671 {
673 if (coil)
674 _myCoilGO = coil->GetGUID();
675 }
676 return coil;
677 }
678
680
682
688};
689
690struct npc_feugen : public ScriptedAI
691{
692public:
693 npc_feugen(Creature* creature) : ScriptedAI(creature),
694 instance(creature->GetInstanceScript()), magneticPullTimer(), staticFieldTimer(), _myCoil(ObjectGuid::Empty), _myCoilGO(ObjectGuid::Empty), isOverloading(false), refreshBeam(false), isFeignDeath(false)
695 {
696 instance = creature->GetInstanceScript();
698 }
699
700 void InitializeAI() override
701 {
702 if (GameObject* coil = myCoilGO())
703 coil->SetGoState(GO_STATE_ACTIVE);
704
707
708 // force coil state to refresh
709 refreshBeam = true;
710 }
711
712 void EnterEvadeMode(EvadeReason /*why*/) override
713 {
715 thaddius->AI()->DoAction(ACTION_FEUGEN_RESET);
716 }
717
719 {
720 if (GameObject* coil = myCoilGO())
721 coil->SetGoState(GO_STATE_READY);
722 me->DespawnOrUnsummon(0s, 7_days); // will be force respawned by thaddius
723 }
724
725 void DoAction(int32 action) override
726 {
727 switch (action)
728 {
731 break;
733 break;
735 if (!isFeignDeath)
736 break;
737
738 me->SetFullHealth();
744 isFeignDeath = false;
745
746 refreshBeam = true; // force beam refresh
747
749 if (stalagg->GetVictim())
750 {
751 AddThreat(stalagg->EnsureVictim(), 0.0f);
752 me->SetInCombatWith(stalagg->EnsureVictim());
753 }
756 break;
758 me->KillSelf(); // true death this time around
759
760 if (Creature* coil = myCoil())
761 {
762 coil->CastStop();
763 coil->AI()->Talk(EMOTE_TESLA_OVERLOAD);
764 }
765 break;
767 if (Creature* coil = myCoil())
769 coil->CastSpell(thaddius, SPELL_SHOCK_VISUAL);
770 break;
772 if (GameObject* coil = myCoilGO())
773 coil->SetGoState(GO_STATE_READY);
774 me->DespawnOrUnsummon(0s, 7_days);
775 break;
776 default:
777 break;
778 }
779 }
780
781 void KilledUnit(Unit* victim) override
782 {
783 if (victim->GetTypeId() == TYPEID_PLAYER)
785 }
786
787 void JustEngagedWith(Unit* who) override
788 {
790
792 thaddius->AI()->DoAction(ACTION_FEUGEN_AGGRO);
793
795 if (!stalagg->IsInCombat())
796 AddThreat(who, 0.0f, stalagg);
797 }
798
799 void DamageTaken(Unit* /*who*/, uint32& damage, DamageEffectType /*damageType*/, SpellInfo const* /*spellInfo = nullptr*/) override
800 {
801 if (damage < me->GetHealth())
802 return;
803
804 if (isFeignDeath) // don't take damage while feigning death
805 {
806 damage = 0;
807 return;
808 }
809
810 isFeignDeath = true;
811 isOverloading = false;
812
815 thaddius->AI()->DoAction(ACTION_FEUGEN_DIED);
816
820 me->AttackStop();
823
824 damage = me->GetHealth()-1;
825
826 // force beam refresh as we just removed auras
827 refreshBeam = true;
828 }
829
830 void SpellHit(WorldObject* caster, SpellInfo const* spellInfo) override
831 {
832 Creature* creatureCaster = caster->ToCreature();
833 if (!creatureCaster)
834 return;
835
836 if (spellInfo->Id != SPELL_FEUGEN_TESLA_PERIODIC)
837 return;
838
839 if (!isFeignDeath && me->IsInCombat() && !me->GetHomePosition().IsInDist(me, OVERLOAD_DISTANCE))
840 {
841 if (!isOverloading)
842 {
843 isOverloading = true;
844 creatureCaster->SetImmuneToPC(false);
845 creatureCaster->AI()->Talk(EMOTE_TESLA_LINK_BREAKS);
847 }
849 {
850 creatureCaster->CastStop(SPELL_TESLA_SHOCK);
851 creatureCaster->CastSpell(target, SPELL_TESLA_SHOCK,true);
852 }
853 }
854 else if (isOverloading || refreshBeam)
855 {
856 isOverloading = false;
857 refreshBeam = false;
858 creatureCaster->CastStop();
859 creatureCaster->CastSpell(me, SPELL_FEUGEN_CHAIN_VISUAL, true);
860 creatureCaster->SetImmuneToPC(true);
861 }
862 }
863
864 void UpdateAI(uint32 uiDiff) override
865 {
866 if (isFeignDeath)
867 return;
868 if (!UpdateVictim())
869 return;
870
871 if (magneticPullTimer <= uiDiff)
872 {
875 }
876 else magneticPullTimer -= uiDiff;
877
878 if (staticFieldTimer <= uiDiff)
879 {
882 }
883 else staticFieldTimer -= uiDiff;
884
886 }
887
888private:
890 {
891 Creature* coil = nullptr;
892 if (!_myCoil.IsEmpty())
894 if (!coil)
895 {
896 coil = me->FindNearestCreature(NPC_TESLA, 1000.0f, true);
897 if (coil)
898 {
899 _myCoil = coil->GetGUID();
901 }
902 }
903 return coil;
904 }
905
907 {
908 GameObject* coil = nullptr;
909 if (!_myCoilGO.IsEmpty())
911 if (!coil)
912 {
914 if (coil)
915 _myCoilGO = coil->GetGUID();
916 }
917 return coil;
918 }
920
923
926
930};
931
932struct npc_tesla : public ScriptedAI
933{
934 npc_tesla(Creature* creature) : ScriptedAI(creature) { }
935
936 void EnterEvadeMode(EvadeReason /*why*/) override { } // never stop casting due to evade
937 void UpdateAI(uint32 /*diff*/) override { } // never do anything unless told
938 void JustEngagedWith(Unit* /*who*/) override { }
939 void DamageTaken(Unit* /*who*/, uint32& damage, DamageEffectType /*damageType*/, SpellInfo const* /*spellInfo = nullptr*/) override { damage = 0; } // no, you can't kill it
940};
941
942// 28062 - Positive Charge
943// 28085 - Negative Charge
945{
947
961
962 void HandleTargets(std::list<WorldObject*>& targetList)
963 {
964 if (!GetTriggeringSpell())
965 return;
966
967 uint32 triggeringId = GetTriggeringSpell()->Id;
968 uint32 ampId;
969 switch (triggeringId)
970 {
973 break;
976 break;
977 default:
978 return;
979 }
980
981 uint8 maxStacks = 0;
982 if (GetCaster())
983 switch (GetCaster()->GetMap()->GetDifficulty())
984 {
986 maxStacks = MAX_POLARITY_10M;
987 break;
989 maxStacks = MAX_POLARITY_25M;
990 break;
991 default:
992 break;
993 }
994
995 uint8 stacksCount = 1; // do we get a stack for our own debuff?
996 std::list<WorldObject*>::iterator it = targetList.begin();
997 while(it != targetList.end())
998 {
999 if ((*it)->GetTypeId() != TYPEID_PLAYER)
1000 {
1001 it = targetList.erase(it);
1002 continue;
1003 }
1004 if ((*it)->ToPlayer()->HasAura(triggeringId))
1005 {
1006 it = targetList.erase(it);
1007 if (stacksCount < maxStacks)
1008 stacksCount++;
1009 continue;
1010 }
1011
1012 // this guy will get hit - achievement failure trigger
1013 if (Creature* thaddius = (*it)->FindNearestCreature(NPC_THADDIUS, 200.0f))
1014 thaddius->AI()->DoAction(ACTION_POLARITY_CROSSED);
1015
1016 ++it;
1017 }
1018
1019 if (GetCaster() && GetCaster()->ToPlayer())
1020 {
1021 if (!GetCaster()->ToPlayer()->HasAura(ampId))
1022 GetCaster()->ToPlayer()->AddAura(ampId, GetCaster());
1023 GetCaster()->ToPlayer()->SetAuraStack(ampId, GetCaster(), stacksCount);
1024 }
1025 }
1026
1031};
1032
1033// 28089 - Polarity Shift
1035{
1037
1051
1052 void HandleDummy(SpellEffIndex /*effIndex*/)
1053 {
1054 if (Unit* target = GetHitUnit())
1055 if (target->GetTypeId() == TYPEID_PLAYER)
1056 {
1057 if (roll_chance_i(50))
1058 { // positive
1059 target->CastSpell(target, SPELL_POSITIVE_CHARGE_APPLY, true);
1060 target->RemoveAura(SPELL_POSITIVE_CHARGE_AMP);
1061 }
1062 else
1063 { // negative
1064 target->CastSpell(target, SPELL_NEGATIVE_CHARGE_APPLY, true);
1065 target->RemoveAura(SPELL_NEGATIVE_CHARGE_AMP);
1066 }
1067 }
1068 }
1069
1074};
1075
1076// 54517 - Magnetic Pull
1078{
1080
1081 bool Validate(SpellInfo const* /*spell*/) override
1082 {
1084 }
1085
1086 void HandleCast() // only feugen ever casts this according to wowhead data
1087 {
1088 Unit* feugen = GetCaster();
1089 if (!feugen || feugen->GetEntry() != NPC_FEUGEN)
1090 return;
1091
1093 if (!stalagg)
1094 return;
1095
1096 ThreatManager& feugenThreat = feugen->GetThreatManager();
1097 ThreatManager& stalaggThreat = stalagg->GetThreatManager();
1098
1099 Unit* feugenTank = feugenThreat.GetCurrentVictim();
1100 Unit* stalaggTank = stalaggThreat.GetCurrentVictim();
1101
1102 if (!feugenTank || !stalaggTank)
1103 return;
1104
1105 if (feugenTank == stalaggTank) // special behavior if the tanks are the same (taken from retail)
1106 {
1107 float feugenTankThreat = feugenThreat.GetThreat(feugenTank);
1108 float stalaggTankThreat = stalaggThreat.GetThreat(stalaggTank);
1109
1110 feugen->GetThreatManager().AddThreat(feugenTank, stalaggTankThreat - feugenTankThreat, nullptr, true, true);
1111 stalagg->GetThreatManager().AddThreat(stalaggTank, feugenTankThreat - stalaggTankThreat, nullptr, true, true);
1112
1113 feugen->CastSpell(stalaggTank, SPELL_MAGNETIC_PULL_EFFECT, true);
1114 }
1115 else // normal case, two tanks
1116 {
1117 float feugenTankThreat = feugenThreat.GetThreat(feugenTank);
1118 float feugenOtherThreat = feugenThreat.GetThreat(stalaggTank);
1119 float stalaggTankThreat = stalaggThreat.GetThreat(stalaggTank);
1120 float stalaggOtherThreat = stalaggThreat.GetThreat(feugenTank);
1121
1122 // set the two entries in feugen's threat table to be equal to the ones in stalagg's
1123 feugen->GetThreatManager().AddThreat(stalaggTank, stalaggTankThreat - feugenOtherThreat, nullptr, true, true);
1124 feugen->GetThreatManager().AddThreat(feugenTank, stalaggOtherThreat - feugenTankThreat, nullptr, true, true);
1125
1126 // set the two entries in stalagg's threat table to be equal to the ones in feugen's
1127 stalagg->GetThreatManager().AddThreat(feugenTank, feugenTankThreat - stalaggOtherThreat, nullptr, true, true);
1128 stalagg->GetThreatManager().AddThreat(stalaggTank, feugenOtherThreat - stalaggTankThreat, nullptr, true, true);
1129
1130 // pull the two tanks across
1131 feugenTank->CastSpell(stalaggTank, SPELL_MAGNETIC_PULL_EFFECT, true);
1132 stalaggTank->CastSpell(feugenTank, SPELL_MAGNETIC_PULL_EFFECT, true);
1133
1134 // @hack prevent mmaps clusterfucks from breaking tesla while tanks are midair
1135 feugen->AddAura(SPELL_ROOT_SELF, feugen);
1136 stalagg->AddAura(SPELL_ROOT_SELF, stalagg);
1137
1138 // and make both attack their respective new tanks
1139 if (feugen->GetAI())
1140 feugen->GetAI()->AttackStart(stalaggTank);
1141 if (stalagg->GetAI())
1142 stalagg->GetAI()->AttackStart(feugenTank);
1143 }
1144 }
1145
1150};
1151
1153{
1154 public:
1155 at_thaddius_entrance() : OnlyOnceAreaTriggerScript("at_thaddius_entrance") { }
1156
1157 bool TryHandleOnce(Player* player, AreaTriggerEntry const* /*areaTrigger*/) override
1158 {
1159 InstanceScript* instance = player->GetInstanceScript();
1160 if (!instance || instance->GetBossState(BOSS_THADDIUS) == DONE)
1161 return true;
1162
1163 if (Creature* thaddius = ObjectAccessor::GetCreature(*player, instance->GetGuidData(DATA_THADDIUS)))
1164 thaddius->AI()->Talk(SAY_GREET);
1165
1166 return true;
1167 }
1168};
1169
1171{
1172 public:
1173 achievement_thaddius_shocking() : AchievementCriteriaScript("achievement_thaddius_shocking") { }
1174
1175 bool OnCheck(Player* /*source*/, Unit* target) override
1176 {
1177 return target && target->GetAI() && target->GetAI()->GetData(DATA_POLARITY_CROSSED);
1178 }
1179};
1180
@ IN_MILLISECONDS
Definition Common.h:35
@ RAID_DIFFICULTY_10MAN_NORMAL
Definition DBCEnums.h:286
@ RAID_DIFFICULTY_25MAN_NORMAL
Definition DBCEnums.h:287
uint8_t uint8
Definition Define.h:135
int32_t int32
Definition Define.h:129
uint32_t uint32
Definition Define.h:133
std::chrono::seconds Seconds
Seconds shorthand typedef.
Definition Duration.h:27
@ IN_PROGRESS
@ DONE
@ TYPEID_PLAYER
Definition ObjectGuid.h:39
Milliseconds randtime(Milliseconds min, Milliseconds max)
Definition Random.cpp:62
uint32 urandms(uint32 min, uint32 max)
Definition Random.cpp:49
bool roll_chance_i(int chance)
Definition Random.h:59
#define RegisterSpellScript(spell_script)
Definition ScriptMgr.h:1128
SpellEffIndex
@ EFFECT_0
@ SPELL_EFFECT_DUMMY
@ TARGET_UNIT_SRC_AREA_ALLY
@ GO_STATE_READY
@ GO_STATE_ACTIVE
@ SPAWN_TYPE_CREATURE
Definition SpawnData.h:31
#define SpellEffectFn(F, I, N)
#define SpellObjectAreaTargetSelectFn(F, I, N)
#define SpellCastFn(F)
@ REACT_PASSIVE
@ REACT_AGGRESSIVE
@ UNIT_STAND_STATE_DEAD
Definition UnitDefines.h:41
@ UNIT_STAND_STATE_STAND
Definition UnitDefines.h:34
@ UNIT_FLAG_STUNNED
@ UNIT_FLAG_UNINTERACTIBLE
@ UNIT_STATE_ROOT
Definition Unit.h:230
@ UNIT_STATE_CASTING
Definition Unit.h:235
DamageEffectType
Definition Unit.h:352
@ MAX_POLARITY_25M
@ MAX_POLARITY_10M
@ DATA_POLARITY_CROSSED
void AddSC_boss_thaddius()
@ PHASE_THADDIUS
@ PHASE_PETS
@ PHASE_TRANSITION
@ PHASE_NOT_ENGAGED
PetYells
@ EMOTE_FEIGN_REVIVE
@ SAY_STALAGG_SLAY
@ EMOTE_FEIGN_DEATH
@ SAY_FEUGEN_SLAY
@ SAY_FEUGEN_AGGRO
@ EMOTE_TESLA_LINK_BREAKS
@ SAY_STALAGG_DEATH
@ SAY_FEUGEN_DEATH
@ SAY_STALAGG_AGGRO
@ EMOTE_TESLA_OVERLOAD
PetSpells
@ SPELL_MAGNETIC_PULL
@ SPELL_MAGNETIC_PULL_EFFECT
@ SPELL_FEUGEN_TESLA_PERIODIC
@ SPELL_TESLA_SHOCK
@ SPELL_STALAGG_CHAIN_VISUAL
@ SPELL_STALAGG_POWERSURGE
@ SPELL_ROOT_SELF
@ SPELL_FEUGEN_STATICFIELD
@ SPELL_FEUGEN_CHAIN_VISUAL
@ SPELL_STALAGG_TESLA_PERIODIC
@ OVERLOAD_DISTANCE
ThaddiusYells
@ SAY_DEATH
@ SAY_ELECT
@ SAY_SCREAM
@ SAY_AGGRO
@ SAY_GREET
@ SAY_SLAY
@ EMOTE_POLARITY_SHIFTED
AIActions
@ ACTION_TRANSITION_2
@ ACTION_TRANSITION
@ ACTION_FEUGEN_AGGRO
@ ACTION_STALAGG_DIED
@ ACTION_FEUGEN_RESET
@ ACTION_FEUGEN_REVIVED
@ ACTION_TRANSITION_3
@ ACTION_POLARITY_CROSSED
@ ACTION_STALAGG_AGGRO
@ ACTION_FEUGEN_REVIVING_FX
@ ACTION_STALAGG_REVIVING_FX
@ ACTION_BEGIN_RESET_ENCOUNTER
@ ACTION_FEUGEN_DIED
@ ACTION_STALAGG_REVIVED
@ ACTION_STALAGG_RESET
ThaddiusSpells
@ SPELL_POLARITY_SHIFT
@ SPELL_BALL_LIGHTNING
@ SPELL_NEGATIVE_CHARGE_TICK
@ SPELL_POSITIVE_CHARGE_TICK
@ SPELL_THADDIUS_SPARK_VISUAL
@ SPELL_POSITIVE_CHARGE_APPLY
@ SPELL_NEGATIVE_CHARGE_APPLY
@ SPELL_SHOCK_VISUAL
@ SPELL_THADDIUS_INACTIVE_VISUAL
@ SPELL_CHAIN_LIGHTNING
@ SPELL_BERSERK
@ SPELL_POSITIVE_CHARGE_AMP
@ SPELL_NEGATIVE_CHARGE_AMP
@ EVENT_TRANSITION_1
@ EVENT_SHIFT
@ EVENT_REVIVE_FEUGEN
@ EVENT_ENABLE_BALL_LIGHTNING
@ EVENT_BERSERK
@ EVENT_ENGAGE
@ EVENT_REVIVE_STALAGG
@ EVENT_TRANSITION_2
@ EVENT_SHIFT_TALK
@ EVENT_CHAIN
@ EVENT_TRANSITION_3
InstanceScript *const instance
bool CanAIAttack(Unit const *target) const override
EventMap events
@ EVADE_REASON_NO_HOSTILES
Definition CreatureAI.h:94
void DoZoneInCombat(Creature *creature=nullptr)
void Talk(uint8 id, WorldObject const *whisperTarget=nullptr)
bool UpdateVictim()
void SetBoundary(CreatureBoundary const *boundary, bool negativeBoundaries=false)
Creature *const me
Definition CreatureAI.h:82
void SetImmuneToPC(bool apply) override
Definition Creature.h:129
void GetHomePosition(float &x, float &y, float &z, float &ori) const
Definition Creature.h:295
bool IsEngaged() const override
void SetReactState(ReactStates st)
Definition Creature.h:119
void DespawnOrUnsummon(Milliseconds timeToDespawn=0s, Seconds forceRespawnTime=0s)
CreatureAI * AI() const
Definition Creature.h:154
void Update(uint32 time)
Definition EventMap.h:67
void Repeat(Milliseconds time)
Definition EventMap.cpp:63
EventId ExecuteEvent()
Definition EventMap.cpp:73
bool IsInPhase(PhaseIndex phase) const
Definition EventMap.h:236
void SetPhase(PhaseIndex phase)
Definition EventMap.cpp:28
void ScheduleEvent(EventId eventId, Milliseconds time, GroupIndex group=0u, PhaseIndex phase=0u)
Definition EventMap.cpp:36
virtual bool SetBossState(uint32 id, EncounterState state)
void DoRemoveAurasDueToSpellOnPlayers(uint32 spell, bool includePets=false, bool includeControlled=false)
virtual ObjectGuid GetGuidData(uint32 type) const override
InstanceMap * instance
CreatureBoundary const * GetBossBoundary(uint32 id) const
EncounterState GetBossState(uint32 id) const
virtual bool CheckRequiredBosses(uint32, Player const *=nullptr) const
void Respawn(RespawnInfo *info, CharacterDatabaseTransaction dbTrans=nullptr)
Definition Map.cpp:3105
bool IsEmpty() const
Definition ObjectGuid.h:172
static Creature * ToCreature(Object *o)
Definition Object.h:186
TypeID GetTypeId() const
Definition Object.h:93
uint32 GetEntry() const
Definition Object.h:81
static ObjectGuid GetGUID(Object const *o)
Definition Object.h:78
static Player * ToPlayer(Object *o)
Definition Object.h:180
uint32 Id
Definition SpellInfo.h:289
Unit * GetCaster() const
SpellInfo const * GetTriggeringSpell() const
Unit * GetHitUnit() const
HookList< EffectHandler > OnEffectHitTarget
HookList< CastHandler > OnCast
HookList< ObjectAreaTargetSelectHandler > OnObjectAreaTargetSelect
Unit * GetCurrentVictim()
void AddThreat(Unit *target, float amount, SpellInfo const *spell=nullptr, bool ignoreModifiers=false, bool ignoreRedirects=false)
== AFFECT MY THREAT LIST ==
float GetThreat(Unit const *who, bool includeOffline=false) const
void DoMeleeAttackIfReady()
Definition UnitAI.cpp:54
virtual uint32 GetData(uint32) const
Definition UnitAI.h:155
SpellCastResult DoCastVictim(uint32 spellId, CastSpellExtraArgs const &args={})
Definition UnitAI.cpp:166
Unit * SelectTarget(SelectTargetMethod targetType, uint32 offset=0, float dist=0.0f, bool playerOnly=false, bool withTank=true, int32 aura=0)
Definition UnitAI.cpp:96
virtual void AttackStart(Unit *)
Definition UnitAI.cpp:30
SpellCastResult DoCastAOE(uint32 spellId, CastSpellExtraArgs const &args={})
Definition UnitAI.h:243
SpellCastResult DoCast(uint32 spellId)
Definition UnitAI.cpp:106
Definition Unit.h:769
void CastStop(uint32 except_spellid=0)
Definition Unit.cpp:988
bool IsWithinMeleeRange(Unit const *obj) const
Definition Unit.h:844
void KillSelf(bool durabilityLoss=true)
Definition Unit.h:1023
void RemoveAura(AuraApplicationMap::iterator &i, AuraRemoveMode mode=AURA_REMOVE_BY_DEFAULT)
Definition Unit.cpp:3638
void SetFullHealth()
Definition Unit.h:927
ThreatManager & GetThreatManager()
Definition Unit.h:1155
void SetInCombatWith(Unit *enemy, bool addSecondUnitSuppressed=false)
Definition Unit.h:1146
void SetControlled(bool apply, UnitState state)
Definition Unit.cpp:11256
Spell * FindCurrentSpellBySpellId(uint32 spell_id) const
Definition Unit.cpp:3108
void SetAuraStack(uint32 spellId, Unit *target, uint32 stack)
Definition Unit.cpp:12010
Aura * AddAura(uint32 spellId, Unit *target)
Definition Unit.cpp:11964
bool IsAlive() const
Definition Unit.h:1234
UnitAI * GetAI() const
Definition Unit.h:800
uint32 GetHealth() const
Definition Unit.h:913
Unit * GetVictim() const
Definition Unit.h:859
bool HasUnitState(const uint32 f) const
Definition Unit.h:876
void SetStandState(UnitStandStateType state)
Definition Unit.cpp:10363
void RemoveAllAuras()
Definition Unit.cpp:4157
void SetUnitFlag(UnitFlags flags)
Definition Unit.h:954
bool isAttackReady(WeaponAttackType type=BASE_ATTACK) const
Definition Unit.h:835
bool AttackStop()
Definition Unit.cpp:5645
bool IsInCombat() const
Definition Unit.h:1144
void RemoveUnitFlag(UnitFlags flags)
Definition Unit.h:955
GameObject * FindNearestGameObject(uint32 entry, float range, bool spawnedOnly=true) const
Definition Object.cpp:2121
InstanceScript * GetInstanceScript() const
Definition Object.cpp:1087
SpellCastResult CastSpell(CastSpellTargetArg const &targets, uint32 spellId, CastSpellExtraArgs const &args={ })
Definition Object.cpp:2832
void setActive(bool isActiveObject)
Definition Object.cpp:991
void SetFarVisible(bool on)
Definition Object.cpp:1014
Creature * FindNearestCreature(uint32 entry, float range, bool alive=true) const
Definition Object.cpp:2099
static bool ValidateSpellInfo(std::initializer_list< uint32 > spellIds)
bool OnCheck(Player *, Unit *target) override
bool TryHandleOnce(Player *player, AreaTriggerEntry const *) override
bool Validate(SpellInfo const *) override
PrepareSpellScript(spell_thaddius_magnetic_pull)
void HandleTargets(std::list< WorldObject * > &targetList)
PrepareSpellScript(spell_thaddius_polarity_charge)
bool Validate(SpellInfo const *) override
PrepareSpellScript(spell_thaddius_polarity_shift)
bool Validate(SpellInfo const *) override
TC_GAME_API GameObject * GetGameObject(WorldObject const &u, ObjectGuid const &guid)
TC_GAME_API Creature * GetCreature(WorldObject const &u, ObjectGuid const &guid)
@ NPC_FEUGEN
Definition naxxramas.h:99
@ NPC_THADDIUS
Definition naxxramas.h:98
@ NPC_TESLA
Definition naxxramas.h:101
@ BOSS_THADDIUS
Definition naxxramas.h:39
@ GO_CONS_NOX_TESLA_FEUGEN
Definition naxxramas.h:160
@ GO_CONS_NOX_TESLA_STALAGG
Definition naxxramas.h:161
@ DATA_THADDIUS
Definition naxxramas.h:72
@ DATA_FEUGEN
Definition naxxramas.h:74
@ DATA_STALAGG
Definition naxxramas.h:75
#define RegisterNaxxramasCreatureAI(ai_name)
Definition naxxramas.h:221
void SetCombatMovement(bool allowMovement)
void AddThreat(Unit *victim, float amount, Unit *who=nullptr)
boss_thaddius(Creature *creature)
void KilledUnit(Unit *victim) override
void DoAction(int32 action) override
void EnterEvadeMode(EvadeReason why) override
void InitializeAI() override
bool CanAIAttack(Unit const *who) const override
uint32 GetData(uint32 id) const override
void JustDied(Unit *) override
void JustAppeared() override
void BeginResetEncounter()
void Reset() override
void UpdateAI(uint32 diff) override
void JustEngagedWith(Unit *who) override
InstanceScript * instance
void InitializeAI() override
void SpellHit(WorldObject *caster, SpellInfo const *spellInfo) override
void KilledUnit(Unit *victim) override
ObjectGuid _myCoil
uint32 magneticPullTimer
uint32 staticFieldTimer
GameObject * myCoilGO()
void UpdateAI(uint32 uiDiff) override
ObjectGuid _myCoilGO
Creature * myCoil()
void DoAction(int32 action) override
npc_feugen(Creature *creature)
void BeginResetEncounter()
void DamageTaken(Unit *, uint32 &damage, DamageEffectType, SpellInfo const *) override
void EnterEvadeMode(EvadeReason) override
Creature * myCoil()
void EnterEvadeMode(EvadeReason) override
ObjectGuid _myCoil
void KilledUnit(Unit *victim) override
InstanceScript * instance
void JustEngagedWith(Unit *who) override
void DoAction(int32 action) override
npc_stalagg(Creature *creature)
void UpdateAI(uint32 uiDiff) override
void InitializeAI() override
uint32 powerSurgeTimer
ObjectGuid _myCoilGO
void BeginResetEncounter()
GameObject * myCoilGO()
void DamageTaken(Unit *, uint32 &damage, DamageEffectType, SpellInfo const *) override
void SpellHit(WorldObject *caster, SpellInfo const *spellInfo) override
void JustEngagedWith(Unit *) override
void EnterEvadeMode(EvadeReason) override
npc_tesla(Creature *creature)
void UpdateAI(uint32) override
void DamageTaken(Unit *, uint32 &damage, DamageEffectType, SpellInfo const *) override