TrinityCore
boss_gothik.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 "AreaBoundary.h"
20#include "CombatAI.h"
21#include "GridNotifiers.h"
22#include "InstanceScript.h"
23#include "Log.h"
24#include "Map.h"
25#include "naxxramas.h"
26#include "ObjectAccessor.h"
27#include "ScriptedCreature.h"
28#include "SpellInfo.h"
29#include "SpellScript.h"
30
31/* Constants */
33{
41
44};
45
47{
48 /* living knight spells */
50
51 /* spectral knight spells */
53
54 /* spectral horse spells */
55 SPELL_STOMP = 27993,
56
57 /* gothik phase two spells */
60
61 /* visual spells */
65
69
73
74 /* teleport spells */
77};
78
79#define SPELL_UNHOLY_AURA RAID_MODE<uint32>(55606, 55608)
80#define SPELL_DEATH_PLAGUE RAID_MODE<uint32>(55604, 55645)
81#define SPELL_SHADOW_BOLT_VOLLEY RAID_MODE<uint32>(27831, 55638)
82#define SPELL_ARCANE_EXPLOSION RAID_MODE<uint32>(27989, 56407)
83#define SPELL_DRAIN_LIFE RAID_MODE<uint32>(27994, 55646)
84#define SPELL_UNHOLY_FRENZY RAID_MODE<uint32>(55648,27995)
85
87{
95
96 NPC_TRIGGER = 16137
97};
98
100{
102 PHASE_TWO = 2
104
106{
118
120{
125
126/* Room side checking logic */
127static AreaBoundary* const livingSide = new RectangleBoundary(2633.84f, 2750.49f, -3434.0f, -3360.78f);
128static AreaBoundary* const deadSide = new RectangleBoundary(2633.84f, 2750.49f, -3360.78f, -3285.0f);
130{
135inline static Side GetSide(Position const* who)
136{
138 return SIDE_LIVING;
139 if (deadSide->IsWithinBoundary(who))
140 return SIDE_DEAD;
141 return SIDE_NONE;
142}
143inline static bool IsOnSameSide(Position const* who, Position const* other)
144{
145 return (GetSide(who) == GetSide(other));
146}
147static Player* FindEligibleTarget(Creature const* me, bool isGateOpen)
148{
149 Map::PlayerList const& players = me->GetMap()->GetPlayers();
150 for (Map::PlayerList::const_iterator it = players.begin(); it != players.end(); ++it)
151 {
152 Player* player = it->GetSource();
153 if (player && (isGateOpen || IsOnSameSide(me, player)) && me->CanSeeOrDetect(player) && me->IsValidAttackTarget(player) && player->isInAccessiblePlaceFor(me))
154 {
155 return player;
156 }
157 }
158
159 return nullptr;
160}
161
162/* Wave data */
163typedef std::pair<uint32, uint8> GothikWaveEntry; // (npcEntry, npcCount)
164typedef std::set<GothikWaveEntry> GothikWave;
165typedef std::pair<GothikWave, uint8> GothikWaveInfo; // (wave, secondsToNext)
166typedef std::vector<GothikWaveInfo> GothikWaveData;
168{
169 {
170 {{NPC_LIVE_TRAINEE, 2}},
171 20},
172 {
173 {{NPC_LIVE_TRAINEE, 2}},
174 20},
175 {
176 {{NPC_LIVE_TRAINEE, 2}},
177 10},
178 {
179 {{NPC_LIVE_KNIGHT, 1}},
180 10},
181 {
182 {{NPC_LIVE_TRAINEE, 2}},
183 15},
184 {
185 {{NPC_LIVE_KNIGHT, 1}},
186 5},
187 {
188 {{NPC_LIVE_TRAINEE, 2}},
189 20},
190 {
192 10},
193 {
194 {{NPC_LIVE_RIDER, 1}},
195 10},
196 {
197 {{NPC_LIVE_TRAINEE, 2}},
198 5},
199 {
200 {{NPC_LIVE_KNIGHT, 1}},
201 15},
202 {
203 {{NPC_LIVE_TRAINEE, 2}, {NPC_LIVE_RIDER, 1}},
204 10},
205 {
206 {{NPC_LIVE_KNIGHT, 2}},
207 10},
208 {
209 {{NPC_LIVE_TRAINEE, 2}},
210 10},
211 {
212 {{NPC_LIVE_RIDER, 1}},
213 5},
214 {
215 {{NPC_LIVE_KNIGHT, 1}},
216 5},
217 {
218 {{NPC_LIVE_TRAINEE, 2}},
219 20},
220 {
222 15},
223 {
224 {{NPC_LIVE_TRAINEE, 2}},
225 0}
226};
227
229{
230 {
231 {{NPC_LIVE_TRAINEE, 3}},
232 20},
233 {
234 {{NPC_LIVE_TRAINEE, 3}},
235 20},
236 {
237 {{NPC_LIVE_TRAINEE, 3}},
238 10},
239 {
240 {{NPC_LIVE_KNIGHT, 2}},
241 10},
242 {
243 {{NPC_LIVE_TRAINEE, 3}},
244 15},
245 {
246 {{NPC_LIVE_KNIGHT, 2}},
247 5},
248 {
249 {{NPC_LIVE_TRAINEE, 3}},
250 20},
251 {
253 10},
254 {
255 {{NPC_LIVE_TRAINEE, 3}},
256 10},
257 {
258 {{NPC_LIVE_RIDER, 1}},
259 5},
260 {
261 {{NPC_LIVE_TRAINEE, 3}},
262 15},
263 {
264 {{NPC_LIVE_RIDER, 1}},
265 10},
266 {
267 {{NPC_LIVE_KNIGHT, 2}},
268 10},
269 {
270 {{NPC_LIVE_RIDER, 1}},
271 10},
272 {
273 {{NPC_LIVE_RIDER, 1}, {NPC_LIVE_TRAINEE, 3}},
274 5},
275 {
277 5},
278 {
279 {{NPC_LIVE_RIDER, 1}, {NPC_LIVE_TRAINEE, 3}},
280 20},
281 {
283 0}
284};
285
286// GUID of first trigger NPC (used as offset for guid checks)
287// 0-1 are living side soul triggers, 2-3 are spectral side soul triggers, 4 is living rider spawn trigger, 5-7 are living other spawn trigger, 8-12 are skull pile triggers
288const uint32 CGUID_TRIGGER = 127618;
289/* Creature AI */
290struct boss_gothik : public BossAI
291{
292 boss_gothik(Creature* creature) : BossAI(creature, BOSS_GOTHIK)
293 {
294 Initialize();
295 }
296
298 {
299 _waveCount = 0;
300 _gateCanOpen = false;
301 _gateIsOpen = true;
302 _lastTeleportDead = false;
303 }
304
305 void Reset() override
306 {
309 _Reset();
310 Initialize();
311 }
312
313 void JustEngagedWith(Unit* who) override
314 {
325 _gateIsOpen = false;
326 }
327
328 void JustSummoned(Creature* summon) override
329 {
330 summons.Summon(summon);
331 if (me->IsInCombat())
332 {
334 summon->SetCombatPulseDelay(5);
335 }
336 else
337 summon->DespawnOrUnsummon();
338 }
339
340 void SummonedCreatureDespawn(Creature* summon) override
341 {
342 summons.Despawn(summon);
343 }
344
345 void KilledUnit(Unit* victim) override
346 {
347 if (victim && victim->GetTypeId() == TYPEID_PLAYER)
348 Talk(SAY_KILL);
349 }
350
351 void JustDied(Unit* /*killer*/) override
352 {
353 _JustDied();
356 _gateIsOpen = false;
357 }
358
359 void OpenGate()
360 {
361 if (_gateIsOpen)
362 return;
365 _gateIsOpen = true;
366
367 for (ObjectGuid summonGuid : summons)
368 {
369 if (Creature* summon = ObjectAccessor::GetCreature(*me, summonGuid))
370 summon->AI()->DoAction(ACTION_GATE_OPENED);
371 if (summons.empty()) // ACTION_GATE_OPENED may cause an evade, despawning summons and invalidating our iterator
372 break;
373 }
374 }
375
376 void DamageTaken(Unit* /*who*/, uint32& damage, DamageEffectType /*damageType*/, SpellInfo const* /*spellInfo = nullptr*/) override
377 {
379 damage = 0;
380 }
381
382 void DoAction(int32 action) override
383 {
384 switch (action)
385 {
389 if (_gateCanOpen)
390 OpenGate();
391 break;
392 }
393 }
394
395 void EnterEvadeMode(EvadeReason why) override
396 {
398 Position const& home = me->GetHomePosition();
399 me->NearTeleportTo(home.GetPositionX(), home.GetPositionY(), home.GetPositionZ(), home.GetOrientation());
400 }
401
402 void UpdateAI(uint32 diff) override
403 {
404 if (!UpdateVictim())
405 return;
406
408 {
409 // NBD: this should only happen in practice if there is nobody left alive on our side (we should open gate)
410 // thus we only do a cursory check to make sure (edge cases?)
411 if (Player* newTarget = FindEligibleTarget(me, _gateIsOpen))
412 {
414 AddThreat(newTarget, 1.0f);
415 AttackStart(newTarget);
416 }
417 else
418 OpenGate();
419 }
420
421 events.Update(diff);
422
424 OpenGate();
425
426 while (uint32 eventId = events.ExecuteEvent())
427 {
428 switch (eventId)
429 {
430 case EVENT_SUMMON:
431 {
432 if (RAID_MODE(waves10,waves25).size() <= _waveCount) // bounds check
433 {
434 TC_LOG_INFO("scripts", "GothikAI: Wave count {} is out of range for difficulty {}.", _waveCount, static_cast<uint32>(GetDifficulty()));
435 break;
436 }
437
438 std::list<Creature*> triggers;
440 for (GothikWaveEntry entry : RAID_MODE(waves10, waves25)[_waveCount].first)
441 for (uint8 i = 0; i < entry.second; ++i)
442 {
443 // GUID layout is as follows:
444 // CGUID+4: center (back of platform) - primary rider spawn
445 // CGUID+5: north (back of platform) - primary knight spawn
446 // CGUID+6: center (front of platform) - second spawn
447 // CGUID+7: south (front of platform) - primary trainee spawn
448 uint32 targetDBGuid;
449 switch (entry.first)
450 {
451 case NPC_LIVE_RIDER: // only spawns from center (back) > north
452 targetDBGuid = (CGUID_TRIGGER + 4) + (i % 2);
453 break;
454 case NPC_LIVE_KNIGHT: // spawns north > center (front) > south
455 targetDBGuid = (CGUID_TRIGGER + 5) + (i % 3);
456 break;
457 case NPC_LIVE_TRAINEE: // spawns south > center (front) > north
458 targetDBGuid = (CGUID_TRIGGER + 7) - (i % 3);
459 break;
460 default:
461 targetDBGuid = 0;
462 }
463
464 for (Creature* trigger : triggers)
465 if (trigger && trigger->GetSpawnId() == targetDBGuid)
466 {
467 DoSummon(entry.first, trigger, 1.0f, 15s, TEMPSUMMON_CORPSE_TIMED_DESPAWN);
468 break;
469 }
470 }
471
472 if (uint8 timeToNext = RAID_MODE(waves10, waves25)[_waveCount].second)
473 events.Repeat(Seconds(timeToNext));
474
475 ++_waveCount;
476 break;
477 }
479 _gateCanOpen = true;
480 for (ObjectGuid summonGuid : summons)
481 if (Creature* summon = ObjectAccessor::GetCreature(*me, summonGuid))
482 if (summon->IsAlive() && (!summon->IsInCombat() || summon->IsInEvadeMode()))
483 {
484 OpenGate();
485 break;
486 }
487 break;
488 case EVENT_PHASE_TWO:
498 break;
499 case EVENT_TELEPORT:
500 if (!HealthBelowPct(30))
501 {
502 me->CastStop();
503 me->AttackStop();
504 me->StopMoving();
509
512 events.Repeat(Seconds(20));
513 }
514 break;
515
516 case EVENT_HARVEST:
517 DoCastAOE(SPELL_HARVEST_SOUL, true); // triggered allows this to go "through" shadow bolt
518 events.Repeat(Seconds(15));
519 break;
523 // return to the start of this method so victim side etc is re-evaluated
524 return UpdateAI(0u); // tail recursion for efficiency
525 case EVENT_BOLT:
528 break;
529 case EVENT_INTRO_2:
531 break;
532 case EVENT_INTRO_3:
534 break;
535 case EVENT_INTRO_4:
537 break;
538 }
539 }
540 }
541
542 private:
547};
548
550{
551 public:
552 npc_gothik_minion_baseAI(Creature* creature, uint32 deathNotify=0) : ScriptedAI(creature), _deathNotify(deathNotify), _gateIsOpen(false) { }
553
554 void JustDied(Unit* /*killer*/) override
555 {
556 if (_deathNotify)
557 DoCastAOE(_deathNotify, true);
558 }
559
560 inline bool isOnSameSide(Unit const* who) const
561 {
562 return IsOnSameSide(me, who);
563 }
564
565 void DamageTaken(Unit* attacker, uint32& damage, DamageEffectType /*damageType*/, SpellInfo const* /*spellInfo = nullptr*/) override
566 { // do not allow minions to take damage before the gate is opened
567 if (!_gateIsOpen && (!attacker || !isOnSameSide(attacker)))
568 damage = 0;
569 }
570
571 void DoAction(int32 action) override
572 {
573 switch (action)
574 {
576 _gateIsOpen = true;
577 [[fallthrough]];
579 if (Player* target = FindEligibleTarget(me, _gateIsOpen))
580 {
581 AddThreat(target, 1.0f);
582 AttackStart(target);
583 }
584 else
586 break;
587 }
588 }
589
590 void EnterEvadeMode(EvadeReason why) override
591 {
593
594 if (InstanceScript* instance = me->GetInstanceScript())
595 if (Creature* gothik = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_GOTHIK)))
596 gothik->AI()->DoAction(ACTION_MINION_EVADE);
597 }
598
599 void UpdateAI(uint32 diff) override
600 {
601 if (!UpdateVictim())
602 return;
603
605 { // reset threat, then try to find someone on same side as us to attack
606 if (Player* newTarget = FindEligibleTarget(me, _gateIsOpen))
607 {
610 AddThreat(newTarget, 1.0f);
611 AttackStart(newTarget);
612 }
613 else
615 }
616
617 _UpdateAI(diff);
618 }
619
620 virtual void _UpdateAI(uint32 diff) { ScriptedAI::UpdateAI(diff); };
621
622 private:
625};
626
628{
630
631 void _UpdateAI(uint32 diff)
632 {
633 if (diff < _deathPlagueTimer)
634 _deathPlagueTimer -= diff;
635 else
636 {
638 _deathPlagueTimer = urandms(5, 20);
639 }
640 }
642};
643
645{
647
648 void _UpdateAI(uint32 diff)
649 {
650 if (diff < _whirlwindTimer)
651 _whirlwindTimer -= diff;
652 else
653 {
655 _whirlwindTimer = urandms(15, 20);
656 }
657 }
659};
660
662{
664
665 void JustAppeared() override
666 {
669 }
670
671 void JustReachedHome() override
672 {
675 }
676
677 void _UpdateAI(uint32 diff) override
678 {
679 if (diff < _boltVolleyTimer)
680 _boltVolleyTimer -= diff;
681 else
682 {
684 _boltVolleyTimer = urandms(10, 15);
685 }
686
688 }
690};
691
693{
695
696 void _UpdateAI(uint32 diff)
697 {
698 if (diff < _explosionTimer)
699 _explosionTimer -= diff;
700 else
701 {
704 }
705 }
707};
708
710{
712
713 void _UpdateAI(uint32 diff)
714 {
715 if (diff < _whirlwindTimer)
716 _whirlwindTimer -= diff;
717 else
718 {
720 _whirlwindTimer = urandms(20, 25);
721 }
722 }
724};
725
727{
729
730 void JustAppeared() override
731 {
734 }
735
736 void JustReachedHome() override
737 {
740 }
741
742 void _UpdateAI(uint32 diff) override
743 {
744 if (diff < _frenzyTimer)
745 _frenzyTimer -= diff;
747 _frenzyTimer = 0;
748 else
749 { // target priority: knight > other rider > horse > gothik
750 std::list<Creature*> potentialTargets = DoFindFriendlyMissingBuff(30.0, SPELL_UNHOLY_FRENZY);
751 Creature *knightTarget = nullptr, *riderTarget = nullptr, *horseTarget = nullptr, *gothikTarget = nullptr;
752 for (Creature* pTarget : potentialTargets)
753 {
754 switch (pTarget->GetEntry())
755 {
756 case NPC_DEAD_KNIGHT:
757 knightTarget = pTarget;
758 break;
759 case NPC_DEAD_RIDER:
760 riderTarget = pTarget;
761 break;
762 case NPC_DEAD_HORSE:
763 horseTarget = pTarget;
764 break;
765 case NPC_GOTHIK:
766 gothikTarget = pTarget;
767 break;
768 }
769 if (knightTarget)
770 break;
771 }
772 Creature* target = knightTarget ? knightTarget : riderTarget ? riderTarget : horseTarget ? horseTarget : gothikTarget ? gothikTarget : nullptr;
773 if (target)
776 }
777
778 if (diff < _drainTimer)
779 _drainTimer -= diff;
780 else
781 {
783 _drainTimer = urandms(10,15);
784 }
785
787 }
789};
790
792{
794
795 void _UpdateAI(uint32 diff)
796 {
797 if (diff < _stompTimer)
798 _stompTimer -= diff;
799 else
800 {
802 _stompTimer = urandms(14, 18);
803 }
804 }
806};
807
809{
810 npc_gothik_trigger(Creature* creature) : ScriptedAI(creature) { creature->SetDisableGravity(true); }
811
812 void EnterEvadeMode(EvadeReason /*why*/) override { }
813 void UpdateAI(uint32 /*diff*/) override { }
814 void JustEngagedWith(Unit* /*who*/) override { }
815 void DamageTaken(Unit* /*who*/, uint32& damage, DamageEffectType /*damageType*/, SpellInfo const* /*spellInfo = nullptr*/) override { damage = 0; }
816
818 {
819 std::list<Creature*> triggers;
821 uint32 targetDBGuid = CGUID_TRIGGER + urand(8, 12); // CGUID+8 to CGUID+12 are the triggers for the skull piles on dead side
822 for (Creature* trigger : triggers)
823 if (trigger && trigger->GetSpawnId() == targetDBGuid)
824 return trigger;
825
826 return nullptr;
827 }
828
829 void SpellHit(WorldObject* /*caster*/, SpellInfo const* spellInfo) override
830 {
831 switch (spellInfo->Id)
832 {
835 break;
838 break;
841 break;
843 if (Creature* target = SelectRandomSkullPile())
844 DoCast(target, SPELL_SKULLS_TRAINEE, true);
845 break;
847 if (Creature* target = SelectRandomSkullPile())
848 DoCast(target, SPELL_SKULLS_DK, true);
849 break;
851 if (Creature* target = SelectRandomSkullPile())
852 DoCast(target, SPELL_SKULLS_RIDER, true);
853 break;
856 break;
857 case SPELL_SKULLS_DK:
859 break;
863 break;
864 }
865 }
866
867 // dead side summons are "owned" by gothik
868 void JustSummoned(Creature* summon) override
869 {
871 gothik->AI()->JustSummoned(summon);
872 }
873 void SummonedCreatureDespawn(Creature* summon) override
874 {
876 gothik->AI()->SummonedCreatureDespawn(summon);
877 }
878};
879
880// 27831, 55638 - Shadow Bolt Volley
882{
883 void FilterTargets(std::list<WorldObject*>& targets)
884 {
885 targets.remove_if(Trinity::UnitAuraCheck(false, SPELL_SHADOW_MARK));
886 }
887
888 void Register() override
889 {
891 }
892};
893
895{
906}
Actions
@ IN_MILLISECONDS
Definition: Common.h:35
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
#define TC_LOG_INFO(filterType__,...)
Definition: Log.h:159
@ TEMPSUMMON_CORPSE_TIMED_DESPAWN
Definition: ObjectDefines.h:68
@ TYPEID_PLAYER
Definition: ObjectGuid.h:41
Spells
Definition: PlayerAI.cpp:32
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_0
Definition: SharedDefines.h:30
@ TARGET_UNIT_SRC_AREA_ENEMY
@ GO_STATE_READY
@ GO_STATE_ACTIVE
@ SPELL_AURA_MOD_TAUNT
#define SpellObjectAreaTargetSelectFn(F, I, N)
Definition: SpellScript.h:864
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
std::vector< GothikWaveInfo > GothikWaveData
const uint32 CGUID_TRIGGER
@ ACTION_ACQUIRE_TARGET
@ ACTION_MINION_EVADE
@ ACTION_GATE_OPENED
@ NPC_DEAD_HORSE
Definition: boss_gothik.cpp:94
@ NPC_DEAD_TRAINEE
Definition: boss_gothik.cpp:91
@ NPC_LIVE_TRAINEE
Definition: boss_gothik.cpp:88
@ NPC_DEAD_RIDER
Definition: boss_gothik.cpp:93
@ NPC_DEAD_KNIGHT
Definition: boss_gothik.cpp:92
@ NPC_LIVE_KNIGHT
Definition: boss_gothik.cpp:89
@ NPC_LIVE_RIDER
Definition: boss_gothik.cpp:90
@ NPC_TRIGGER
Definition: boss_gothik.cpp:96
static AreaBoundary *const livingSide
#define SPELL_DEATH_PLAGUE
Definition: boss_gothik.cpp:80
@ SAY_DEATH
Definition: boss_gothik.cpp:39
@ SAY_INTRO_2
Definition: boss_gothik.cpp:35
@ SAY_PHASE_TWO
Definition: boss_gothik.cpp:38
@ SAY_INTRO_1
Definition: boss_gothik.cpp:34
@ SAY_KILL
Definition: boss_gothik.cpp:40
@ EMOTE_PHASE_TWO
Definition: boss_gothik.cpp:42
@ SAY_INTRO_3
Definition: boss_gothik.cpp:36
@ SAY_INTRO_4
Definition: boss_gothik.cpp:37
@ EMOTE_GATE_OPENED
Definition: boss_gothik.cpp:43
#define SPELL_SHADOW_BOLT_VOLLEY
Definition: boss_gothik.cpp:81
#define SPELL_ARCANE_EXPLOSION
Definition: boss_gothik.cpp:82
#define SPELL_DRAIN_LIFE
Definition: boss_gothik.cpp:83
std::set< GothikWaveEntry > GothikWave
#define SPELL_UNHOLY_AURA
Definition: boss_gothik.cpp:79
@ SPELL_STOMP
Definition: boss_gothik.cpp:55
@ SPELL_ANCHOR_1_DK
Definition: boss_gothik.cpp:63
@ SPELL_ANCHOR_1_TRAINEE
Definition: boss_gothik.cpp:62
@ SPELL_ANCHOR_2_RIDER
Definition: boss_gothik.cpp:68
@ SPELL_SKULLS_DK
Definition: boss_gothik.cpp:71
@ SPELL_SHADOW_BOLT
Definition: boss_gothik.cpp:59
@ SPELL_HARVEST_SOUL
Definition: boss_gothik.cpp:58
@ SPELL_ANCHOR_2_DK
Definition: boss_gothik.cpp:67
@ SPELL_SKULLS_TRAINEE
Definition: boss_gothik.cpp:70
@ SPELL_SHADOW_MARK
Definition: boss_gothik.cpp:49
@ SPELL_SKULLS_RIDER
Definition: boss_gothik.cpp:72
@ SPELL_ANCHOR_1_RIDER
Definition: boss_gothik.cpp:64
@ SPELL_TELEPORT_LIVE
Definition: boss_gothik.cpp:76
@ SPELL_WHIRLWIND
Definition: boss_gothik.cpp:52
@ SPELL_TELEPORT_DEAD
Definition: boss_gothik.cpp:75
@ SPELL_ANCHOR_2_TRAINEE
Definition: boss_gothik.cpp:66
@ PHASE_ONE
@ PHASE_TWO
void AddSC_boss_gothik()
static bool IsOnSameSide(Position const *who, Position const *other)
Side
@ SIDE_DEAD
@ SIDE_LIVING
@ SIDE_NONE
std::pair< uint32, uint8 > GothikWaveEntry
static AreaBoundary *const deadSide
const GothikWaveData waves25
std::pair< GothikWave, uint8 > GothikWaveInfo
static Side GetSide(Position const *who)
#define SPELL_UNHOLY_FRENZY
Definition: boss_gothik.cpp:84
const GothikWaveData waves10
@ EVENT_INTRO_4
@ EVENT_PHASE_TWO
@ EVENT_INTRO_2
@ EVENT_TELEPORT
@ EVENT_BOLT
@ EVENT_RESUME_ATTACK
@ EVENT_DOORS_UNLOCK
@ EVENT_INTRO_3
@ EVENT_SUMMON
@ EVENT_HARVEST
static Player * FindEligibleTarget(Creature const *me, bool isGateOpen)
Yells
bool IsWithinBoundary(Position const *pos) const
Definition: AreaBoundary.h:26
InstanceScript *const instance
void JustEngagedWith(Unit *who) override
SummonList summons
EventMap events
void _JustDied()
virtual void JustReachedHome()
Definition: CreatureAI.h:159
virtual void EnterEvadeMode(EvadeReason why=EvadeReason::Other)
Definition: CreatureAI.cpp:219
void Talk(uint8 id, WorldObject const *whisperTarget=nullptr)
Definition: CreatureAI.cpp:56
virtual void JustAppeared()
Definition: CreatureAI.cpp:194
bool UpdateVictim()
Definition: CreatureAI.cpp:245
Creature *const me
Definition: CreatureAI.h:61
Creature * DoSummon(uint32 entry, Position const &pos, Milliseconds despawnTime=30s, TempSummonType summonType=TEMPSUMMON_CORPSE_TIMED_DESPAWN)
Definition: CreatureAI.cpp:464
void SetCombatPulseDelay(uint32 delay)
Definition: Creature.h:345
void GetHomePosition(float &x, float &y, float &z, float &ori) const
Definition: Creature.h:373
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
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 CancelEvent(uint32 eventId)
Definition: EventMap.cpp:131
void SetPhase(uint8 phase)
Definition: EventMap.cpp:28
virtual ObjectGuid GetGuidData(uint32 type) const override
iterator end()
Definition: MapRefManager.h:35
iterator begin()
Definition: MapRefManager.h:34
PlayerList const & GetPlayers() const
Definition: Map.h:367
TypeID GetTypeId() const
Definition: Object.h:173
uint32 const Id
Definition: SpellInfo.h:325
HookList< ObjectAreaTargetSelectHandler > OnObjectAreaTargetSelect
Definition: SpellScript.h:863
bool empty() const
void Despawn(Creature const *summon)
void Summon(Creature const *summon)
bool IsThreatListEmpty(bool includeOffline=false) const
virtual void DoAction(int32)
Definition: UnitAI.h:72
SpellCastResult DoCastSelf(uint32 spellId, CastSpellExtraArgs const &args={})
Definition: UnitAI.h:159
SpellCastResult DoCastVictim(uint32 spellId, CastSpellExtraArgs const &args={})
Definition: UnitAI.cpp:180
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
void RemoveAurasByType(AuraType auraType, std::function< bool(AuraApplication const *)> const &check, AuraRemoveMode removeMode=AURA_REMOVE_BY_DEFAULT)
Definition: Unit.cpp:3812
ThreatManager & GetThreatManager()
Definition: Unit.h:1063
void StopMoving()
Definition: Unit.cpp:10049
bool SetDisableGravity(bool disable, bool updateAnimTier=true)
Definition: Unit.cpp:12725
bool isInAccessiblePlaceFor(Creature const *c) const
Definition: Unit.cpp:3165
void NearTeleportTo(Position const &pos, bool casting=false)
Definition: Unit.cpp:12327
Unit * GetVictim() const
Definition: Unit.h:715
bool HasUnitState(const uint32 f) const
Definition: Unit.h:732
bool AttackStop()
Definition: Unit.cpp:5781
bool IsInCombat() const
Definition: Unit.h:1043
Map * GetMap() const
Definition: Object.h:624
InstanceScript * GetInstanceScript() const
Definition: Object.cpp:1042
void GetCreatureListWithEntryInGrid(Container &creatureContainer, uint32 entry, float maxSearchRange=250.0f) const
Definition: Object.cpp:3312
bool IsValidAttackTarget(WorldObject const *target, SpellInfo const *bySpell=nullptr) const
Definition: Object.cpp:2991
bool CanSeeOrDetect(WorldObject const *obj, bool implicitDetect=false, bool distanceCheck=false, bool checkAlert=false) const
Definition: Object.cpp:1514
virtual void SetData(uint32, uint32)
Definition: ZoneScript.h:92
void FilterTargets(std::list< WorldObject * > &targets)
TC_GAME_API Creature * GetCreature(WorldObject const &u, ObjectGuid const &guid)
constexpr std::size_t size()
Definition: UpdateField.h:796
@ NPC_GOTHIK
Definition: naxxramas.h:91
@ BOSS_GOTHIK
Definition: naxxramas.h:41
@ DATA_GOTHIK_GATE
Definition: naxxramas.h:49
@ DATA_GOTHIK
Definition: naxxramas.h:66
#define RegisterNaxxramasCreatureAI(ai_name)
Definition: naxxramas.h:221
constexpr float GetPositionX() const
Definition: Position.h:76
constexpr float GetPositionY() const
Definition: Position.h:77
constexpr float GetOrientation() const
Definition: Position.h:79
constexpr float GetPositionZ() const
Definition: Position.h:78
void AttackStart(Unit *) override
== Triggered Actions Requested ==================
T const & RAID_MODE(T const &normal10, T const &normal25) const
bool HealthBelowPct(uint32 pct) const
Difficulty GetDifficulty() const
std::list< Creature * > DoFindFriendlyMissingBuff(float range, uint32 spellId)
void ResetThreatList(Unit *who=nullptr)
void AddThreat(Unit *victim, float amount, Unit *who=nullptr)
virtual void UpdateAI(uint32 diff) override
void JustEngagedWith(Unit *who) override
bool _lastTeleportDead
void UpdateAI(uint32 diff) override
void DamageTaken(Unit *, uint32 &damage, DamageEffectType, SpellInfo const *) override
void KilledUnit(Unit *victim) override
void Initialize()
void JustSummoned(Creature *summon) override
void EnterEvadeMode(EvadeReason why) override
void Reset() override
boss_gothik(Creature *creature)
void DoAction(int32 action) override
void SummonedCreatureDespawn(Creature *summon) override
uint32 _waveCount
void JustDied(Unit *) override
void OpenGate()
void DoAction(int32 action) override
virtual void _UpdateAI(uint32 diff)
bool isOnSameSide(Unit const *who) const
void JustDied(Unit *) override
void DamageTaken(Unit *attacker, uint32 &damage, DamageEffectType, SpellInfo const *) override
void UpdateAI(uint32 diff) override
npc_gothik_minion_baseAI(Creature *creature, uint32 deathNotify=0)
void EnterEvadeMode(EvadeReason why) override
npc_gothik_minion_livingknight(Creature *creature)
npc_gothik_minion_livingrider(Creature *creature)
void _UpdateAI(uint32 diff) override
npc_gothik_minion_livingtrainee(Creature *creature)
npc_gothik_minion_spectralhorse(Creature *creature)
npc_gothik_minion_spectralknight(Creature *creature)
void _UpdateAI(uint32 diff) override
npc_gothik_minion_spectralrider(Creature *creature)
npc_gothik_minion_spectraltrainee(Creature *creature)
Creature * SelectRandomSkullPile()
void SpellHit(WorldObject *, SpellInfo const *spellInfo) override
void EnterEvadeMode(EvadeReason) override
void JustSummoned(Creature *summon) override
void UpdateAI(uint32) override
void DamageTaken(Unit *, uint32 &damage, DamageEffectType, SpellInfo const *) override
void JustEngagedWith(Unit *) override
void SummonedCreatureDespawn(Creature *summon) override
npc_gothik_trigger(Creature *creature)