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 "SpellScript.h"
29
30/* Constants */
44
46{
47 /* living trainee spells */
49
50 /* living knight spells */
52
53 /* living rider spells */
55
56 /* spectral trainee spells */
58
59 /* spectral knight spells */
61
62 /* spectral rider spells */
65
66 /* spectral horse spells */
67 SPELL_STOMP = 27993,
68
69 /* gothik phase two spells */
72
73 /* visual spells */
77
81
85
86 /* teleport spells */
89};
90#define SPELLHELPER_UNHOLY_FRENZY RAID_MODE<uint32>(SPELL_UNHOLY_FRENZY,27995)
91
104
106{
108 PHASE_TWO = 2
110
124
131
132/* Room side checking logic */
133static AreaBoundary* const livingSide = new RectangleBoundary(2633.84f, 2750.49f, -3434.0f, -3360.78f);
134static AreaBoundary* const deadSide = new RectangleBoundary(2633.84f, 2750.49f, -3360.78f, -3285.0f);
141inline static Side GetSide(Position const* who)
142{
144 return SIDE_LIVING;
145 if (deadSide->IsWithinBoundary(who))
146 return SIDE_DEAD;
147 return SIDE_NONE;
148}
149inline static bool IsOnSameSide(Position const* who, Position const* other)
150{
151 return (GetSide(who) == GetSide(other));
152}
153static Player* FindEligibleTarget(Creature const* me, bool isGateOpen)
154{
155 Map::PlayerList const& players = me->GetMap()->GetPlayers();
156 for (Map::PlayerList::const_iterator it = players.begin(); it != players.end(); ++it)
157 {
158 Player* player = it->GetSource();
159 if (player && (isGateOpen || IsOnSameSide(me, player)) && me->CanSeeOrDetect(player) && me->IsValidAttackTarget(player) && player->isInAccessiblePlaceFor(me))
160 {
161 return player;
162 }
163 }
164
165 return nullptr;
166}
167
168/* Wave data */
169typedef std::pair<uint32, uint8> GothikWaveEntry; // (npcEntry, npcCount)
170typedef std::set<GothikWaveEntry> GothikWave;
171typedef std::pair<GothikWave, uint8> GothikWaveInfo; // (wave, secondsToNext)
172typedef std::vector<GothikWaveInfo> GothikWaveData;
174{
175 {
176 {{NPC_LIVE_TRAINEE, 2}},
177 20},
178 {
179 {{NPC_LIVE_TRAINEE, 2}},
180 20},
181 {
182 {{NPC_LIVE_TRAINEE, 2}},
183 10},
184 {
185 {{NPC_LIVE_KNIGHT, 1}},
186 10},
187 {
188 {{NPC_LIVE_TRAINEE, 2}},
189 15},
190 {
191 {{NPC_LIVE_KNIGHT, 1}},
192 5},
193 {
194 {{NPC_LIVE_TRAINEE, 2}},
195 20},
196 {
198 10},
199 {
200 {{NPC_LIVE_RIDER, 1}},
201 10},
202 {
203 {{NPC_LIVE_TRAINEE, 2}},
204 5},
205 {
206 {{NPC_LIVE_KNIGHT, 1}},
207 15},
208 {
209 {{NPC_LIVE_TRAINEE, 2}, {NPC_LIVE_RIDER, 1}},
210 10},
211 {
212 {{NPC_LIVE_KNIGHT, 2}},
213 10},
214 {
215 {{NPC_LIVE_TRAINEE, 2}},
216 10},
217 {
218 {{NPC_LIVE_RIDER, 1}},
219 5},
220 {
221 {{NPC_LIVE_KNIGHT, 1}},
222 5},
223 {
224 {{NPC_LIVE_TRAINEE, 2}},
225 20},
226 {
228 15},
229 {
230 {{NPC_LIVE_TRAINEE, 2}},
231 0}
232};
233
235{
236 {
237 {{NPC_LIVE_TRAINEE, 3}},
238 20},
239 {
240 {{NPC_LIVE_TRAINEE, 3}},
241 20},
242 {
243 {{NPC_LIVE_TRAINEE, 3}},
244 10},
245 {
246 {{NPC_LIVE_KNIGHT, 2}},
247 10},
248 {
249 {{NPC_LIVE_TRAINEE, 3}},
250 15},
251 {
252 {{NPC_LIVE_KNIGHT, 2}},
253 5},
254 {
255 {{NPC_LIVE_TRAINEE, 3}},
256 20},
257 {
259 10},
260 {
261 {{NPC_LIVE_TRAINEE, 3}},
262 10},
263 {
264 {{NPC_LIVE_RIDER, 1}},
265 5},
266 {
267 {{NPC_LIVE_TRAINEE, 3}},
268 15},
269 {
270 {{NPC_LIVE_RIDER, 1}},
271 10},
272 {
273 {{NPC_LIVE_KNIGHT, 2}},
274 10},
275 {
276 {{NPC_LIVE_RIDER, 1}},
277 10},
278 {
279 {{NPC_LIVE_RIDER, 1}, {NPC_LIVE_TRAINEE, 3}},
280 5},
281 {
283 5},
284 {
285 {{NPC_LIVE_RIDER, 1}, {NPC_LIVE_TRAINEE, 3}},
286 20},
287 {
289 0}
290};
291
292// GUID of first trigger NPC (used as offset for guid checks)
293// 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
294const uint32 CGUID_TRIGGER = 127618;
295/* Creature AI */
296struct boss_gothik : public BossAI
297{
298 boss_gothik(Creature* creature) : BossAI(creature, BOSS_GOTHIK)
299 {
300 Initialize();
301 }
302
304 {
305 _waveCount = 0;
306 _gateCanOpen = false;
307 _gateIsOpen = true;
308 _lastTeleportDead = false;
309 }
310
311 void Reset() override
312 {
315 _Reset();
316 Initialize();
317 }
318
333
334 void JustSummoned(Creature* summon) override
335 {
336 summons.Summon(summon);
337 if (me->IsInCombat())
338 {
340 summon->SetCombatPulseDelay(5);
341 }
342 else
343 summon->DespawnOrUnsummon();
344 }
345
346 void SummonedCreatureDespawn(Creature* summon) override
347 {
348 summons.Despawn(summon);
349 }
350
351 void KilledUnit(Unit* victim) override
352 {
353 if (victim && victim->GetTypeId() == TYPEID_PLAYER)
354 Talk(SAY_KILL);
355 }
356
357 void JustDied(Unit* /*killer*/) override
358 {
359 _JustDied();
362 _gateIsOpen = false;
363 }
364
365 void OpenGate()
366 {
367 if (_gateIsOpen)
368 return;
371 _gateIsOpen = true;
372
373 for (ObjectGuid summonGuid : summons)
374 {
375 if (Creature* summon = ObjectAccessor::GetCreature(*me, summonGuid))
376 summon->AI()->DoAction(ACTION_GATE_OPENED);
377 if (summons.empty()) // ACTION_GATE_OPENED may cause an evade, despawning summons and invalidating our iterator
378 break;
379 }
380 }
381
382 void DamageTaken(Unit* /*who*/, uint32& damage, DamageEffectType /*damageType*/, SpellInfo const* /*spellInfo = nullptr*/) override
383 {
385 damage = 0;
386 }
387
388 void DoAction(int32 action) override
389 {
390 switch (action)
391 {
395 if (_gateCanOpen)
396 OpenGate();
397 break;
398 }
399 }
400
401 void EnterEvadeMode(EvadeReason why) override
402 {
404 Position const& home = me->GetHomePosition();
405 me->NearTeleportTo(home.GetPositionX(), home.GetPositionY(), home.GetPositionZ(), home.GetOrientation());
406 }
407
408 void UpdateAI(uint32 diff) override
409 {
410 if (!UpdateVictim())
411 return;
412
414 {
415 // NBD: this should only happen in practice if there is nobody left alive on our side (we should open gate)
416 // thus we only do a cursory check to make sure (edge cases?)
417 if (Player* newTarget = FindEligibleTarget(me, _gateIsOpen))
418 {
420 AddThreat(newTarget, 1.0f);
421 AttackStart(newTarget);
422 }
423 else
424 OpenGate();
425 }
426
427 events.Update(diff);
428
430 OpenGate();
431
432 while (uint32 eventId = events.ExecuteEvent())
433 {
434 switch (eventId)
435 {
436 case EVENT_SUMMON:
437 {
438 if (RAID_MODE(waves10,waves25).size() <= _waveCount) // bounds check
439 {
440 TC_LOG_INFO("scripts", "GothikAI: Wave count {} is out of range for difficulty {}.", _waveCount, static_cast<uint32>(GetDifficulty()));
441 break;
442 }
443
444 std::list<Creature*> triggers;
446 for (GothikWaveEntry entry : RAID_MODE(waves10, waves25)[_waveCount].first)
447 for (uint8 i = 0; i < entry.second; ++i)
448 {
449 // GUID layout is as follows:
450 // CGUID+4: center (back of platform) - primary rider spawn
451 // CGUID+5: north (back of platform) - primary knight spawn
452 // CGUID+6: center (front of platform) - second spawn
453 // CGUID+7: south (front of platform) - primary trainee spawn
454 uint32 targetDBGuid;
455 switch (entry.first)
456 {
457 case NPC_LIVE_RIDER: // only spawns from center (back) > north
458 targetDBGuid = (CGUID_TRIGGER + 4) + (i % 2);
459 break;
460 case NPC_LIVE_KNIGHT: // spawns north > center (front) > south
461 targetDBGuid = (CGUID_TRIGGER + 5) + (i % 3);
462 break;
463 case NPC_LIVE_TRAINEE: // spawns south > center (front) > north
464 targetDBGuid = (CGUID_TRIGGER + 7) - (i % 3);
465 break;
466 default:
467 targetDBGuid = 0;
468 }
469
470 for (Creature* trigger : triggers)
471 if (trigger && trigger->GetSpawnId() == targetDBGuid)
472 {
473 DoSummon(entry.first, trigger, 1.0f, 15s, TEMPSUMMON_CORPSE_TIMED_DESPAWN);
474 break;
475 }
476 }
477
478 if (uint8 timeToNext = RAID_MODE(waves10, waves25)[_waveCount].second)
479 events.Repeat(Seconds(timeToNext));
480
481 ++_waveCount;
482 break;
483 }
485 _gateCanOpen = true;
486 for (ObjectGuid summonGuid : summons)
487 if (Creature* summon = ObjectAccessor::GetCreature(*me, summonGuid))
488 if (summon->IsAlive() && (!summon->IsInCombat() || summon->IsInEvadeMode()))
489 {
490 OpenGate();
491 break;
492 }
493 break;
494 case EVENT_PHASE_TWO:
504 break;
505 case EVENT_TELEPORT:
506 if (!HealthBelowPct(30))
507 {
508 me->CastStop();
509 me->AttackStop();
510 me->StopMoving();
515
518 events.Repeat(Seconds(20));
519 }
520 break;
521
522 case EVENT_HARVEST:
523 DoCastAOE(SPELL_HARVEST_SOUL, true); // triggered allows this to go "through" shadow bolt
524 events.Repeat(Seconds(15));
525 break;
529 // return to the start of this method so victim side etc is re-evaluated
530 return UpdateAI(0u); // tail recursion for efficiency
531 case EVENT_BOLT:
534 break;
535 case EVENT_INTRO_2:
537 break;
538 case EVENT_INTRO_3:
540 break;
541 case EVENT_INTRO_4:
543 break;
544 }
545 }
546 }
547
548 private:
553};
554
556{
557 public:
558 npc_gothik_minion_baseAI(Creature* creature, uint32 deathNotify=0) : ScriptedAI(creature), _deathNotify(deathNotify), _gateIsOpen(false) { }
559
560 void JustDied(Unit* /*killer*/) override
561 {
562 if (_deathNotify)
563 DoCastAOE(_deathNotify, true);
564 }
565
566 inline bool isOnSameSide(Unit const* who) const
567 {
568 return IsOnSameSide(me, who);
569 }
570
571 void DamageTaken(Unit* attacker, uint32& damage, DamageEffectType /*damageType*/, SpellInfo const* /*spellInfo = nullptr*/) override
572 { // do not allow minions to take damage before the gate is opened
573 if (!_gateIsOpen && (!attacker || !isOnSameSide(attacker)))
574 damage = 0;
575 }
576
577 void DoAction(int32 action) override
578 {
579 switch (action)
580 {
582 _gateIsOpen = true;
583 [[fallthrough]];
585 if (Player* target = FindEligibleTarget(me, _gateIsOpen))
586 {
587 AddThreat(target, 1.0f);
588 AttackStart(target);
589 }
590 else
592 break;
593 }
594 }
595
596 void EnterEvadeMode(EvadeReason why) override
597 {
599
600 if (InstanceScript* instance = me->GetInstanceScript())
601 if (Creature* gothik = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_GOTHIK)))
602 gothik->AI()->DoAction(ACTION_MINION_EVADE);
603 }
604
605 void UpdateAI(uint32 diff) override
606 {
607 if (!UpdateVictim())
608 return;
609
611 { // reset threat, then try to find someone on same side as us to attack
612 if (Player* newTarget = FindEligibleTarget(me, _gateIsOpen))
613 {
616 AddThreat(newTarget, 1.0f);
617 AttackStart(newTarget);
618 }
619 else
621 }
622
623 _UpdateAI(diff);
624 }
625
626 virtual void _UpdateAI(uint32 diff) { ScriptedAI::UpdateAI(diff); };
627
628 private:
631};
632
650
668
687
705
723
725{
727
728 void _UpdateAI(uint32 diff)
729 {
730 if (diff < _frenzyTimer)
731 _frenzyTimer -= diff;
733 _frenzyTimer = 0;
734 else
735 { // target priority: knight > other rider > horse > gothik
736 std::list<Creature*> potentialTargets = DoFindFriendlyMissingBuff(30.0, SPELLHELPER_UNHOLY_FRENZY);
737 Creature *knightTarget = nullptr, *riderTarget = nullptr, *horseTarget = nullptr, *gothikTarget = nullptr;
738 for (Creature* pTarget : potentialTargets)
739 {
740 switch (pTarget->GetEntry())
741 {
742 case NPC_DEAD_KNIGHT:
743 knightTarget = pTarget;
744 break;
745 case NPC_DEAD_RIDER:
746 riderTarget = pTarget;
747 break;
748 case NPC_DEAD_HORSE:
749 horseTarget = pTarget;
750 break;
751 case NPC_GOTHIK:
752 gothikTarget = pTarget;
753 break;
754 }
755 if (knightTarget)
756 break;
757 }
758 Creature* target = knightTarget ? knightTarget : riderTarget ? riderTarget : horseTarget ? horseTarget : gothikTarget ? gothikTarget : nullptr;
759 if (target)
762 }
763
764 if (diff < _drainTimer)
765 _drainTimer -= diff;
766 else
767 {
769 _drainTimer = urandms(10,15);
770 }
771
774 }
776};
777
779{
781
782 void _UpdateAI(uint32 diff)
783 {
784 if (diff < _stompTimer)
785 _stompTimer -= diff;
786 else
787 {
789 _stompTimer = urandms(14, 18);
790 }
792 }
794};
795
797{
798 npc_gothik_trigger(Creature* creature) : ScriptedAI(creature) { creature->SetDisableGravity(true); }
799
800 void EnterEvadeMode(EvadeReason /*why*/) override { }
801 void UpdateAI(uint32 /*diff*/) override { }
802 void JustEngagedWith(Unit* /*who*/) override { }
803 void DamageTaken(Unit* /*who*/, uint32& damage, DamageEffectType /*damageType*/, SpellInfo const* /*spellInfo = nullptr*/) override { damage = 0; }
804
806 {
807 std::list<Creature*> triggers;
809 uint32 targetDBGuid = CGUID_TRIGGER + urand(8, 12); // CGUID+8 to CGUID+12 are the triggers for the skull piles on dead side
810 for (Creature* trigger : triggers)
811 if (trigger && trigger->GetSpawnId() == targetDBGuid)
812 return trigger;
813
814 return nullptr;
815 }
816
817 void SpellHit(WorldObject* /*caster*/, SpellInfo const* spellInfo) override
818 {
819 switch (spellInfo->Id)
820 {
823 break;
826 break;
829 break;
831 if (Creature* target = SelectRandomSkullPile())
832 DoCast(target, SPELL_SKULLS_TRAINEE, true);
833 break;
835 if (Creature* target = SelectRandomSkullPile())
836 DoCast(target, SPELL_SKULLS_DK, true);
837 break;
839 if (Creature* target = SelectRandomSkullPile())
840 DoCast(target, SPELL_SKULLS_RIDER, true);
841 break;
844 break;
845 case SPELL_SKULLS_DK:
847 break;
851 break;
852 }
853 }
854
855 // dead side summons are "owned" by gothik
856 void JustSummoned(Creature* summon) override
857 {
859 gothik->AI()->JustSummoned(summon);
860 }
861 void SummonedCreatureDespawn(Creature* summon) override
862 {
864 gothik->AI()->SummonedCreatureDespawn(summon);
865 }
866};
867
868// 27831, 55638 - Shadow Bolt Volley
883
Actions
@ IN_MILLISECONDS
Definition Common.h:35
uint8_t uint8
Definition Define.h:135
int32_t int32
Definition Define.h:129
uint32_t uint32
Definition Define.h:133
std::chrono::seconds Seconds
Seconds shorthand typedef.
Definition Duration.h:27
std::chrono::minutes Minutes
Minutes shorthand typedef.
Definition Duration.h:30
#define TC_LOG_INFO(filterType__,...)
Definition Log.h:159
@ TEMPSUMMON_CORPSE_TIMED_DESPAWN
@ TYPEID_PLAYER
Definition ObjectGuid.h:39
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:1128
@ EFFECT_0
@ TARGET_UNIT_SRC_AREA_ENEMY
@ GO_STATE_READY
@ GO_STATE_ACTIVE
@ SPELL_AURA_MOD_TAUNT
#define SpellObjectAreaTargetSelectFn(F, I, N)
@ REACT_PASSIVE
@ REACT_AGGRESSIVE
@ UNIT_STATE_CASTING
Definition Unit.h:235
DamageEffectType
Definition Unit.h:352
Creatures
std::vector< GothikWaveInfo > GothikWaveData
const uint32 CGUID_TRIGGER
@ ACTION_ACQUIRE_TARGET
@ ACTION_MINION_EVADE
@ ACTION_GATE_OPENED
@ 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
@ 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
std::set< GothikWaveEntry > GothikWave
@ SPELL_STOMP
@ SPELL_SHADOW_BOLT_VOLLEY
@ SPELL_ANCHOR_1_DK
@ SPELL_UNHOLY_FRENZY
@ SPELL_DEATH_PLAGUE
@ SPELL_ANCHOR_1_TRAINEE
@ SPELL_ANCHOR_2_RIDER
@ SPELL_ARCANE_EXPLOSION
@ 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_DRAIN_LIFE
@ 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
std::pair< uint32, uint8 > GothikWaveEntry
static AreaBoundary *const deadSide
const GothikWaveData waves25
std::pair< GothikWave, uint8 > GothikWaveInfo
static Side GetSide(Position const *who)
const GothikWaveData waves10
#define SPELLHELPER_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 Player * FindEligibleTarget(Creature const *me, bool isGateOpen)
Yells
bool IsWithinBoundary(Position const *pos) const
InstanceScript *const instance
void JustEngagedWith(Unit *who) override
SummonList summons
EventMap events
@ EVADE_REASON_NO_HOSTILES
Definition CreatureAI.h:94
bool UpdateVictim()
Creature *const me
Definition CreatureAI.h:82
Creature * DoSummon(uint32 entry, Position const &pos, Milliseconds despawnTime=30s, TempSummonType summonType=TEMPSUMMON_CORPSE_TIMED_DESPAWN)
virtual void EnterEvadeMode(EvadeReason why=EVADE_REASON_OTHER)
void SetCombatPulseDelay(uint32 delay)
Definition Creature.h:269
void GetHomePosition(float &x, float &y, float &z, float &ori) const
Definition Creature.h:295
bool HasReactState(ReactStates state) const
Definition Creature.h:121
void SetReactState(ReactStates st)
Definition Creature.h:119
void DespawnOrUnsummon(Milliseconds timeToDespawn=0s, Seconds forceRespawnTime=0s)
CreatureAI * AI() const
Definition Creature.h:154
void Update(uint32 time)
Definition EventMap.h:67
void Repeat(Milliseconds time)
Definition EventMap.cpp:63
EventId ExecuteEvent()
Definition EventMap.cpp:73
bool IsInPhase(PhaseIndex phase) const
Definition EventMap.h:236
void CancelEvent(EventId eventId)
Definition EventMap.cpp:151
void SetPhase(PhaseIndex phase)
Definition EventMap.cpp:28
void ScheduleEvent(EventId eventId, Milliseconds time, GroupIndex group=0u, PhaseIndex phase=0u)
Definition EventMap.cpp:36
virtual ObjectGuid GetGuidData(uint32 type) const override
iterator end()
iterator begin()
PlayerList const & GetPlayers() const
Definition Map.h:448
TypeID GetTypeId() const
Definition Object.h:93
uint32 Id
Definition SpellInfo.h:289
HookList< ObjectAreaTargetSelectHandler > OnObjectAreaTargetSelect
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:154
void DoMeleeAttackIfReady()
Definition UnitAI.cpp:54
SpellCastResult DoCastVictim(uint32 spellId, CastSpellExtraArgs const &args={})
Definition UnitAI.cpp:166
SpellCastResult DoCastAOE(uint32 spellId, CastSpellExtraArgs const &args={})
Definition UnitAI.h:243
SpellCastResult DoCast(uint32 spellId)
Definition UnitAI.cpp:106
Definition Unit.h:769
void CastStop(uint32 except_spellid=0)
Definition Unit.cpp:988
void RemoveAurasByType(AuraType auraType, std::function< bool(AuraApplication const *)> const &check, AuraRemoveMode removeMode=AURA_REMOVE_BY_DEFAULT)
Definition Unit.cpp:3765
ThreatManager & GetThreatManager()
Definition Unit.h:1155
void StopMoving(bool force=false)
Definition Unit.cpp:10312
bool SetDisableGravity(bool disable, bool updateAnimTier=true)
Definition Unit.cpp:13286
bool isInAccessiblePlaceFor(Creature const *c) const
Definition Unit.cpp:3154
void NearTeleportTo(Position const &pos, bool casting=false)
Definition Unit.cpp:12832
Unit * GetVictim() const
Definition Unit.h:859
bool HasUnitState(const uint32 f) const
Definition Unit.h:876
bool AttackStop()
Definition Unit.cpp:5645
bool IsInCombat() const
Definition Unit.h:1144
Map * GetMap() const
Definition Object.h:449
InstanceScript * GetInstanceScript() const
Definition Object.cpp:1087
void GetCreatureListWithEntryInGrid(Container &creatureContainer, uint32 entry, float maxSearchRange=250.0f) const
Definition Object.cpp:3153
bool IsValidAttackTarget(WorldObject const *target, SpellInfo const *bySpell=nullptr) const
Definition Object.cpp:2856
bool CanSeeOrDetect(WorldObject const *obj, bool implicitDetect=false, bool distanceCheck=false, bool checkAlert=false) const
Definition Object.cpp:1547
virtual void SetData(uint32, uint32)
Definition ZoneScript.h:56
void FilterTargets(std::list< WorldObject * > &targets)
PrepareSpellScript(spell_gothik_shadow_bolt_volley)
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
float GetPositionZ() const
Definition Position.h:81
float GetOrientation() const
Definition Position.h:82
float GetPositionX() const
Definition Position.h:79
float GetPositionY() const
Definition Position.h:80
void AttackStart(Unit *) override
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)
npc_gothik_minion_livingtrainee(Creature *creature)
npc_gothik_minion_spectralhorse(Creature *creature)
npc_gothik_minion_spectralknight(Creature *creature)
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)