TrinityCore
boss_kelthuzad.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 "MotionMaster.h"
22#include "naxxramas.h"
23#include "ObjectAccessor.h"
24#include "Player.h"
25#include "PlayerAI.h"
26#include "ScriptedCreature.h"
27#include "SpellAuraEffects.h"
28#include "SpellScript.h"
29#include "TemporarySummon.h"
30
32{
37 SAY_REQUEST_AID = 12, //start of phase 3
39 SAY_SUMMON_MINIONS = 14, //start of phase 1
41
42 // The Lich King
44
45 // Guardian of Icecrown
48};
49
51{
52 // phase one
58
59 // phase two
65
66 // phase three transition
69};
70
72{
77};
78
80{
83};
84
86{
87 // Kel'thuzad - Phase one
88 SPELL_VISUAL_CHANNEL = 29423, // channeled throughout phase one
89
90 // Kel'thuzad - Phase two
98 SPELL_CHAINS = 28410,
99 SPELL_CHAINS_DUMMY = 28408, // this holds the category cooldown - the main chains spell can't have one as it is cast multiple times
100
102
103 // Unstoppable Abomination
105
106 // Guardian of Icecrown
108
109 // Shadow Fissure
110 SPELL_VOID_BLAST = 27812
112
113static const uint8 nGuardianSpawns = 4;
114static const uint8 nMinionGroups = 7;
116{
118 SUMMON_GROUP_MINION_FIRST = 05 /*..11 */
121
123{
125 PHASE_TWO = 2 // "phase three" is not actually a phase in events, as timers from phase two carry over
127
129{
131};
132
134{
135 NPC_SKELETON1 = 16427, // Soldiers of the Frozen Wastes
137 NPC_ABOMINATION1 = 16428, // Unstoppable Abominations
139 NPC_BANSHEE1 = 16429, // Soul Weavers
141 NPC_GUARDIAN = 16441 // Guardians of Icecrown
143
144static const uint8 nMinionSpawnPoints = 7;
146 { 3768.40f, -5072.00f, 143.65f }, // summon group 5
147 { 3729.30f, -5044.10f, 143.65f }, // summon group 6
148 { 3683.00f, -5054.05f, 143.65f }, // summon group 7
149 { 3654.15f, -5093.48f, 143.65f }, // summon group 8
150 { 3664.55f, -5140.50f, 143.65f }, // summon group 9
151 { 3704.00f, -5170.00f, 143.65f }, // summon group 10
152 { 3751.95f, -5158.90f, 143.65f } // summon group 11
153};
155{
157}
158
159// uniformly distribute on the circle
160static Position GetRandomPositionOnCircle(Position const& center, float radius)
161{
162 float angle = float(M_PI * rand_norm() * 2.0);
163 float relDistance = rand_norm() + rand_norm();
164 if (relDistance > 1)
165 relDistance = 1 - relDistance;
166 return Position(center.GetPositionX() + std::sin(angle) * relDistance * radius, center.GetPositionY() + std::cos(angle) * relDistance * radius, center.GetPositionZ());
167}
168
170{
171 public:
173
175 {
176 bool operator()(Unit const* target) const
177 {
178 Player const* pTarget = target->ToPlayer();
179 if (!pTarget)
180 return false;
181 if (pTarget->HasAura(SPELL_CHAINS))
182 return false;
184 return false;
185 // We _really_ dislike healers. So we hit them in the face. Repeatedly. Exclusively.
186 return PlayerAI::IsPlayerHealer(pTarget);
187 }
188 };
189
190 Unit* SelectAttackTarget() const override
191 {
192 if (Creature* charmer = GetCharmer())
193 {
194 if (Unit* target = charmer->AI()->SelectTarget(SelectTargetMethod::Random, 0, CharmedPlayerTargetSelectPred()))
195 return target;
196 if (Unit* target = charmer->AI()->SelectTarget(SelectTargetMethod::Random, 0, 0.0f, true, true, -SPELL_CHAINS))
197 return target;
198 }
199 return nullptr;
200 }
201};
202
204{
205 bool operator()(Unit const* target) const
206 {
207 return target->GetTypeId() == TYPEID_PLAYER && target->GetPowerType() == POWER_MANA;
208 }
209};
210
211struct boss_kelthuzad : public BossAI
212{
213 public:
215 {
216 for (uint8 i = 0; i < nGuardianSpawns; ++i)
218 }
219
220 void Reset() override
221 {
222 if (!me->IsAlive())
223 return;
224 _Reset();
226 me->SetUninteractible(true);
227 me->SetImmuneToPC(true);
228 _skeletonCount = 0;
229 _bansheeCount = 0;
232 _phaseThree = false;
233 }
234
235 void EnterEvadeMode(EvadeReason /*why*/) override
236 {
237 if (!me->IsAlive())
238 return;
239
240 for (NAXData64 portalData : portalList)
241 if (GameObject* portal = ObjectAccessor::GetGameObject(*me, instance->GetGuidData(portalData)))
242 portal->SetGoState(GO_STATE_READY);
243
244 Reset();
246 }
247
248 void JustSummoned (Creature* summon) override
249 { // prevent DoZoneInCombat
250 summons.Summon(summon);
251 }
252
253 void KilledUnit(Unit* victim) override
254 {
255 if (victim->GetTypeId() == TYPEID_PLAYER)
256 Talk(SAY_SLAY);
257 }
258
259 void JustDied(Unit* /*killer*/) override
260 {
262 while (it != summons.end())
263 if (Creature* cSummon = ObjectAccessor::GetCreature(*me, *it))
264 {
265 if (cSummon->IsAlive() && cSummon->GetEntry() == NPC_GUARDIAN)
266 {
267 cSummon->AI()->DoAction(ACTION_KELTHUZAD_DIED);
268 it = summons.erase(it); // prevent them from being despawned by _JustDied
269 }
270 else
271 ++it;
272 }
273
274 _JustDied();
276 }
277
278 void DamageTaken(Unit* /*attacker*/, uint32& damage, DamageEffectType /*damageType*/, SpellInfo const* /*spellInfo = nullptr*/) override
279 {
281 damage = 0;
282 }
283
284 void SpellHit(WorldObject* /*caster*/, SpellInfo const* spellInfo) override
285 {
286 if (spellInfo->Id == SPELL_CHAINS_DUMMY)
287 {
289 std::list<Unit*> targets;
290 SelectTargetList(targets, 3, SelectTargetMethod::Random, 0, 0.0f, true, false);
291 for (Unit* target : targets)
292 DoCast(target, SPELL_CHAINS);
293 }
294 }
295
296 void UpdateAI(uint32 diff) override
297 {
298 if (!UpdateVictim())
299 return;
300
301 events.Update(diff);
302
303 if (_frostboltCooldown < diff)
305 else
306 _frostboltCooldown -= diff;
307
309 return;
310
311 if (!_phaseThree && HealthBelowPct(45))
312 {
313 _phaseThree = true;
314 _guardianCount = 0;
319 if (Is25ManRaid())
320 {
323 }
324 }
325
326 while (uint32 eventId = events.ExecuteEvent())
327 {
328 if (_frostboltCooldown <= 4 * IN_MILLISECONDS) // stop casting bolts for 4 seconds after doing another action
330 switch (eventId)
331 {
332 case EVENT_SKELETON:
333 {
335 if (_skeletonCount == 1) // the first skeleton is actually one of the pre-existing ones - I'm not sure why, but that's what the sniffs say
336 {
337 std::list<Creature*> skeletons;
339 if (skeletons.empty())
340 { // prevent UB
342 return;
343 }
344 std::list<Creature*>::iterator it = skeletons.begin();
345 std::advance(it, urand(0, skeletons.size() - 1));
346 (*it)->SetReactState(REACT_AGGRESSIVE);
347 (*it)->AI()->DoZoneInCombat(); // will select a player on our threat list as we are the summoner
348 }
349 else
350 {
351 // retail uses server-side spell 28421 for this
353 summon->AI()->DoZoneInCombat();
354 }
355
356 uint8 nextTime = 0;
357 if (_skeletonCount < 10)
358 nextTime = 5;
359 else if (_skeletonCount < 19)
360 nextTime = 4;
361 else if (_skeletonCount < 31)
362 nextTime = 3;
363 else if (_skeletonCount == 31)
364 nextTime = 4;
365 else if (_skeletonCount < 72)
366 nextTime = 2;
367
368 if (nextTime)
370 break;
371 }
372
373 case EVENT_BANSHEE:
374 {
376 // retail uses server-side spell 28423 for this
378 summon->AI()->DoZoneInCombat();
379
380 uint8 nextTime = 0;
381 if (_bansheeCount < 3)
382 nextTime = 30;
383 else if (_bansheeCount < 7)
384 nextTime = 20;
385 else if (_bansheeCount < 9)
386 nextTime = 15;
387
388 if (nextTime)
390 break;
391 }
392
394 {
396 // retail uses server-side spell 28422 for this
398 summon->AI()->DoZoneInCombat();
399
400 uint8 nextTime = 0;
401 if (_abominationCount < 3)
402 nextTime = 30;
403 else if (_abominationCount < 7)
404 nextTime = 20;
405 else if (_abominationCount < 9)
406 nextTime = 15;
407
408 if (nextTime)
410 break;
411 }
412
414 {
415 // we need a temp vector, as we can't modify summons while iterating (this would cause UB)
416 std::vector<Creature*> toDespawn;
417 toDespawn.reserve(summons.size());
418 for (ObjectGuid sGuid : summons)
419 if (Creature* summon = ObjectAccessor::GetCreature(*me, sGuid))
420 if (!summon->IsInCombat())
421 toDespawn.push_back(summon);
422 for (Creature* summon : toDespawn)
423 summon->DespawnOrUnsummon();
425 break;
426 }
427
428 case EVENT_PHASE_TWO:
429 me->CastStop();
431 me->SetUninteractible(false);
432 me->SetImmuneToPC(false);
436
442 if (Is25ManRaid())
444 break;
445
449 break;
450
452 if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 0.0f, true))
455 break;
456
458 {
460 if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, pred))
463 break;
464 }
465
467 if (Unit* target = SelectTarget(SelectTargetMethod::Random, 1, 0.0f, true))
468 DoCast(target, SPELL_FROST_BLAST);
470 break;
471
472 case EVENT_CHAINS:
473 {
476 break;
477 }
478
481 lichKing->AI()->Talk(SAY_ANSWER_REQUEST);
482 for (NAXData64 portalData : portalList)
483 if (GameObject* portal = ObjectAccessor::GetGameObject(*me, instance->GetGuidData(portalData)))
484 portal->SetGoState(GO_STATE_ACTIVE);
485 break;
486
488 {
489 uint8 selected = urand(_guardianCount, nGuardianSpawns - 1);
490 if (selected != _guardianCount)
491 std::swap(_guardianGroups[selected], _guardianGroups[_guardianCount]);
492
493 std::list<TempSummon*> summoned;
494 // server-side spell 28454 is used on retail - no point replicating this in spell_dbc
496 for (TempSummon* guardian : summoned)
497 guardian->AI()->DoAction(ACTION_JUST_SUMMONED);
498 break;
499 }
500 }
501
503 return;
504 }
505
507 {
510 }
511 }
512
513 uint32 GetData(uint32 data) const override
514 {
517 return 0;
518 }
519
520 void DoAction(int32 action) override
521 {
522 switch (action)
523 {
526 return;
527 me->SetImmuneToPC(false);
533
535 {
536 std::list<TempSummon*> summoned;
537 me->SummonCreatureGroup(group, &summoned);
538 for (TempSummon* summon : summoned)
539 {
540 summon->SetReactState(REACT_PASSIVE);
541 summon->AI()->SetData(DATA_MINION_POCKET_ID, group);
542 }
543 }
544
550 break;
551
554 break;
555
556 default:
557 break;
558 }
559 }
560
562 {
563 return new KelThuzadCharmedPlayerAI(player);
564 }
565
566 private:
574 std::array<uint32, nGuardianSpawns> _guardianGroups;
575};
576
577static const float MINION_AGGRO_DISTANCE = 20.0f;
578// @hack the entire _movementTimer logic only exists because RandomMovementGenerator gets really confused due to the unique map geography of KT's room (it's placed on top of a copy of Winterspring).
579// As of the time of writing, RMG sometimes selects positions on the "floor" below the room, causing Abominations to path wildly through the room.
580// This custom movement code prevents this by simply ignoring z coord calculation (the floor of the minion coves is flat anyway).
581// Dev from the future that is reading this, if RMG has been fixed on the current core revision, please get rid of this hack. Thank you!
583{
584 public:
585 npc_kelthuzad_minionAI(Creature* creature) : ScriptedAI(creature), instance(creature->GetInstanceScript()), pocketId(0), _movementTimer(urandms(4,12)), _home(me->GetPosition()) { }
586
587 void Reset() override
588 {
589 }
590
591 void EnterEvadeMode(EvadeReason why) override
592 {
595 kelThuzad->AI()->EnterEvadeMode(EvadeReason::Other);
596 }
597
598 void JustEngagedWith(Unit* who) override
599 {
600 _movementTimer = 0; // once it's zero, it'll never get checked again
602 {
604 return;
605 }
606
607 if (!pocketId)
608 return;
609
610 std::list<Creature*> others;
611 me->GetCreatureListWithEntryInGrid(others, me->GetEntry(), 80.0f);
612 for (Creature* other : others)
613 if (other->AI()->GetData(DATA_MINION_POCKET_ID) == pocketId)
614 {
615 other->SetReactState(REACT_AGGRESSIVE);
616 other->AI()->AttackStart(who);
617 }
619 AttackStart(who);
621 }
622
623 void AttackStart(Unit* who) override
624 {
626 }
627
628 void MoveInLineOfSight(Unit* who) override
629 {
631 {
633 return;
634 }
635
636 if (me->CanStartAttack(who, false) && me->GetDistance2d(who) <= MINION_AGGRO_DISTANCE)
637 JustEngagedWith(who);
638 }
639
640 void SetData(uint32 data, uint32 value) override
641 {
642 if (data == DATA_MINION_POCKET_ID)
643 pocketId = value;
644 }
645
646 uint32 GetData(uint32 data) const override
647 {
648 if (data == DATA_MINION_POCKET_ID)
649 return pocketId;
650 return 0;
651 }
652
653 void MovementInform(uint32 /*type*/, uint32 id) override
654 {
655 if (id == MOVEMENT_MINION_RANDOM)
656 _movementTimer = urandms(2, 10) + urandms(2, 10);
657 }
658
660 {
661 if (!_movementTimer)
662 return;
663
664 if (_movementTimer <= diff)
665 {
666 _movementTimer = 0;
668 }
669 else
670 _movementTimer -= diff;
671 }
672
673 protected:
676
677 private:
680};
681
683{
685
686 void UpdateAI(uint32 diff) override
687 {
689
690 if (!UpdateVictim())
691 return;
692 }
693};
694
696{
698
699 void UpdateAI(uint32 diff) override
700 {
702
703 if (!UpdateVictim())
704 return;
705 }
706};
707
709{
711
712 void UpdateAI(uint32 diff) override
713 {
715
716 if (!UpdateVictim())
717 return;
718
719 if (_woundTimer <= diff)
720 {
721 _woundTimer = urandms(14, 18);
723 }
724 else
725 _woundTimer -= diff;
726 }
727
728 void JustDied(Unit* killer) override
729 {
731 kelThuzad->AI()->DoAction(ACTION_ABOMINATION_DIED);
733 }
734
736};
737
739{
740 public:
741 npc_kelthuzad_guardian(Creature* creature) : ScriptedAI(creature), instance(creature->GetInstanceScript()), _visibilityTimer(0), _bloodTapTimer(0) { }
742
743 void DoAction(int32 action) override
744 {
745 switch (action)
746 {
748 me->SetVisible(false);
754 break;
759 me->CombatStop();
760 me->StopMoving();
761 me->SetImmuneToPC(true);
762 me->DespawnOrUnsummon(30s); // just in case anything interrupts the movement
764 break;
765 default:
766 break;
767 }
768 }
769
770 void EnterEvadeMode(EvadeReason why) override
771 {
773 kelthuzad->AI()->EnterEvadeMode();
775 }
776
777 void JustReachedHome() override
778 {
780 }
781
782 void Reset() override
783 {
786 }
787
788 void UpdateAI(uint32 diff) override
789 {
791 {
792 if (diff > _visibilityTimer)
793 _visibilityTimer -= diff;
794 else
795 {
796 me->SetVisible(true);
799 }
800 }
801
802 if (!UpdateVictim())
803 return;
804
805 if (_bloodTapTimer <= diff)
806 {
808 _bloodTapTimer = urandms(18, 26);
809 }
810 else
811 _bloodTapTimer -= diff;
812 }
813
814 private:
818};
819
821{
823
824 void InitializeAI() override
825 {
827 }
828
829 void JustAppeared() override
830 {
831 _scheduler.Schedule(5s, [this](TaskContext /*task*/)
832 {
834 });
835 }
836
837 void UpdateAI(uint32 diff) override
838 {
839 _scheduler.Update(diff);
840 }
841
842private:
844};
845
846// 28410 - Chains of Kel'Thuzad
848{
850 {
851 aurEff->HandleAuraModScale(GetTargetApplication(), mode, true);
852 }
853
855 {
856 aurEff->HandleAuraModScale(GetTargetApplication(), mode, false);
857 }
858
859 void Register() override
860 {
863 }
864};
865
866// 27819 - Detonate Mana
868{
869 bool Validate(SpellInfo const* /*spell*/) override
870 {
872 }
873
874 void HandleScript(AuraEffect const* aurEff)
875 {
877
878 Unit* target = GetTarget();
879 if (int32 mana = int32(target->GetMaxPower(POWER_MANA) / 10))
880 {
881 mana = target->ModifyPower(POWER_MANA, -mana);
882 CastSpellExtraArgs args(aurEff);
883 args.AddSpellBP0(-mana * 10);
884 target->CastSpell(target, SPELL_MANA_DETONATION_DAMAGE, args);
885 }
886 }
887
888 void Register() override
889 {
891 }
892};
893
894// 27808 - Frost Blast
896{
897 bool Validate(SpellInfo const* /*spellInfo*/) override
898 {
900 }
901
902 void PeriodicTick(AuraEffect const* aurEff)
903 {
905
906 // Stuns the target, dealing 26% of the target's maximum health in Frost damage every second for 4 sec.
907 if (Unit* caster = GetCaster())
908 {
909 CastSpellExtraArgs args(aurEff);
910 args.AddSpellBP0(GetTarget()->CountPctFromMaxHealth(26));
911 caster->CastSpell(GetTarget(), SPELL_FROST_BLAST_DMG, args);
912 }
913 }
914
915 void Register() override
916 {
918 }
919};
920
922{
923public:
924 at_kelthuzad_center() : AreaTriggerScript("at_kelthuzad_center") { }
925
926 bool OnTrigger(Player* player, AreaTriggerEntry const* /*at*/) override
927 {
928 InstanceScript* instance = player->GetInstanceScript();
929 if (!instance || instance->GetBossState(BOSS_KELTHUZAD) != NOT_STARTED)
930 return true;
931
932 if (player->IsGameMaster())
933 return true;
934
935 Creature* kelThuzad = ObjectAccessor::GetCreature(*player, instance->GetGuidData(DATA_KELTHUZAD));
936 if (!kelThuzad)
937 return true;
938
939 kelThuzad->AI()->DoAction(ACTION_BEGIN_ENCOUNTER);
940
941 return true;
942 }
943};
944
946{
947 public:
948 achievement_just_cant_get_enough() : AchievementCriteriaScript("achievement_just_cant_get_enough") { }
949
950 bool OnCheck(Player* /*player*/, Unit* target) override
951 {
952 if (!target)
953 return false;
954
955 if (InstanceScript* instance = target->GetInstanceScript())
956 if (Creature* kelThuzad = ObjectAccessor::GetCreature(*target, instance->GetGuidData(DATA_KELTHUZAD)))
957 if (kelThuzad->AI()->GetData(DATA_ABOMINATION_DEATH_COUNT) >= 18)
958 return true;
959
960 return false;
961 }
962};
963
965{
977}
Texts
Actions
@ IN_MILLISECONDS
Definition: Common.h:35
#define M_PI
Definition: Common.h:115
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
std::chrono::minutes Minutes
Minutes shorthand typedef.
Definition: Duration.h:35
@ IN_PROGRESS
@ NOT_STARTED
@ TEMPSUMMON_CORPSE_TIMED_DESPAWN
Definition: ObjectDefines.h:68
@ TYPEID_PLAYER
Definition: ObjectGuid.h:41
Spells
Definition: PlayerAI.cpp:32
Milliseconds randtime(Milliseconds min, Milliseconds max)
Definition: Random.cpp:62
float rand_norm()
Definition: Random.cpp:75
uint32 urand(uint32 min, uint32 max)
Definition: Random.cpp:42
uint32 urandms(uint32 min, uint32 max)
Definition: Random.cpp:49
#define RegisterSpellScript(spell_script)
Definition: ScriptMgr.h:1369
@ EFFECT_1
Definition: SharedDefines.h:31
@ EFFECT_0
Definition: SharedDefines.h:30
@ POWER_MANA
@ GO_STATE_READY
@ GO_STATE_ACTIVE
AuraEffectHandleModes
@ AURA_EFFECT_HANDLE_REAL
@ SPELL_AURA_MOD_DAMAGE_PERCENT_DONE
@ SPELL_AURA_PERIODIC_TRIGGER_SPELL
#define AuraEffectPeriodicFn(F, I, N)
Definition: SpellScript.h:2046
#define AuraEffectApplyFn(F, I, N, M)
Definition: SpellScript.h:2029
EvadeReason
Definition: UnitAICommon.h:30
@ REACT_PASSIVE
Definition: UnitDefines.h:506
@ REACT_AGGRESSIVE
Definition: UnitDefines.h:508
DamageEffectType
Definition: UnitDefines.h:131
@ UNIT_STATE_CASTING
Definition: Unit.h:270
Movements
static Position GetRandomPositionOnCircle(Position const &center, float radius)
@ SUMMON_GROUP_GUARDIAN_FIRST
@ SUMMON_GROUP_MINION_FIRST
@ ACTION_JUST_SUMMONED
@ ACTION_KELTHUZAD_DIED
@ ACTION_ABOMINATION_DIED
@ ACTION_BEGIN_ENCOUNTER
@ NPC_ABOMINATION1
@ NPC_BANSHEE2
@ NPC_GUARDIAN
@ NPC_SKELETON1
@ NPC_BANSHEE1
@ NPC_SKELETON2
@ NPC_ABOMINATION2
static const uint8 nGuardianSpawns
static const uint8 nMinionGroups
static const Position minionSpawnPoints[nMinionSpawnPoints]
void AddSC_boss_kelthuzad()
@ SPELL_MANA_DETONATION_DAMAGE
@ SPELL_FROST_BLAST_DMG
@ SPELL_SHADOW_FISSURE
@ SPELL_VOID_BLAST
@ SPELL_CHAINS
@ SPELL_VISUAL_CHANNEL
@ SPELL_FROSTBOLT_VOLLEY
@ SPELL_FROST_BLAST
@ SPELL_DETONATE_MANA
@ SPELL_FROSTBOLT_SINGLE
@ SPELL_CHAINS_DUMMY
@ SPELL_BERSERK
@ SPELL_MORTAL_WOUND
@ SPELL_BLOOD_TAP
@ PHASE_ONE
@ PHASE_TWO
@ SAY_DEATH
@ SAY_AGGRO
@ EMOTE_GUARDIAN_FLEE
@ SAY_SPECIAL
@ EMOTE_GUARDIAN_APPEAR
@ SAY_ANSWER_REQUEST
@ EMOTE_PHASE_TWO
@ SAY_SLAY
@ SAY_CHAINS
@ SAY_SUMMON_MINIONS
@ SAY_REQUEST_AID
KTData
@ DATA_MINION_POCKET_ID
@ DATA_ABOMINATION_DEATH_COUNT
static const uint8 nMinionSpawnPoints
static const float MINION_AGGRO_DISTANCE
static Position const & GetRandomMinionSpawnPoint()
static NAXData64 const portalList[]
@ MOVEMENT_MINION_RANDOM
@ EVENT_PHASE_TWO
@ EVENT_CHAINS
@ EVENT_ABOMINATION
@ EVENT_FROSTBOLT_VOLLEY
@ EVENT_FROST_BLAST
@ EVENT_SKELETON
@ EVENT_DETONATE_MANA
@ EVENT_BANSHEE
@ EVENT_TRANSITION_SUMMON
@ EVENT_SHADOW_FISSURE
@ EVENT_DESPAWN_MINIONS
@ EVENT_TRANSITION_REPLY
SummonGroups
void HandleAuraModScale(AuraApplication const *aurApp, uint8 mode, bool apply) const
void PreventDefaultAction()
AuraApplication const * GetTargetApplication() const
HookList< EffectApplyHandler > AfterEffectRemove
Definition: SpellScript.h:2039
HookList< EffectPeriodicHandler > OnEffectPeriodic
Definition: SpellScript.h:2045
HookList< EffectApplyHandler > AfterEffectApply
Definition: SpellScript.h:2028
Unit * GetCaster() const
Unit * GetTarget() const
InstanceScript *const instance
void _DespawnAtEvade(Seconds delayToRespawn=30s, Creature *who=nullptr)
SummonList summons
EventMap events
void _JustDied()
virtual void MoveInLineOfSight(Unit *)
Definition: CreatureAI.cpp:122
virtual void JustEngagedWith(Unit *)
Definition: CreatureAI.h:99
void DoZoneInCombat()
Definition: CreatureAI.h:161
virtual void JustDied(Unit *)
Definition: CreatureAI.h:105
virtual void EnterEvadeMode(EvadeReason why=EvadeReason::Other)
Definition: CreatureAI.cpp:219
void Talk(uint8 id, WorldObject const *whisperTarget=nullptr)
Definition: CreatureAI.cpp:56
bool UpdateVictim()
Definition: CreatureAI.cpp:245
Creature *const me
Definition: CreatureAI.h:61
void SetCombatPulseDelay(uint32 delay)
Definition: Creature.h:345
void SetHomePosition(float x, float y, float z, float o)
Definition: Creature.h:371
void SetImmuneToPC(bool apply) override
Definition: Creature.h:170
bool HasReactState(ReactStates state) const
Definition: Creature.h:162
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
bool CanStartAttack(Unit const *u, bool force) const
Definition: Creature.cpp:2099
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)
virtual ObjectGuid GetGuidData(uint32 type) const override
EncounterState GetBossState(uint32 id) const
Unit * SelectAttackTarget() const override
KelThuzadCharmedPlayerAI(Player *player)
void MovePoint(uint32 id, Position const &pos, bool generatePath=true, Optional< float > finalOrient={}, Optional< float > speed={}, MovementWalkRunSpeedSelectionMode speedSelectionMode=MovementWalkRunSpeedSelectionMode::Default, Optional< float > closeEnoughDistance={})
void MoveTargetedHome()
TypeID GetTypeId() const
Definition: Object.h:173
uint32 GetEntry() const
Definition: Object.h:161
static Player * ToPlayer(Object *o)
Definition: Object.h:213
static bool IsPlayerHealer(Player const *who)
Definition: PlayerAI.cpp:414
Creature * GetCharmer() const
Definition: PlayerAI.cpp:402
bool IsGameMaster() const
Definition: Player.h:1178
uint32 const Id
Definition: SpellInfo.h:325
static bool ValidateSpellInfo(std::initializer_list< uint32 > spellIds)
Definition: SpellScript.h:162
iterator erase(iterator i)
iterator begin()
void Summon(Creature const *summon)
iterator end()
size_type size() const
StorageType::iterator iterator
TaskScheduler & Schedule(std::chrono::duration< Rep, Period > time, task_handler_t task)
TaskScheduler & Update(success_t const &callback=nullptr)
virtual void DoAction(int32)
Definition: UnitAI.h:72
virtual void Reset()
Definition: UnitAI.h:63
SpellCastResult DoCastSelf(uint32 spellId, CastSpellExtraArgs const &args={})
Definition: UnitAI.h:159
SpellCastResult DoCastVictim(uint32 spellId, CastSpellExtraArgs const &args={})
Definition: UnitAI.cpp:180
void SelectTargetList(std::list< Unit * > &targetList, uint32 num, SelectTargetMethod targetType, uint32 offset=0, float dist=0.0f, bool playerOnly=false, bool withTank=true, int32 aura=0)
Definition: UnitAI.cpp:84
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
int32 ModifyPower(Powers power, int32 val, bool withPowerUpdate=true)
Definition: Unit.cpp:8280
void CastStop(uint32 except_spellid=0)
Definition: Unit.cpp:1135
void SetVisible(bool x)
Definition: Unit.cpp:8351
void CombatStop(bool includingCast=false, bool mutualPvP=true, bool(*unitFilter)(Unit const *otherUnit)=nullptr)
Definition: Unit.cpp:5827
bool HasBreakableByDamageCrowdControlAura(Unit *excludeCasterChannel=nullptr) const
Definition: Unit.cpp:734
MotionMaster * GetMotionMaster()
Definition: Unit.h:1652
Powers GetPowerType() const
Definition: Unit.h:799
bool IsAlive() const
Definition: Unit.h:1164
int32 GetMaxPower(Powers power) const
Definition: Unit.cpp:9410
void StopMoving()
Definition: Unit.cpp:10049
void SetUninteractible(bool apply)
Definition: Unit.cpp:8147
bool HasUnitState(const uint32 f) const
Definition: Unit.h:732
bool HasAura(uint32 spellId, ObjectGuid casterGUID=ObjectGuid::Empty, ObjectGuid itemCasterGUID=ObjectGuid::Empty, uint32 reqEffMask=0) const
Definition: Unit.cpp:4664
void RemoveAllAuras()
Definition: Unit.cpp:4242
InstanceScript * GetInstanceScript() const
Definition: Object.cpp:1042
void GetCreatureListWithEntryInGrid(Container &creatureContainer, uint32 entry, float maxSearchRange=250.0f) const
Definition: Object.cpp:3312
SpellCastResult CastSpell(CastSpellTargetArg const &targets, uint32 spellId, CastSpellExtraArgs const &args={ })
Definition: Object.cpp:2896
TempSummon * SummonCreature(uint32 entry, Position const &pos, TempSummonType despawnType=TEMPSUMMON_MANUAL_DESPAWN, Milliseconds despawnTime=0s, uint32 vehId=0, uint32 spellId=0, ObjectGuid privateObjectOwner=ObjectGuid::Empty)
Definition: Object.cpp:2025
float GetDistance2d(WorldObject const *obj) const
Definition: Object.cpp:1096
void SummonCreatureGroup(uint8 group, std::list< TempSummon * > *list=nullptr)
Definition: Object.cpp:2131
bool OnCheck(Player *, Unit *target) override
bool OnTrigger(Player *player, AreaTriggerEntry const *) override
void Register() override
void HandleRemove(AuraEffect const *aurEff, AuraEffectHandleModes mode)
void HandleApply(AuraEffect const *aurEff, AuraEffectHandleModes mode)
bool Validate(SpellInfo const *) override
void HandleScript(AuraEffect const *aurEff)
bool Validate(SpellInfo const *) override
void PeriodicTick(AuraEffect const *aurEff)
TC_GAME_API GameObject * GetGameObject(WorldObject const &u, ObjectGuid const &guid)
TC_GAME_API Creature * GetCreature(WorldObject const &u, ObjectGuid const &guid)
@ BOSS_KELTHUZAD
Definition: naxxramas.h:44
NAXData64
Definition: naxxramas.h:62
@ DATA_KELTHUZAD
Definition: naxxramas.h:77
@ DATA_KELTHUZAD_PORTAL02
Definition: naxxramas.h:79
@ DATA_KELTHUZAD_PORTAL01
Definition: naxxramas.h:78
@ DATA_KELTHUZAD_PORTAL04
Definition: naxxramas.h:81
@ DATA_KELTHUZAD_PORTAL03
Definition: naxxramas.h:80
#define RegisterNaxxramasCreatureAI(ai_name)
Definition: naxxramas.h:221
CastSpellExtraArgs & AddSpellBP0(int32 val)
Definition: SpellDefines.h:475
bool operator()(Unit const *target) const
constexpr float GetPositionX() const
Definition: Position.h:76
constexpr float GetPositionY() const
Definition: Position.h:77
constexpr void GetPosition(float &x, float &y) const
Definition: Position.h:81
constexpr float GetPositionZ() const
Definition: Position.h:78
void AttackStart(Unit *) override
== Triggered Actions Requested ==================
bool HealthBelowPct(uint32 pct) const
bool Is25ManRaid() const
void ResetThreatList(Unit *who=nullptr)
std::array< uint32, nGuardianSpawns > _guardianGroups
void DoAction(int32 action) override
void Reset() override
boss_kelthuzad(Creature *creature)
void DamageTaken(Unit *, uint32 &damage, DamageEffectType, SpellInfo const *) override
void EnterEvadeMode(EvadeReason) override
uint8 _abominationDeathCount
void JustSummoned(Creature *summon) override
void KilledUnit(Unit *victim) override
void SpellHit(WorldObject *, SpellInfo const *spellInfo) override
uint32 GetData(uint32 data) const override
void UpdateAI(uint32 diff) override
PlayerAI * GetAIForCharmedPlayer(Player *player) override
void JustDied(Unit *) override
void UpdateAI(uint32 diff) override
npc_kelthuzad_abomination(Creature *creature)
void JustDied(Unit *killer) override
npc_kelthuzad_banshee(Creature *creature)
void UpdateAI(uint32 diff) override
void JustReachedHome() override
void EnterEvadeMode(EvadeReason why) override
InstanceScript *const instance
void DoAction(int32 action) override
void UpdateAI(uint32 diff) override
npc_kelthuzad_guardian(Creature *creature)
void EnterEvadeMode(EvadeReason why) override
npc_kelthuzad_minionAI(Creature *creature)
void MovementInform(uint32, uint32 id) override
uint32 GetData(uint32 data) const override
void UpdateRandomMovement(uint32 diff)
void SetData(uint32 data, uint32 value) override
InstanceScript *const instance
void MoveInLineOfSight(Unit *who) override
void AttackStart(Unit *who) override
== Triggered Actions Requested ==================
void JustEngagedWith(Unit *who) override
npc_kelthuzad_shadow_fissure(Creature *creature)
void UpdateAI(uint32 diff) override
npc_kelthuzad_skeleton(Creature *creature)
void UpdateAI(uint32 diff) override
@ DATA_LICH_KING