TrinityCore
Loading...
Searching...
No Matches
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 */
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
98
100{
102 PHASE_TWO = 2
104
118
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);
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 */
168
170{
171 constexpr GothikWaveInfo(std::initializer_list<GothikWaveEntry> waves, int64 timeToNextWave) : TimeToNextWave(timeToNextWave)
172 {
173 std::ranges::copy_n(waves.begin(), std::min(std::ranges::ssize(waves), std::ranges::ssize(Creatures)), Creatures.begin());
174 }
175
176 std::array<GothikWaveEntry, 3> Creatures;
178};
179
180static constexpr std::array<GothikWaveInfo, 19> waves10 =
181{ {
182 {
183 {{NPC_LIVE_TRAINEE, 2}},
184 20},
185 {
186 {{NPC_LIVE_TRAINEE, 2}},
187 20},
188 {
189 {{NPC_LIVE_TRAINEE, 2}},
190 10},
191 {
192 {{NPC_LIVE_KNIGHT, 1}},
193 10},
194 {
195 {{NPC_LIVE_TRAINEE, 2}},
196 15},
197 {
198 {{NPC_LIVE_KNIGHT, 1}},
199 5},
200 {
201 {{NPC_LIVE_TRAINEE, 2}},
202 20},
203 {
205 10},
206 {
207 {{NPC_LIVE_RIDER, 1}},
208 10},
209 {
210 {{NPC_LIVE_TRAINEE, 2}},
211 5},
212 {
213 {{NPC_LIVE_KNIGHT, 1}},
214 15},
215 {
216 {{NPC_LIVE_TRAINEE, 2}, {NPC_LIVE_RIDER, 1}},
217 10},
218 {
219 {{NPC_LIVE_KNIGHT, 2}},
220 10},
221 {
222 {{NPC_LIVE_TRAINEE, 2}},
223 10},
224 {
225 {{NPC_LIVE_RIDER, 1}},
226 5},
227 {
228 {{NPC_LIVE_KNIGHT, 1}},
229 5},
230 {
231 {{NPC_LIVE_TRAINEE, 2}},
232 20},
233 {
235 15},
236 {
237 {{NPC_LIVE_TRAINEE, 2}},
238 0}
239} };
240
241static constexpr std::array<GothikWaveInfo, 18> waves25 =
242{ {
243 {
244 {{NPC_LIVE_TRAINEE, 3}},
245 20},
246 {
247 {{NPC_LIVE_TRAINEE, 3}},
248 20},
249 {
250 {{NPC_LIVE_TRAINEE, 3}},
251 10},
252 {
253 {{NPC_LIVE_KNIGHT, 2}},
254 10},
255 {
256 {{NPC_LIVE_TRAINEE, 3}},
257 15},
258 {
259 {{NPC_LIVE_KNIGHT, 2}},
260 5},
261 {
262 {{NPC_LIVE_TRAINEE, 3}},
263 20},
264 {
266 10},
267 {
268 {{NPC_LIVE_TRAINEE, 3}},
269 10},
270 {
271 {{NPC_LIVE_RIDER, 1}},
272 5},
273 {
274 {{NPC_LIVE_TRAINEE, 3}},
275 15},
276 {
277 {{NPC_LIVE_RIDER, 1}},
278 10},
279 {
280 {{NPC_LIVE_KNIGHT, 2}},
281 10},
282 {
283 {{NPC_LIVE_RIDER, 1}},
284 10},
285 {
286 {{NPC_LIVE_RIDER, 1}, {NPC_LIVE_TRAINEE, 3}},
287 5},
288 {
290 5},
291 {
292 {{NPC_LIVE_RIDER, 1}, {NPC_LIVE_TRAINEE, 3}},
293 20},
294 {
296 0}
297} };
298
299// GUID of first trigger NPC (used as offset for guid checks)
300// 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
301const uint32 CGUID_TRIGGER = 127618;
302/* Creature AI */
303struct boss_gothik : public BossAI
304{
305 boss_gothik(Creature* creature) : BossAI(creature, BOSS_GOTHIK)
306 {
307 Initialize();
308 }
309
311 {
312 _waveCount = 0;
313 _gateCanOpen = false;
314 _gateIsOpen = true;
315 _lastTeleportDead = false;
316 }
317
318 void Reset() override
319 {
322 _Reset();
323 Initialize();
324 }
325
340
341 void JustSummoned(Creature* summon) override
342 {
343 summons.Summon(summon);
344 if (me->IsInCombat())
346 else
347 summon->DespawnOrUnsummon();
348 }
349
350 void SummonedCreatureDespawn(Creature* summon) override
351 {
352 summons.Despawn(summon);
353 }
354
355 void KilledUnit(Unit* victim) override
356 {
357 if (victim && victim->GetTypeId() == TYPEID_PLAYER)
358 Talk(SAY_KILL);
359 }
360
361 void JustDied(Unit* /*killer*/) override
362 {
363 _JustDied();
366 _gateIsOpen = false;
367 }
368
369 void OpenGate()
370 {
371 if (_gateIsOpen)
372 return;
375 _gateIsOpen = true;
376
377 for (ObjectGuid summonGuid : summons)
378 {
379 if (Creature* summon = ObjectAccessor::GetCreature(*me, summonGuid))
380 summon->AI()->DoAction(ACTION_GATE_OPENED);
381 if (summons.empty()) // ACTION_GATE_OPENED may cause an evade, despawning summons and invalidating our iterator
382 break;
383 }
384 }
385
386 void DamageTaken(Unit* /*who*/, uint32& damage, DamageEffectType /*damageType*/, SpellInfo const* /*spellInfo = nullptr*/) override
387 {
389 damage = 0;
390 }
391
392 void DoAction(int32 action) override
393 {
394 switch (action)
395 {
399 if (_gateCanOpen)
400 OpenGate();
401 break;
402 }
403 }
404
405 void EnterEvadeMode(EvadeReason why) override
406 {
408 Position const& home = me->GetHomePosition();
409 me->NearTeleportTo(home.GetPositionX(), home.GetPositionY(), home.GetPositionZ(), home.GetOrientation());
410 }
411
412 void UpdateAI(uint32 diff) override
413 {
414 if (!UpdateVictim())
415 return;
416
418 {
419 // NBD: this should only happen in practice if there is nobody left alive on our side (we should open gate)
420 // thus we only do a cursory check to make sure (edge cases?)
421 if (Player* newTarget = FindEligibleTarget(me, _gateIsOpen))
422 {
424 AddThreat(newTarget, 1.0f);
425 AttackStart(newTarget);
426 }
427 else
428 OpenGate();
429 }
430
431 events.Update(diff);
432
434 OpenGate();
435
436 while (uint32 eventId = events.ExecuteEvent())
437 {
438 switch (eventId)
439 {
440 case EVENT_SUMMON:
441 {
442 if (RAID_MODE(waves10.size(), waves25.size()) <= _waveCount) // bounds check
443 {
444 TC_LOG_INFO("scripts", "GothikAI: Wave count {} is out of range for difficulty {}.", _waveCount, static_cast<uint32>(GetDifficulty()));
445 break;
446 }
447
448 std::list<Creature*> triggers;
451 {
452 for (uint32 i = 0; i < entry.Count; ++i)
453 {
454 // GUID layout is as follows:
455 // CGUID+4: center (back of platform) - primary rider spawn
456 // CGUID+5: north (back of platform) - primary knight spawn
457 // CGUID+6: center (front of platform) - second spawn
458 // CGUID+7: south (front of platform) - primary trainee spawn
459 uint32 targetDBGuid;
460 switch (entry.CreatureId)
461 {
462 case NPC_LIVE_RIDER: // only spawns from center (back) > north
463 targetDBGuid = (CGUID_TRIGGER + 4) + (i % 2);
464 break;
465 case NPC_LIVE_KNIGHT: // spawns north > center (front) > south
466 targetDBGuid = (CGUID_TRIGGER + 5) + (i % 3);
467 break;
468 case NPC_LIVE_TRAINEE: // spawns south > center (front) > north
469 targetDBGuid = (CGUID_TRIGGER + 7) - (i % 3);
470 break;
471 default:
472 continue;
473 }
474
475 auto triggerItr = std::ranges::find(triggers, targetDBGuid, [](Creature const* trigger) { return trigger->GetSpawnId(); });
476 if (triggerItr != triggers.end())
477 DoSummon(entry.CreatureId, *triggerItr, 1.0f, 15s, TEMPSUMMON_CORPSE_TIMED_DESPAWN);
478 }
479 }
480
481 if (Seconds timeToNext = RAID_MODE(waves10[_waveCount], waves25[_waveCount]).TimeToNextWave; timeToNext > 0s)
482 events.Repeat(timeToNext);
483
484 ++_waveCount;
485 break;
486 }
488 _gateCanOpen = true;
489 for (ObjectGuid summonGuid : summons)
490 if (Creature* summon = ObjectAccessor::GetCreature(*me, summonGuid))
491 if (summon->IsAlive() && (!summon->IsInCombat() || summon->IsInEvadeMode()))
492 {
493 OpenGate();
494 break;
495 }
496 break;
497 case EVENT_PHASE_TWO:
507 break;
508 case EVENT_TELEPORT:
509 if (!HealthBelowPct(30))
510 {
511 me->CastStop();
512 me->AttackStop();
513 me->StopMoving();
518
521 events.Repeat(Seconds(20));
522 }
523 break;
524
525 case EVENT_HARVEST:
526 DoCastAOE(SPELL_HARVEST_SOUL, true); // triggered allows this to go "through" shadow bolt
527 events.Repeat(Seconds(15));
528 break;
532 // return to the start of this method so victim side etc is re-evaluated
533 return UpdateAI(0u); // tail recursion for efficiency
534 case EVENT_BOLT:
537 break;
538 case EVENT_INTRO_2:
540 break;
541 case EVENT_INTRO_3:
543 break;
544 case EVENT_INTRO_4:
546 break;
547 default:
548 break;
549 }
550 }
551 }
552
553 private:
558};
559
561{
562 public:
563 npc_gothik_minion_baseAI(Creature* creature, uint32 deathNotify=0) : ScriptedAI(creature), _deathNotify(deathNotify), _gateIsOpen(false) { }
564
565 void JustDied(Unit* /*killer*/) override
566 {
567 if (_deathNotify)
568 DoCastAOE(_deathNotify, true);
569 }
570
571 inline bool isOnSameSide(Unit const* who) const
572 {
573 return IsOnSameSide(me, who);
574 }
575
576 void DamageTaken(Unit* attacker, uint32& damage, DamageEffectType /*damageType*/, SpellInfo const* /*spellInfo = nullptr*/) override
577 { // do not allow minions to take damage before the gate is opened
578 if (!_gateIsOpen && (!attacker || !isOnSameSide(attacker)))
579 damage = 0;
580 }
581
582 void DoAction(int32 action) override
583 {
584 switch (action)
585 {
587 _gateIsOpen = true;
588 [[fallthrough]];
590 if (Player* target = FindEligibleTarget(me, _gateIsOpen))
591 {
592 AddThreat(target, 1.0f);
593 AttackStart(target);
594 }
595 else
597 break;
598 }
599 }
600
601 void EnterEvadeMode(EvadeReason why) override
602 {
604
605 if (InstanceScript* instance = me->GetInstanceScript())
606 if (Creature* gothik = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_GOTHIK)))
607 gothik->AI()->DoAction(ACTION_MINION_EVADE);
608 }
609
610 void UpdateAI(uint32 diff) override
611 {
612 if (!UpdateVictim())
613 return;
614
616 { // reset threat, then try to find someone on same side as us to attack
617 if (Player* newTarget = FindEligibleTarget(me, _gateIsOpen))
618 {
621 AddThreat(newTarget, 1.0f);
622 AttackStart(newTarget);
623 }
624 else
626 }
627
628 _UpdateAI(diff);
629 }
630
631 virtual void _UpdateAI(uint32 diff) { ScriptedAI::UpdateAI(diff); }
632
633 private:
636};
637
654
671
702
719
736
738{
740
746
752
753 void _UpdateAI(uint32 diff) override
754 {
755 if (diff < _frenzyTimer)
756 _frenzyTimer -= diff;
758 _frenzyTimer = 0;
759 else
760 { // target priority: knight > other rider > horse > gothik
761 std::list<Creature*> potentialTargets = DoFindFriendlyMissingBuff(30.0, SPELL_UNHOLY_FRENZY);
762 Creature *knightTarget = nullptr, *riderTarget = nullptr, *horseTarget = nullptr, *gothikTarget = nullptr;
763 for (Creature* pTarget : potentialTargets)
764 {
765 switch (pTarget->GetEntry())
766 {
767 case NPC_DEAD_KNIGHT:
768 knightTarget = pTarget;
769 break;
770 case NPC_DEAD_RIDER:
771 riderTarget = pTarget;
772 break;
773 case NPC_DEAD_HORSE:
774 horseTarget = pTarget;
775 break;
776 case NPC_GOTHIK:
777 gothikTarget = pTarget;
778 break;
779 }
780 if (knightTarget)
781 break;
782 }
783 Creature* target = knightTarget ? knightTarget : riderTarget ? riderTarget : horseTarget ? horseTarget : gothikTarget ? gothikTarget : nullptr;
784 if (target)
787 }
788
789 if (diff < _drainTimer)
790 _drainTimer -= diff;
791 else
792 {
794 _drainTimer = urandms(10,15);
795 }
796
798 }
800};
801
803{
805
806 void _UpdateAI(uint32 diff)
807 {
808 if (diff < _stompTimer)
809 _stompTimer -= diff;
810 else
811 {
813 _stompTimer = urandms(14, 18);
814 }
815 }
817};
818
820{
821 npc_gothik_trigger(Creature* creature) : ScriptedAI(creature) { creature->SetDisableGravity(true); }
822
823 void EnterEvadeMode(EvadeReason /*why*/) override { }
824 void UpdateAI(uint32 /*diff*/) override { }
825 void JustEngagedWith(Unit* /*who*/) override { }
826 void DamageTaken(Unit* /*who*/, uint32& damage, DamageEffectType /*damageType*/, SpellInfo const* /*spellInfo = nullptr*/) override { damage = 0; }
827
829 {
830 std::list<Creature*> triggers;
832 uint32 targetDBGuid = CGUID_TRIGGER + urand(8, 12); // CGUID+8 to CGUID+12 are the triggers for the skull piles on dead side
833 for (Creature* trigger : triggers)
834 if (trigger && trigger->GetSpawnId() == targetDBGuid)
835 return trigger;
836
837 return nullptr;
838 }
839
840 void SpellHit(WorldObject* /*caster*/, SpellInfo const* spellInfo) override
841 {
842 switch (spellInfo->Id)
843 {
846 break;
849 break;
852 break;
854 if (Creature* target = SelectRandomSkullPile())
855 DoCast(target, SPELL_SKULLS_TRAINEE, true);
856 break;
858 if (Creature* target = SelectRandomSkullPile())
859 DoCast(target, SPELL_SKULLS_DK, true);
860 break;
862 if (Creature* target = SelectRandomSkullPile())
863 DoCast(target, SPELL_SKULLS_RIDER, true);
864 break;
867 break;
868 case SPELL_SKULLS_DK:
870 break;
874 break;
875 }
876 }
877
878 // dead side summons are "owned" by gothik
879 void JustSummoned(Creature* summon) override
880 {
882 gothik->AI()->JustSummoned(summon);
883 }
884 void SummonedCreatureDespawn(Creature* summon) override
885 {
887 gothik->AI()->SummonedCreatureDespawn(summon);
888 }
889};
890
891// 27831, 55638 - Shadow Bolt Volley
904
@ IN_MILLISECONDS
Definition Common.h:38
int64_t int64
Definition Define.h:149
int32_t int32
Definition Define.h:150
uint32_t uint32
Definition Define.h:154
std::chrono::seconds Seconds
Seconds shorthand typedef.
Definition Duration.h:28
std::chrono::minutes Minutes
Minutes shorthand typedef.
Definition Duration.h:32
#define TC_LOG_INFO(filterType__, message__,...)
Definition Log.h:184
@ TEMPSUMMON_CORPSE_TIMED_DESPAWN
@ TYPEID_PLAYER
Definition ObjectGuid.h:44
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:1383
@ EFFECT_0
@ TARGET_UNIT_SRC_AREA_ENEMY
@ GO_STATE_READY
@ GO_STATE_ACTIVE
@ SPELL_AURA_MOD_TAUNT
#define SpellObjectAreaTargetSelectFn(F, I, N)
EvadeReason
@ REACT_PASSIVE
@ REACT_AGGRESSIVE
DamageEffectType
@ UNIT_STATE_CASTING
Definition Unit.h:276
Creatures
const uint32 CGUID_TRIGGER
@ ACTION_ACQUIRE_TARGET
@ ACTION_MINION_EVADE
@ ACTION_GATE_OPENED
Creatures
@ NPC_DEAD_HORSE
@ NPC_DEAD_TRAINEE
@ NPC_LIVE_TRAINEE
@ NPC_DEAD_RIDER
@ NPC_DEAD_KNIGHT
@ NPC_LIVE_KNIGHT
@ NPC_LIVE_RIDER
@ NPC_TRIGGER
static AreaBoundary *const livingSide
#define SPELL_DEATH_PLAGUE
@ SAY_DEATH
@ SAY_INTRO_2
@ SAY_PHASE_TWO
@ SAY_INTRO_1
@ SAY_KILL
@ EMOTE_PHASE_TWO
@ SAY_INTRO_3
@ SAY_INTRO_4
@ EMOTE_GATE_OPENED
#define SPELL_SHADOW_BOLT_VOLLEY
#define SPELL_ARCANE_EXPLOSION
#define SPELL_DRAIN_LIFE
static constexpr std::array< GothikWaveInfo, 19 > waves10
#define SPELL_UNHOLY_AURA
@ SPELL_STOMP
@ SPELL_ANCHOR_1_DK
@ SPELL_ANCHOR_1_TRAINEE
@ SPELL_ANCHOR_2_RIDER
@ SPELL_SKULLS_DK
@ SPELL_SHADOW_BOLT
@ SPELL_HARVEST_SOUL
@ SPELL_ANCHOR_2_DK
@ SPELL_SKULLS_TRAINEE
@ SPELL_SHADOW_MARK
@ SPELL_SKULLS_RIDER
@ SPELL_ANCHOR_1_RIDER
@ SPELL_TELEPORT_LIVE
@ SPELL_WHIRLWIND
@ SPELL_TELEPORT_DEAD
@ SPELL_ANCHOR_2_TRAINEE
@ PHASE_ONE
@ PHASE_TWO
void AddSC_boss_gothik()
static bool IsOnSameSide(Position const *who, Position const *other)
@ SIDE_DEAD
@ SIDE_LIVING
@ SIDE_NONE
static AreaBoundary *const deadSide
static Side GetSide(Position const *who)
#define SPELL_UNHOLY_FRENZY
@ 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 constexpr std::array< GothikWaveInfo, 18 > waves25
static Player * FindEligibleTarget(Creature const *me, bool isGateOpen)
Yells
bool IsWithinBoundary(Position const *pos) const
TypeID GetTypeId() const
Definition BaseEntity.h:166
InstanceScript *const instance
void JustEngagedWith(Unit *who) override
SummonList summons
EventMap events
virtual void JustReachedHome()
Definition CreatureAI.h:167
virtual void EnterEvadeMode(EvadeReason why=EvadeReason::Other)
virtual void JustAppeared()
bool UpdateVictim()
Creature *const me
Definition CreatureAI.h:63
Creature * DoSummon(uint32 entry, Position const &pos, Milliseconds despawnTime=30s, TempSummonType summonType=TEMPSUMMON_CORPSE_TIMED_DESPAWN)
void GetHomePosition(float &x, float &y, float &z, float &ori) const
Definition Creature.h:388
bool HasReactState(ReactStates state) const
Definition Creature.h:176
void SetReactState(ReactStates st)
Definition Creature.h:174
void DespawnOrUnsummon(Milliseconds timeToDespawn=0s, Seconds forceRespawnTime=0s)
ObjectGuid::LowType GetSpawnId() const
Definition Creature.h:110
CreatureAI * AI() const
Definition Creature.h:228
uint32 ExecuteEvent()
Definition EventMap.cpp:77
void Update(uint32 time)
Definition EventMap.h:61
void Repeat(Milliseconds time)
Definition EventMap.cpp:67
void ScheduleEvent(uint32 eventId, Milliseconds time, uint32 group=0, uint8 phase=0)
Definition EventMap.cpp:40
bool IsInPhase(uint8 phase) const
Definition EventMap.h:222
void CancelEvent(uint32 eventId)
Definition EventMap.cpp:135
void SetPhase(uint8 phase)
Definition EventMap.cpp:32
virtual ObjectGuid GetGuidData(uint32 type) const override
PlayerList const & GetPlayers() const
Definition Map.h:403
iterator end()
Definition RefManager.h:36
iterator begin()
Definition RefManager.h:35
uint32 const Id
Definition SpellInfo.h:328
HookList< ObjectAreaTargetSelectHandler > OnObjectAreaTargetSelect
bool empty() const
void Despawn(Creature const *summon)
void Summon(Creature const *summon)
bool IsThreatListEmpty(bool includeOffline=false) const
SpellCastResult DoCastSelf(uint32 spellId, CastSpellExtraArgs const &args={})
Definition UnitAI.h:160
virtual void DoAction(int32 param)
Definition UnitAI.h:73
SpellCastResult DoCastVictim(uint32 spellId, CastSpellExtraArgs const &args={})
Definition UnitAI.cpp:180
SpellCastResult DoCastAOE(uint32 spellId, CastSpellExtraArgs const &args={})
Definition UnitAI.h:162
SpellCastResult DoCast(uint32 spellId)
Definition UnitAI.cpp:89
Definition Unit.h:635
void CastStop(uint32 except_spellid=0)
Definition Unit.cpp:1186
void RemoveAurasByType(AuraType auraType, std::function< bool(AuraApplication const *)> const &check, AuraRemoveMode removeMode=AURA_REMOVE_BY_DEFAULT)
Definition Unit.cpp:3955
ThreatManager & GetThreatManager()
Definition Unit.h:1078
void StopMoving()
Definition Unit.cpp:10680
bool SetDisableGravity(bool disable, bool updateAnimTier=true)
Definition Unit.cpp:13361
bool isInAccessiblePlaceFor(Creature const *c) const
Definition Unit.cpp:3310
Unit * GetVictim() const
Definition Unit.h:726
void NearTeleportTo(TeleportLocation const &target, bool casting=false)
Definition Unit.cpp:12958
bool HasUnitState(const uint32 f) const
Definition Unit.h:743
bool AttackStop()
Definition Unit.cpp:5965
bool IsInCombat() const
Definition Unit.h:1058
Map * GetMap() const
Definition Object.h:411
InstanceScript * GetInstanceScript() const
Definition Object.cpp:396
void GetCreatureListWithEntryInGrid(Container &creatureContainer, uint32 entry, float maxSearchRange=250.0f) const
Definition Object.cpp:2658
bool IsValidAttackTarget(WorldObject const *target, SpellInfo const *bySpell=nullptr) const
Definition Object.cpp:2324
bool CanSeeOrDetect(WorldObject const *obj, CanSeeOrDetectExtraArgs const &args={ }) const
Definition Object.cpp:857
virtual void SetData(uint32, uint32)
Definition ZoneScript.h:100
void FilterTargets(std::list< WorldObject * > &targets)
TC_GAME_API Creature * GetCreature(WorldObject const &u, ObjectGuid const &guid)
@ 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
std::array< GothikWaveEntry, 3 > Creatures
constexpr GothikWaveInfo(std::initializer_list< GothikWaveEntry > waves, int64 timeToNextWave)
Seconds TimeToNextWave
constexpr float GetPositionX() const
Definition Position.h:87
constexpr float GetPositionY() const
Definition Position.h:88
constexpr float GetOrientation() const
Definition Position.h:90
constexpr float GetPositionZ() const
Definition Position.h:89
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 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)