TrinityCore
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
30{
35};
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
72enum Misc
73{
76
78};
79
80// Feugen & Stalagg
82{
86
90
93
96};
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
127{
134
137
139{
143
147
148 // polarity handling
150
154
158};
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
301 me->SetUninteractible(false);
302
306 }
307
309 {
311 return;
312
313 // remove polarity shift debuffs on reset
316
317 me->DespawnOrUnsummon(0s, 30s);
318
320 me->SetImmuneToPC(true);
321 me->SetUninteractible(true);
322 me->setActive(false);
323 me->SetFarVisible(false);
325 feugen->AI()->DoAction(ACTION_BEGIN_RESET_ENCOUNTER);
327 stalagg->AI()->DoAction(ACTION_BEGIN_RESET_ENCOUNTER);
328 }
329
331 {
332 feugenAlive = true;
333 stalaggAlive = true;
334
335 _Reset();
338
339 // @todo these guys should really be moved to a summon group - this is merely a hack to make them work in dynamic_spawning
340 instance->instance->Respawn(SPAWN_TYPE_CREATURE, 130958); // Stalagg
341 instance->instance->Respawn(SPAWN_TYPE_CREATURE, 130959); // Feugen
342 }
343
344 void UpdateAI(uint32 diff) override
345 {
347 return;
349 return;
350
351 events.Update(diff);
352 while (uint32 eventId = events.ExecuteEvent())
353 {
354 switch (eventId)
355 {
357 feugenAlive = true;
359 feugen->AI()->DoAction(ACTION_FEUGEN_REVIVED);
360 break;
362 stalaggAlive = true;
364 stalagg->AI()->DoAction(ACTION_STALAGG_REVIVED);
365 break;
366 case EVENT_TRANSITION_1: // tesla coils overload
368 feugen->AI()->DoAction(ACTION_TRANSITION);
370 stalagg->AI()->DoAction(ACTION_TRANSITION);
371 break;
372 case EVENT_TRANSITION_2: // tesla coils shock thaddius
375 feugen->AI()->DoAction(ACTION_TRANSITION_2);
377 stalagg->AI()->DoAction(ACTION_TRANSITION_2);
378 break;
379 case EVENT_TRANSITION_3: // thaddius becomes active
381 ballLightningUnlocked = false;
383 me->SetImmuneToPC(false);
385
387 feugen->AI()->DoAction(ACTION_TRANSITION_3);
389 stalagg->AI()->DoAction(ACTION_TRANSITION_3);
390
392
394
400
401 break;
404 break;
405 case EVENT_ENGAGE:
407 break;
408 case EVENT_SHIFT:
409 me->CastStop(); // shift overrides all other spells
413 break;
414 case EVENT_SHIFT_TALK:
417 break;
418 case EVENT_CHAIN:
419 if (me->FindCurrentSpellBySpellId(SPELL_POLARITY_SHIFT)) // delay until shift is over
421 else
422 {
423 me->CastStop();
426 }
427 break;
428 case EVENT_BERSERK:
429 me->CastStop();
431 break;
432 default:
433 break;
434 }
435 }
436
438 {
440 ballLightningEnabled = false;
441 else if (ballLightningUnlocked)
444 }
445 }
446
447private:
450 bool ballLightningUnlocked; // whether the initial ball lightning grace period has expired and we should proceed to exterminate with extreme prejudice
451 bool ballLightningEnabled; // switch that is flipped to true if we try to evade due to no eligible targets in melee range
453};
454
455struct npc_stalagg : public ScriptedAI
456{
457public:
458 npc_stalagg(Creature* creature) : ScriptedAI(creature),
459 instance(creature->GetInstanceScript()), powerSurgeTimer(), _myCoil(ObjectGuid::Empty), _myCoilGO(ObjectGuid::Empty), isOverloading(false), refreshBeam(false), isFeignDeath(false)
460 {
461 instance = creature->GetInstanceScript();
463 }
464
465 void InitializeAI() override
466 {
467 if (GameObject* coil = myCoilGO())
468 coil->SetGoState(GO_STATE_ACTIVE);
469
471
472 // force tesla coil state refresh
473 refreshBeam = true;
474 }
475
476 void EnterEvadeMode(EvadeReason /*reason*/) override
477 {
479 thaddius->AI()->DoAction(ACTION_STALAGG_RESET);
480 }
481
483 {
484 if (GameObject* coil = myCoilGO())
485 coil->SetGoState(GO_STATE_READY);
486 me->DespawnOrUnsummon(0s, 7_days); // will be force respawned by thaddius
487 }
488
489 void DoAction(int32 action) override
490 {
491 switch (action)
492 {
495 break;
497 break;
499 if (!isFeignDeath)
500 break;
501
502 me->SetFullHealth();
505 me->SetUninteractible(false);
508 isFeignDeath = false;
509
510 refreshBeam = true; // force beam refresh
511
513 if (!me->IsEngaged())
515 break;
517 me->KillSelf(); // true death
518
519 if (Creature* coil = myCoil())
520 {
521 coil->CastStop();
522 coil->AI()->Talk(EMOTE_TESLA_OVERLOAD);
523 }
524 break;
526 if (Creature* coil = myCoil())
528 coil->CastSpell(thaddius, SPELL_SHOCK_VISUAL);
529 break;
531 if (GameObject* coil = myCoilGO())
532 coil->SetGoState(GO_STATE_READY);
533 me->DespawnOrUnsummon(0s, 7_days);
534 break;
535 default:
536 break;
537 }
538 }
539
540 void KilledUnit(Unit* victim) override
541 {
542 if (victim->GetTypeId() == TYPEID_PLAYER)
544 }
545
546 void JustEngagedWith(Unit* who) override
547 {
549
551 thaddius->AI()->DoAction(ACTION_STALAGG_AGGRO);
552
554 if (!feugen->IsEngaged())
555 AddThreat(who, 0.0f, feugen);
556 }
557
558 void DamageTaken(Unit* /*who*/, uint32& damage, DamageEffectType /*damageType*/, SpellInfo const* /*spellInfo = nullptr*/) override
559 {
560 if (damage < me->GetHealth())
561 return;
562
563 if (isFeignDeath) // don't take damage while feigning death
564 {
565 damage = 0;
566 return;
567 }
568
569 isFeignDeath = true;
570 isOverloading = false;
571
574 thaddius->AI()->DoAction(ACTION_STALAGG_DIED);
575
576 me->SetUninteractible(true);
579 me->AttackStop();
582
583 damage = me->GetHealth()-1;
584
585 // force beam refresh as we just removed auras
586 refreshBeam = true;
587 }
588
589 void SpellHit(WorldObject* caster, SpellInfo const* spellInfo) override
590 {
591 Creature* creatureCaster = caster->ToCreature();
592 if (!creatureCaster)
593 return;
594
595 if (spellInfo->Id != SPELL_STALAGG_TESLA_PERIODIC)
596 return;
597 if (!isFeignDeath && me->IsInCombat() && !me->GetHomePosition().IsInDist(me, OVERLOAD_DISTANCE))
598 {
599 if (!isOverloading)
600 {
601 isOverloading = true;
602 creatureCaster->SetImmuneToPC(false);
603 creatureCaster->AI()->Talk(EMOTE_TESLA_LINK_BREAKS);
605 }
607 {
608 creatureCaster->CastStop(SPELL_TESLA_SHOCK);
609 creatureCaster->CastSpell(target, SPELL_TESLA_SHOCK,true);
610 }
611 }
612 else if (isOverloading || refreshBeam)
613 {
614 isOverloading = false;
615 refreshBeam = false;
616 creatureCaster->CastStop();
617 creatureCaster->CastSpell(me, SPELL_STALAGG_CHAIN_VISUAL, true);
618 creatureCaster->SetImmuneToPC(true);
619 }
620 }
621
622 void UpdateAI(uint32 uiDiff) override
623 {
624 if (!isFeignDeath)
625 if (!UpdateVictim())
626 return;
627
628 if (powerSurgeTimer <= uiDiff)
629 {
630 if (isFeignDeath) // delay until potential revive
631 powerSurgeTimer = 0u;
632 else
633 {
635 powerSurgeTimer = urandms(25, 30);
636 }
637 }
638 else
639 powerSurgeTimer -= uiDiff;
640 }
641
642private:
644 {
645 Creature* coil = nullptr;
646 if (!_myCoil.IsEmpty())
648 if (!coil)
649 {
650 coil = me->FindNearestCreature(NPC_TESLA, 1000.0f, true);
651 if (coil)
652 {
653 _myCoil = coil->GetGUID();
655 }
656 }
657 return coil;
658 }
659
661 {
662 GameObject* coil = nullptr;
663 if (!_myCoilGO.IsEmpty())
665 if (!coil)
666 {
668 if (coil)
669 _myCoilGO = coil->GetGUID();
670 }
671 return coil;
672 }
673
675
677
683};
684
685struct npc_feugen : public ScriptedAI
686{
687public:
688 npc_feugen(Creature* creature) : ScriptedAI(creature),
689 instance(creature->GetInstanceScript()), magneticPullTimer(), staticFieldTimer(), _myCoil(ObjectGuid::Empty), _myCoilGO(ObjectGuid::Empty), isOverloading(false), refreshBeam(false), isFeignDeath(false)
690 {
691 instance = creature->GetInstanceScript();
693 }
694
695 void InitializeAI() override
696 {
697 if (GameObject* coil = myCoilGO())
698 coil->SetGoState(GO_STATE_ACTIVE);
699
702
703 // force coil state to refresh
704 refreshBeam = true;
705 }
706
707 void EnterEvadeMode(EvadeReason /*why*/) override
708 {
710 thaddius->AI()->DoAction(ACTION_FEUGEN_RESET);
711 }
712
714 {
715 if (GameObject* coil = myCoilGO())
716 coil->SetGoState(GO_STATE_READY);
717 me->DespawnOrUnsummon(0s, 7_days); // will be force respawned by thaddius
718 }
719
720 void DoAction(int32 action) override
721 {
722 switch (action)
723 {
726 break;
728 break;
730 if (!isFeignDeath)
731 break;
732
733 me->SetFullHealth();
736 me->SetUninteractible(false);
739 isFeignDeath = false;
740
741 refreshBeam = true; // force beam refresh
742
744 if (stalagg->GetVictim())
745 {
746 AddThreat(stalagg->EnsureVictim(), 0.0f);
747 me->SetInCombatWith(stalagg->EnsureVictim());
748 }
751 break;
753 me->KillSelf(); // true death this time around
754
755 if (Creature* coil = myCoil())
756 {
757 coil->CastStop();
758 coil->AI()->Talk(EMOTE_TESLA_OVERLOAD);
759 }
760 break;
762 if (Creature* coil = myCoil())
764 coil->CastSpell(thaddius, SPELL_SHOCK_VISUAL);
765 break;
767 if (GameObject* coil = myCoilGO())
768 coil->SetGoState(GO_STATE_READY);
769 me->DespawnOrUnsummon(0s, 7_days);
770 break;
771 default:
772 break;
773 }
774 }
775
776 void KilledUnit(Unit* victim) override
777 {
778 if (victim->GetTypeId() == TYPEID_PLAYER)
780 }
781
782 void JustEngagedWith(Unit* who) override
783 {
785
787 thaddius->AI()->DoAction(ACTION_FEUGEN_AGGRO);
788
790 if (!stalagg->IsInCombat())
791 AddThreat(who, 0.0f, stalagg);
792 }
793
794 void DamageTaken(Unit* /*who*/, uint32& damage, DamageEffectType /*damageType*/, SpellInfo const* /*spellInfo = nullptr*/) override
795 {
796 if (damage < me->GetHealth())
797 return;
798
799 if (isFeignDeath) // don't take damage while feigning death
800 {
801 damage = 0;
802 return;
803 }
804
805 isFeignDeath = true;
806 isOverloading = false;
807
810 thaddius->AI()->DoAction(ACTION_FEUGEN_DIED);
811
812 me->SetUninteractible(true);
815 me->AttackStop();
818
819 damage = me->GetHealth()-1;
820
821 // force beam refresh as we just removed auras
822 refreshBeam = true;
823 }
824
825 void SpellHit(WorldObject* caster, SpellInfo const* spellInfo) override
826 {
827 Creature* creatureCaster = caster->ToCreature();
828 if (!creatureCaster)
829 return;
830
831 if (spellInfo->Id != SPELL_FEUGEN_TESLA_PERIODIC)
832 return;
833
834 if (!isFeignDeath && me->IsInCombat() && !me->GetHomePosition().IsInDist(me, OVERLOAD_DISTANCE))
835 {
836 if (!isOverloading)
837 {
838 isOverloading = true;
839 creatureCaster->SetImmuneToPC(false);
840 creatureCaster->AI()->Talk(EMOTE_TESLA_LINK_BREAKS);
842 }
844 {
845 creatureCaster->CastStop(SPELL_TESLA_SHOCK);
846 creatureCaster->CastSpell(target, SPELL_TESLA_SHOCK,true);
847 }
848 }
849 else if (isOverloading || refreshBeam)
850 {
851 isOverloading = false;
852 refreshBeam = false;
853 creatureCaster->CastStop();
854 creatureCaster->CastSpell(me, SPELL_FEUGEN_CHAIN_VISUAL, true);
855 creatureCaster->SetImmuneToPC(true);
856 }
857 }
858
859 void UpdateAI(uint32 uiDiff) override
860 {
861 if (isFeignDeath)
862 return;
863 if (!UpdateVictim())
864 return;
865
866 if (magneticPullTimer <= uiDiff)
867 {
870 }
871 else magneticPullTimer -= uiDiff;
872
873 if (staticFieldTimer <= uiDiff)
874 {
877 }
878 else staticFieldTimer -= uiDiff;
879 }
880
881private:
883 {
884 Creature* coil = nullptr;
885 if (!_myCoil.IsEmpty())
887 if (!coil)
888 {
889 coil = me->FindNearestCreature(NPC_TESLA, 1000.0f, true);
890 if (coil)
891 {
892 _myCoil = coil->GetGUID();
894 }
895 }
896 return coil;
897 }
898
900 {
901 GameObject* coil = nullptr;
902 if (!_myCoilGO.IsEmpty())
904 if (!coil)
905 {
907 if (coil)
908 _myCoilGO = coil->GetGUID();
909 }
910 return coil;
911 }
913
916
919
923};
924
925struct npc_tesla : public ScriptedAI
926{
927 npc_tesla(Creature* creature) : ScriptedAI(creature) { }
928
929 void EnterEvadeMode(EvadeReason /*why*/) override { } // never stop casting due to evade
930 void UpdateAI(uint32 /*diff*/) override { } // never do anything unless told
931 void JustEngagedWith(Unit* /*who*/) override { }
932 void DamageTaken(Unit* /*who*/, uint32& damage, DamageEffectType /*damageType*/, SpellInfo const* /*spellInfo = nullptr*/) override { damage = 0; } // no, you can't kill it
933};
934
935// 28062 - Positive Charge
936// 28085 - Negative Charge
938{
939 bool Validate(SpellInfo const* /*spell*/) override
940 {
941 return ValidateSpellInfo(
942 {
950 });
951 }
952
953 void HandleTargets(std::list<WorldObject*>& targetList)
954 {
955 if (!GetTriggeringSpell())
956 return;
957
958 uint32 triggeringId = GetTriggeringSpell()->Id;
959 uint32 ampId;
960 switch (triggeringId)
961 {
964 break;
967 break;
968 default:
969 return;
970 }
971
972 uint8 maxStacks = 0;
973 if (GetCaster())
974 switch (GetCaster()->GetMap()->GetDifficultyID())
975 {
976 case DIFFICULTY_10_N:
977 maxStacks = MAX_POLARITY_10M;
978 break;
979 case DIFFICULTY_25_N:
980 maxStacks = MAX_POLARITY_25M;
981 break;
982 default:
983 break;
984 }
985
986 uint8 stacksCount = 1; // do we get a stack for our own debuff?
987 std::list<WorldObject*>::iterator it = targetList.begin();
988 while(it != targetList.end())
989 {
990 if ((*it)->GetTypeId() != TYPEID_PLAYER)
991 {
992 it = targetList.erase(it);
993 continue;
994 }
995 if ((*it)->ToPlayer()->HasAura(triggeringId))
996 {
997 it = targetList.erase(it);
998 if (stacksCount < maxStacks)
999 stacksCount++;
1000 continue;
1001 }
1002
1003 // this guy will get hit - achievement failure trigger
1004 if (Creature* thaddius = (*it)->FindNearestCreature(NPC_THADDIUS, 200.0f))
1005 thaddius->AI()->DoAction(ACTION_POLARITY_CROSSED);
1006
1007 ++it;
1008 }
1009
1010 if (GetCaster() && GetCaster()->ToPlayer())
1011 {
1012 if (!GetCaster()->ToPlayer()->HasAura(ampId))
1013 GetCaster()->ToPlayer()->AddAura(ampId, GetCaster());
1014 GetCaster()->ToPlayer()->SetAuraStack(ampId, GetCaster(), stacksCount);
1015 }
1016 }
1017
1018 void Register() override
1019 {
1021 }
1022};
1023
1024// 28089 - Polarity Shift
1026{
1027 bool Validate(SpellInfo const* /*spell*/) override
1028 {
1029 return ValidateSpellInfo(
1030 {
1038 });
1039 }
1040
1041 void HandleDummy(SpellEffIndex /*effIndex*/)
1042 {
1043 if (Unit* target = GetHitUnit())
1044 if (target->GetTypeId() == TYPEID_PLAYER)
1045 {
1046 if (roll_chance_i(50))
1047 { // positive
1048 target->CastSpell(target, SPELL_POSITIVE_CHARGE_APPLY, true);
1049 target->RemoveAura(SPELL_POSITIVE_CHARGE_AMP);
1050 }
1051 else
1052 { // negative
1053 target->CastSpell(target, SPELL_NEGATIVE_CHARGE_APPLY, true);
1054 target->RemoveAura(SPELL_NEGATIVE_CHARGE_AMP);
1055 }
1056 }
1057 }
1058
1059 void Register() override
1060 {
1062 }
1063};
1064
1065// 54517 - Magnetic Pull
1067{
1068 bool Validate(SpellInfo const* /*spell*/) override
1069 {
1071 }
1072
1073 void HandleCast() // only feugen ever casts this according to wowhead data
1074 {
1075 Unit* feugen = GetCaster();
1076 if (!feugen || feugen->GetEntry() != NPC_FEUGEN)
1077 return;
1078
1080 if (!stalagg)
1081 return;
1082
1083 ThreatManager& feugenThreat = feugen->GetThreatManager();
1084 ThreatManager& stalaggThreat = stalagg->GetThreatManager();
1085
1086 Unit* feugenTank = feugenThreat.GetCurrentVictim();
1087 Unit* stalaggTank = stalaggThreat.GetCurrentVictim();
1088
1089 if (!feugenTank || !stalaggTank)
1090 return;
1091
1092 if (feugenTank == stalaggTank) // special behavior if the tanks are the same (taken from retail)
1093 {
1094 float feugenTankThreat = feugenThreat.GetThreat(feugenTank);
1095 float stalaggTankThreat = stalaggThreat.GetThreat(stalaggTank);
1096
1097 feugen->GetThreatManager().AddThreat(feugenTank, stalaggTankThreat - feugenTankThreat, nullptr, true, true);
1098 stalagg->GetThreatManager().AddThreat(stalaggTank, feugenTankThreat - stalaggTankThreat, nullptr, true, true);
1099
1100 feugen->CastSpell(stalaggTank, SPELL_MAGNETIC_PULL_EFFECT, true);
1101 }
1102 else // normal case, two tanks
1103 {
1104 float feugenTankThreat = feugenThreat.GetThreat(feugenTank);
1105 float feugenOtherThreat = feugenThreat.GetThreat(stalaggTank);
1106 float stalaggTankThreat = stalaggThreat.GetThreat(stalaggTank);
1107 float stalaggOtherThreat = stalaggThreat.GetThreat(feugenTank);
1108
1109 // set the two entries in feugen's threat table to be equal to the ones in stalagg's
1110 feugen->GetThreatManager().AddThreat(stalaggTank, stalaggTankThreat - feugenOtherThreat, nullptr, true, true);
1111 feugen->GetThreatManager().AddThreat(feugenTank, stalaggOtherThreat - feugenTankThreat, nullptr, true, true);
1112
1113 // set the two entries in stalagg's threat table to be equal to the ones in feugen's
1114 stalagg->GetThreatManager().AddThreat(feugenTank, feugenTankThreat - stalaggOtherThreat, nullptr, true, true);
1115 stalagg->GetThreatManager().AddThreat(stalaggTank, feugenOtherThreat - stalaggTankThreat, nullptr, true, true);
1116
1117 // pull the two tanks across
1118 feugenTank->CastSpell(stalaggTank, SPELL_MAGNETIC_PULL_EFFECT, true);
1119 stalaggTank->CastSpell(feugenTank, SPELL_MAGNETIC_PULL_EFFECT, true);
1120
1121 // @hack prevent mmaps clusterfucks from breaking tesla while tanks are midair
1122 feugen->AddAura(SPELL_ROOT_SELF, feugen);
1123 stalagg->AddAura(SPELL_ROOT_SELF, stalagg);
1124
1125 // and make both attack their respective new tanks
1126 if (feugen->GetAI())
1127 feugen->GetAI()->AttackStart(stalaggTank);
1128 if (stalagg->GetAI())
1129 stalagg->GetAI()->AttackStart(feugenTank);
1130 }
1131 }
1132
1133 void Register() override
1134 {
1136 }
1137};
1138
1140{
1141 public:
1142 at_thaddius_entrance() : OnlyOnceAreaTriggerScript("at_thaddius_entrance") { }
1143
1144 bool TryHandleOnce(Player* player, AreaTriggerEntry const* /*areaTrigger*/) override
1145 {
1146 InstanceScript* instance = player->GetInstanceScript();
1147 if (!instance || instance->GetBossState(BOSS_THADDIUS) == DONE)
1148 return true;
1149
1150 if (Creature* thaddius = ObjectAccessor::GetCreature(*player, instance->GetGuidData(DATA_THADDIUS)))
1151 thaddius->AI()->Talk(SAY_GREET);
1152
1153 return true;
1154 }
1155};
1156
1158{
1159 public:
1160 achievement_thaddius_shocking() : AchievementCriteriaScript("achievement_thaddius_shocking") { }
1161
1162 bool OnCheck(Player* /*source*/, Unit* target) override
1163 {
1164 return target && target->GetAI() && target->GetAI()->GetData(DATA_POLARITY_CROSSED);
1165 }
1166};
1167
1169{
1174
1178
1180
1182}
@ IN_MILLISECONDS
Definition: Common.h:35
@ DIFFICULTY_10_N
Definition: DBCEnums.h:877
@ DIFFICULTY_25_N
Definition: DBCEnums.h:878
uint8_t uint8
Definition: Define.h:144
int32_t int32
Definition: Define.h:138
uint32_t uint32
Definition: Define.h:142
std::chrono::seconds Seconds
Seconds shorthand typedef.
Definition: Duration.h:32
@ IN_PROGRESS
@ DONE
@ TYPEID_PLAYER
Definition: ObjectGuid.h:41
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:1369
SpellEffIndex
Definition: SharedDefines.h:29
@ EFFECT_0
Definition: SharedDefines.h:30
@ TARGET_UNIT_SRC_AREA_ALLY
@ SPELL_EFFECT_DUMMY
@ GO_STATE_READY
@ GO_STATE_ACTIVE
@ SPAWN_TYPE_CREATURE
Definition: SpawnData.h:34
#define SpellEffectFn(F, I, N)
Definition: SpellScript.h:842
#define SpellObjectAreaTargetSelectFn(F, I, N)
Definition: SpellScript.h:864
#define SpellCastFn(F)
Definition: SpellScript.h:825
EvadeReason
Definition: UnitAICommon.h:30
@ REACT_PASSIVE
Definition: UnitDefines.h:506
@ REACT_AGGRESSIVE
Definition: UnitDefines.h:508
@ UNIT_STAND_STATE_DEAD
Definition: UnitDefines.h:49
@ UNIT_STAND_STATE_STAND
Definition: UnitDefines.h:42
DamageEffectType
Definition: UnitDefines.h:131
@ UNIT_FLAG_STUNNED
Definition: UnitDefines.h:162
@ UNIT_STATE_ROOT
Definition: Unit.h:265
@ UNIT_STATE_CASTING
Definition: Unit.h:270
@ 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
PetMisc
@ 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
void _JustDied()
void DoZoneInCombat()
Definition: CreatureAI.h:161
void Talk(uint8 id, WorldObject const *whisperTarget=nullptr)
Definition: CreatureAI.cpp:56
bool UpdateVictim()
Definition: CreatureAI.cpp:245
void SetBoundary(CreatureBoundary const *boundary, bool negativeBoundaries=false)
Definition: CreatureAI.cpp:446
Creature *const me
Definition: CreatureAI.h:61
void SetImmuneToPC(bool apply) override
Definition: Creature.h:170
void GetHomePosition(float &x, float &y, float &z, float &ori) const
Definition: Creature.h:373
bool IsEngaged() const override
Definition: Creature.cpp:3601
void SetReactState(ReactStates st)
Definition: Creature.h:160
void DespawnOrUnsummon(Milliseconds timeToDespawn=0s, Seconds forceRespawnTime=0s)
Definition: Creature.cpp:2415
CreatureAI * AI() const
Definition: Creature.h:214
uint32 ExecuteEvent()
Definition: EventMap.cpp:73
void Update(uint32 time)
Definition: EventMap.h:56
void Repeat(Milliseconds time)
Definition: EventMap.cpp:63
void ScheduleEvent(uint32 eventId, Milliseconds time, uint32 group=0, uint8 phase=0)
Definition: EventMap.cpp:36
bool IsInPhase(uint8 phase) const
Definition: EventMap.h:217
void SetPhase(uint8 phase)
Definition: EventMap.cpp:28
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:2058
bool IsEmpty() const
Definition: ObjectGuid.h:319
static Creature * ToCreature(Object *o)
Definition: Object.h:219
TypeID GetTypeId() const
Definition: Object.h:173
uint32 GetEntry() const
Definition: Object.h:161
static ObjectGuid GetGUID(Object const *o)
Definition: Object.h:159
static Player * ToPlayer(Object *o)
Definition: Object.h:213
uint32 const Id
Definition: SpellInfo.h:325
static bool ValidateSpellInfo(std::initializer_list< uint32 > spellIds)
Definition: SpellScript.h:162
Unit * GetCaster() const
SpellInfo const * GetTriggeringSpell() const
Unit * GetHitUnit() const
HookList< EffectHandler > OnEffectHitTarget
Definition: SpellScript.h:840
HookList< CastHandler > OnCast
Definition: SpellScript.h:822
HookList< ObjectAreaTargetSelectHandler > OnObjectAreaTargetSelect
Definition: SpellScript.h:863
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
virtual void AttackStart(Unit *victim)
Definition: UnitAI.cpp:29
virtual uint32 GetData(uint32) const
Definition: UnitAI.h:73
SpellCastResult DoCastVictim(uint32 spellId, CastSpellExtraArgs const &args={})
Definition: UnitAI.cpp:180
Unit * SelectTarget(SelectTargetMethod targetType, uint32 offset=0, float dist=0.0f, bool playerOnly=false, bool withTank=true, int32 aura=0)
Definition: UnitAI.cpp:79
SpellCastResult DoCastAOE(uint32 spellId, CastSpellExtraArgs const &args={})
Definition: UnitAI.h:161
SpellCastResult DoCast(uint32 spellId)
Definition: UnitAI.cpp:89
Definition: Unit.h:627
void CastStop(uint32 except_spellid=0)
Definition: Unit.cpp:1135
bool IsWithinMeleeRange(Unit const *obj) const
Definition: Unit.h:699
void RemoveAura(AuraApplicationMap::iterator &i, AuraRemoveMode mode=AURA_REMOVE_BY_DEFAULT)
Definition: Unit.cpp:3685
void SetFullHealth()
Definition: Unit.h:790
void SetStandState(UnitStandStateType state, uint32 animKitID=0)
Definition: Unit.cpp:10100
ThreatManager & GetThreatManager()
Definition: Unit.h:1063
void SetInCombatWith(Unit *enemy, bool addSecondUnitSuppressed=false)
Definition: Unit.h:1045
void SetControlled(bool apply, UnitState state)
Definition: Unit.cpp:10911
Spell * FindCurrentSpellBySpellId(uint32 spell_id) const
Definition: Unit.cpp:3104
void SetAuraStack(uint32 spellId, Unit *target, uint32 stack)
Definition: Unit.cpp:11665
Aura * AddAura(uint32 spellId, Unit *target)
Definition: Unit.cpp:11618
bool IsAlive() const
Definition: Unit.h:1164
UnitAI * GetAI() const
Definition: Unit.h:660
void SetUninteractible(bool apply)
Definition: Unit.cpp:8147
uint64 GetHealth() const
Definition: Unit.h:776
Unit * GetVictim() const
Definition: Unit.h:715
bool HasUnitState(const uint32 f) const
Definition: Unit.h:732
void RemoveAllAuras()
Definition: Unit.cpp:4242
void SetUnitFlag(UnitFlags flags)
Definition: Unit.h:833
bool isAttackReady(WeaponAttackType type=BASE_ATTACK) const
Definition: Unit.h:690
void KillSelf(bool durabilityLoss=true, bool skipSettingDeathState=false)
Definition: Unit.h:921
bool AttackStop()
Definition: Unit.cpp:5781
bool IsInCombat() const
Definition: Unit.h:1043
GameObject * FindNearestGameObject(uint32 entry, float range, bool spawnedOnly=true) const
Definition: Object.cpp:2170
InstanceScript * GetInstanceScript() const
Definition: Object.cpp:1042
SpellCastResult CastSpell(CastSpellTargetArg const &targets, uint32 spellId, CastSpellExtraArgs const &args={ })
Definition: Object.cpp:2896
void setActive(bool isActiveObject)
Definition: Object.cpp:922
void SetFarVisible(bool on)
Definition: Object.cpp:973
Creature * FindNearestCreature(uint32 entry, float range, bool alive=true) const
Definition: Object.cpp:2148
bool OnCheck(Player *, Unit *target) override
bool TryHandleOnce(Player *player, AreaTriggerEntry const *) override
bool Validate(SpellInfo const *) override
void HandleTargets(std::list< WorldObject * > &targetList)
bool Validate(SpellInfo const *) override
void HandleDummy(SpellEffIndex)
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
bool ballLightningUnlocked
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