TrinityCore
Loading...
Searching...
No Matches
boss_thorim.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 "CellImpl.h"
21#include "Containers.h"
22#include "GridNotifiersImpl.h"
23#include "InstanceScript.h"
24#include "MotionMaster.h"
25#include "MoveSplineInit.h"
26#include "ObjectAccessor.h"
27#include "Player.h"
28#include "ScriptedCreature.h"
29#include "SpellAuraEffects.h"
30#include "SpellMgr.h"
31#include "SpellScript.h"
32#include "ulduar.h"
33#include <G3D/Vector3.h>
34
36{
37 // Thorim
49 SPELL_LIGHTNING_ORB_CHARGED = 62186, // wrong duration, triggered spell should handle lightning release
52 SPELL_LIGHTNING_PILLAR_2 = 62976, // caster high position, target low position
53 SPELL_LIGHTNING_PILLAR_1 = 63238, // caster high position, target low position
58
59 // Credits
62
63 // Lightning Field
66
67 // Sif
69 SPELL_BLINK = 62578,
74
75 // Runic Colossus
76 SPELL_SMASH = 62339,
82
83 // Ancient Rune Giant
86};
87
88#define SPELL_STOMP RAID_MODE<uint32>(62411,62413)
89
96
141
171
214
235
244
267
277
283
285{
286 { { 2149.68f, -263.477f, 419.679f, 3.120f }, NPC_JORMUNGAR_BEHEMOTH },
287 { { 2131.31f, -271.640f, 419.840f, 2.188f }, NPC_MERCENARY_CAPTAIN_A },
288 { { 2127.24f, -259.182f, 419.974f, 5.917f }, NPC_MERCENARY_SOLDIER_A },
289 { { 2123.32f, -254.770f, 419.840f, 6.170f }, NPC_MERCENARY_SOLDIER_A },
290 { { 2120.10f, -258.990f, 419.840f, 6.250f }, NPC_MERCENARY_SOLDIER_A },
291 { { 2129.09f, -277.142f, 419.756f, 1.222f }, NPC_DARK_RUNE_ACOLYTE_PRE }
292};
293
295{
296 { { 2218.38f, -297.50f, 412.18f, 1.030f }, NPC_IRON_RING_GUARD },
297 { { 2235.07f, -297.98f, 412.18f, 1.613f }, NPC_IRON_RING_GUARD },
298 { { 2235.26f, -338.34f, 412.18f, 1.589f }, NPC_IRON_RING_GUARD },
299 { { 2217.69f, -337.39f, 412.18f, 1.241f }, NPC_IRON_RING_GUARD },
300 { { 2227.58f, -308.30f, 412.18f, 1.591f }, NPC_DARK_RUNE_ACOLYTE },
301 { { 2227.47f, -345.37f, 412.18f, 1.566f }, NPC_DARK_RUNE_ACOLYTE }
302};
303
305{
306 { { 2198.05f, -428.77f, 419.95f, 6.056f }, NPC_IRON_HONOR_GUARD },
307 { { 2220.31f, -436.22f, 412.26f, 1.064f }, NPC_IRON_HONOR_GUARD },
308 { { 2158.88f, -441.73f, 438.25f, 0.127f }, NPC_IRON_HONOR_GUARD },
309 { { 2198.29f, -436.92f, 419.95f, 0.261f }, NPC_DARK_RUNE_ACOLYTE },
310 { { 2230.93f, -434.27f, 412.26f, 1.931f }, NPC_DARK_RUNE_ACOLYTE }
311};
312
313Position const SifSpawnPosition = { 2148.301f, -297.8453f, 438.3308f, 2.687807f };
314
316{
319
324
325G3D::Vector3 const LightningOrbPath[] =
326{
327 { 2134.889893f, -298.632996f, 438.247467f },
328 { 2134.570068f, -440.317993f, 438.247467f },
329 { 2167.820312f, -440.330261f, 438.247589f },
330 { 2213.394287f, -433.318298f, 412.665863f },
331 { 2227.766113f, -433.275818f, 412.177032f },
332 { 2227.551270f, -263.081085f, 412.176880f },
333 { 2202.208008f, -262.939270f, 412.168976f },
334 { 2182.310059f, -263.233093f, 414.739410f }
335};
336
337// used for trash jump calculation
338Position const ArenaCenter = { 2134.77f, -262.307f };
339
340// used for lightning field calculation
341Position const LightningFieldCenter = { 2135.178f, -321.122f };
342
345
351
353{
354 public:
355 HeightPositionCheck(bool ret) : _ret(ret) { }
356
357 bool operator()(Position const* pos) const
358 {
359 return (pos->GetPositionZ() > THORIM_BALCONY_Z_CHECK) == _ret;
360 }
361
362 private:
363 bool _ret;
364
365 static float const THORIM_BALCONY_Z_CHECK;
366};
368
370{
371 public:
373
374 bool Execute(uint64 /*eventTime*/, uint32 /*updateTime*/) override
375 {
377 return true;
378 }
379
380 private:
382};
383
385{
386 public:
387 TrashJumpEvent(Creature* owner) : _owner(owner), _stage(0) { }
388
389 bool Execute(uint64 eventTime, uint32 /*updateTime*/) override
390 {
391 switch (_stage)
392 {
393 case 0:
394 _owner->CastSpell(nullptr, SPELL_LEAP);
395 ++_stage;
396 _owner->m_Events.AddEvent(this, Milliseconds(eventTime) + 2s);
397 return false;
398 case 1:
402 return true;
403 default:
404 break;
405 }
406
407 return true;
408 }
409
410 private:
413};
414
416{
417 public:
419
420 bool Execute(uint64 eventTime, uint32 /*updateTime*/) override
421 {
422 if (InstanceScript* instance = _owner->GetInstanceScript())
423 {
424 if (instance->GetBossState(DATA_THORIM) == IN_PROGRESS)
425 {
427 _owner->m_Events.AddEvent(this, Milliseconds(eventTime) + 1s);
428 return false;
429 }
430 }
431
434 return true;
435 }
436
437 private:
439};
440
442{
443 public:
444 boss_thorim() : CreatureScript("boss_thorim") { }
445
446 struct boss_thorimAI : public BossAI
447 {
448 boss_thorimAI(Creature* creature) : BossAI(creature, DATA_THORIM)
449 {
450 _encounterFinished = false;
451 Initialize();
452 }
453
455 {
456 _killedCount = 0;
457 _waveType = 0;
458 _hardMode = true;
459 _orbSummoned = false;
461 }
462
463 void Reset() override
464 {
466 return;
467
468 SetBoundary(nullptr);
469 _Reset();
470 Initialize();
471
473 me->SetDisableGravity(true);
475 me->SetImmuneToPC(true);
476
478
479 // Respawn Mini Bosses
480 for (uint8 i = DATA_RUNIC_COLOSSUS; i <= DATA_RUNE_GIANT; ++i)
482 miniBoss->Respawn(true);
483
484 // Spawn Pre Phase Adds
485 for (SummonLocation const& s : PreAddLocations)
487
489 lever->SetFlag(GO_FLAG_NOT_SELECTABLE);
490
491 // Remove trigger auras
493 pillar->RemoveAllAuras();
494
496 controller->RemoveAllAuras();
497
499 }
500
501 void EnterEvadeMode(EvadeReason /*why*/) override
502 {
505 }
506
507 void SetGUID(ObjectGuid const& guid, int32 id) override
508 {
509 if (id == DATA_CHARGED_PILLAR)
510 {
511 _activePillarGUID = guid;
512
514 {
515 pillar->CastSpell(pillar, SPELL_LIGHTNING_ORB_CHARGED, true);
516 pillar->CastSpell(nullptr, SPELL_LIGHTNING_PILLAR_2);
518 }
519 }
520 }
521
522 void KilledUnit(Unit* who) override
523 {
524 if (who->GetTypeId() == TYPEID_PLAYER)
525 Talk(SAY_SLAY);
526 }
527
528 void SpellHit(WorldObject* /*caster*/, SpellInfo const* spellInfo) override
529 {
530 if (spellInfo->Id == SPELL_TOUCH_OF_DOMINION_TRIGGERED)
531 {
533 {
534 sif->AI()->Talk(SAY_SIF_DESPAWN);
535 sif->DespawnOrUnsummon(6s);
536 _hardMode = false;
537 }
538 }
539 }
540
541 void SpellHitTarget(WorldObject* target, SpellInfo const* spellInfo) override
542 {
543 if (target->GetTypeId() == TYPEID_PLAYER && spellInfo->Id == SPELL_LIGHTNING_RELEASE)
545 }
546
548 {
550 return;
551
552 _encounterFinished = true;
553
554 DoCastAOE(SPELL_CREDIT_KILL, true); // before change faction
555
559 me->AttackStop();
562
564 controller->RemoveAllAuras();
566 pillar->RemoveAllAuras();
567
568 if (_hardMode)
569 {
571 {
572 summons.Despawn(sif);
573 sif->DespawnOrUnsummon(10s);
574 }
575 }
576
577 _JustDied();
578
583
585 }
586
587 void MovementInform(uint32 type, uint32 id) override
588 {
589 if (type != EFFECT_MOTION_TYPE || id != EVENT_JUMP)
590 return;
591
594 }
595
596 void JustEngagedWith(Unit* who) override
597 {
600
602
606
611
613
614 if (Creature* runicColossus = instance->GetCreature(DATA_RUNIC_COLOSSUS))
615 {
616 runicColossus->SetImmuneToPC(false);
617 runicColossus->AI()->DoAction(ACTION_ACTIVATE_ADDS);
618 }
619
621 lever->RemoveFlag(GO_FLAG_NOT_SELECTABLE);
622
623 // Summon Sif
625 }
626
627 void JustSummoned(Creature* summon) override
628 {
629 switch (summon->GetEntry())
630 {
632 {
634 summon->CastSpell(summon, SPELL_LIGHTNING_DESTRUCTION, true);
635
636 std::function<void(Movement::MoveSplineInit&)> initializer = [](Movement::MoveSplineInit& init)
637 {
638 init.MovebyPath(LightningOrbPath);
639 };
640 summon->GetMotionMaster()->LaunchMoveSpline(std::move(initializer), 0, MOTION_PRIORITY_NORMAL, POINT_MOTION_TYPE);
641 break;
642 }
648 summon->m_Events.AddEvent(new TrashJumpEvent(summon), summon->m_Events.CalculateTime(3s));
649 break;
650 case NPC_SIF:
652 break;
653 default:
654 break;
655 }
656
657 BossAI::JustSummoned(summon);
658 }
659
660 void UpdateAI(uint32 diff) override
661 {
662 if (!UpdateVictim())
663 return;
664
665 events.Update(diff);
666
668 return;
669
670 while (uint32 eventId = events.ExecuteEvent())
671 {
672 switch (eventId)
673 {
676 break;
679 sif->AI()->Talk(SAY_SIF_START);
680 break;
683 sif->CastSpell(me, SPELL_TOUCH_OF_DOMINION);
684 break;
687 events.Repeat(15s, 20s);
688 break;
689 case EVENT_CHARGE_ORB:
691 events.Repeat(15s, 20s);
692 break;
694 SummonWave();
695 events.Repeat(_orbSummoned ? 3s : 10s);
696 break;
697 case EVENT_JUMPDOWN:
698 if (_hardMode)
700 sif->AI()->DoAction(ACTION_START_HARD_MODE);
703 me->SetDisableGravity(false);
705 me->GetMotionMaster()->MoveJump(EVENT_JUMP, { 2134.8f, -263.056f, 419.983f }, {}, 5.0f);
709 break;
712 events.Repeat(15s, 20s);
713 break;
715 if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 100.0f, true))
717 events.Repeat(7s, 15s);
718 break;
721 controller->CastSpell(controller, SPELL_ACTIVATE_LIGHTNING_ORB_PERIODIC, true);
722 break;
726 break;
727 case EVENT_BERSERK:
729 {
730 Talk(SAY_WIPE);
733 }
734 else
735 {
738 }
739 break;
741 {
742 std::list<Creature*> triggers;
744 triggers.remove_if([](Creature* bunny)
745 {
746 if (HeightPositionCheck(false)(bunny))
747 return true;
748 return LightningFieldCenter.GetExactDist2dSq(bunny) > 1296.0f;
749 });
750
751 Milliseconds timer = 1s;
752 for (Creature* bunny : triggers)
753 bunny->m_Events.AddEvent(new LightningFieldEvent(bunny), bunny->m_Events.CalculateTime(timer += 100ms));
754
755 triggers.remove_if([](Creature* bunny)
756 {
757 return LightningFieldCenter.GetExactDist2dSq(bunny) < 576.0f;
758 });
759
760 triggers.sort([](Creature* a, Creature* b)
761 {
762 return a->GetPositionX() < b->GetPositionX();
763 });
764
765 for (auto itr = triggers.cbegin(); itr != triggers.cend();)
766 {
767 auto prev = itr++;
768 if (itr != triggers.cend())
769 (*prev)->CastSpell(*itr, SPELL_LIGHTNING_BEAM_CHANNEL);
770 }
771 break;
772 }
773 case EVENT_OUTRO_1:
775 if (_hardMode)
777 break;
778 case EVENT_OUTRO_2:
780 if (_hardMode)
782 sif->SetStandState(UNIT_STAND_STATE_DEAD);
783 break;
784 case EVENT_OUTRO_3:
786 break;
787 default:
788 break;
789 }
790
792 return;
793 }
794 }
795
796 void DoAction(int32 action) override
797 {
798 switch (action)
799 {
800 case ACTION_BERSERK:
802 return;
803
804 if (!_orbSummoned)
805 {
806 _orbSummoned = true;
808 }
809 return;
811 if (++_killedCount >= 6)
812 {
813 // Event starts
814 me->SetImmuneToPC(false);
816 }
817 break;
818 default:
819 break;
820 }
821 }
822
823 void GetTrashSpawnTriggers(std::list<Creature*>& triggerList, uint32 count = 1)
824 {
826 triggerList.remove_if([](Creature* bunny)
827 {
828 if (HeightPositionCheck(false)(bunny))
829 return true;
830 return ArenaCenter.GetExactDist2dSq(bunny) < 3025.0f;
831 });
832
833 if (triggerList.empty())
834 return;
835
836 if (count == 1)
837 {
839 triggerList.clear();
840 triggerList.push_back(bunny);
841 }
842 else
843 Trinity::Containers::RandomResize(triggerList, count);
844 }
845
847 {
848 switch (_waveType)
849 {
850 case 0:
851 {
852 // Dark Rune Commoner
853 std::list<Creature*> triggers;
854 GetTrashSpawnTriggers(triggers, urand(5, 6));
855
856 for (Creature* bunny : triggers)
858
859 ++_waveType;
860 break;
861 }
862 case 1:
863 if (urand(0, 1))
864 {
865 // Dark Rune Champion or Dark Rune Evoker
866 std::list<Creature*> triggers;
867 GetTrashSpawnTriggers(triggers, urand(2, 4));
868
869 for (Creature* bunny : triggers)
871 }
872 else
873 {
874 // Dark Rune Warbringer
875 std::list<Creature*> triggers;
876 GetTrashSpawnTriggers(triggers);
877
878 for (Creature* bunny : triggers)
880 }
881 --_waveType;
882 break;
883 }
884 }
885
886 bool CanStartPhase2(Unit* actor) const
887 {
888 if (!actor || actor->GetTypeId() != TYPEID_PLAYER || !me->IsWithinDistInMap(actor, 10.0f))
889 return false;
890
893 return runicColossus && !runicColossus->IsAlive() && runeGiant && !runeGiant->IsAlive();
894 }
895
896 void DamageTaken(Unit* attacker, uint32& damage, DamageEffectType /*damageType*/, SpellInfo const* /*spellInfo = nullptr*/) override
897 {
898 if (events.IsInPhase(PHASE_1) && CanStartPhase2(attacker))
899 {
905
907 sif->InterruptNonMeleeSpells(false);
908
909 // Hard Mode
910 if (_hardMode)
912 }
913 else if (me->HealthBelowPctDamaged(1, damage))
914 {
915 damage = 0;
917 }
918 }
919
920 private:
928 };
929
930 CreatureAI* GetAI(Creature* creature) const override
931 {
932 return GetUlduarAI<boss_thorimAI>(creature);
933 }
934};
935
937{
939 {
940 _instance = creature->GetInstanceScript();
941 for (uint8 i = 0; i < ThorimTrashCount; ++i)
944
945 ASSERT(_info);
947 me->SetCanMelee(false); // DoSpellAttackIfReady
948 }
949
950 struct AIHelper
951 {
953 static uint32 GetTotalHeal(SpellInfo const* spellInfo, Unit const* caster)
954 {
955 SpellEffectValue heal = 0;
956 for (SpellEffectInfo const& spellEffectInfo : spellInfo->GetEffects())
957 {
958 if (spellEffectInfo.IsEffect(SPELL_EFFECT_HEAL))
959 heal += spellEffectInfo.CalcValue(caster);
960
961 if (spellEffectInfo.IsEffect(SPELL_EFFECT_APPLY_AURA) && spellEffectInfo.IsAura(SPELL_AURA_PERIODIC_HEAL))
962 heal += spellEffectInfo.GetPeriodicTickCount() * spellEffectInfo.CalcValue(caster);
963 }
964 return static_cast<uint32>(heal);
965 }
966
969 {
970 SpellEffectValue heal = 0;
972 for (AuraEffect const* aurEff : auras)
973 heal += aurEff->GetAmount() * aurEff->GetRemainingTicks();
974
975 return static_cast<uint32>(heal);
976 }
977
979 {
980 public:
981 MostHPMissingInRange(Unit const* referer, float range, uint32 hp, uint32 exclAura = 0, bool exclSelf = false)
982 : _referer(referer), _range(range), _hp(hp), _exclAura(exclAura), _exclSelf(exclSelf) { }
983
985 {
986 if (_exclSelf && u == _referer)
987 return false;
988
989 if (_exclAura && u->HasAura(_exclAura))
990 return false;
991
992 if ((u->GetHealth() + GetRemainingHealOn(u) + _hp) > u->GetMaxHealth())
993 return false;
994
995 uint32 missingHP = u->GetMaxHealth() - u->GetHealth();
996 if (u->IsAlive() && _referer->IsFriendlyTo(u) && _referer->IsWithinDistInMap(u, _range) && missingHP > _hp)
997 {
998 _hp = missingHP;
999 return true;
1000 }
1001
1002 return false;
1003 }
1004
1005 private:
1007 float _range;
1011 };
1012
1013 static Unit* GetUnitWithMostMissingHp(SpellInfo const* spellInfo, Unit* caster)
1014 {
1015 // use positive range, it's a healing spell
1016 float const range = spellInfo->GetMaxRange(true);
1017 uint32 const heal = GetTotalHeal(spellInfo, caster);
1018
1019 Unit* target = nullptr;
1020 Trinity::MostHPMissingInRange checker(caster, range, heal);
1021 Trinity::UnitLastSearcher<Trinity::MostHPMissingInRange> searcher(caster, target, checker);
1022 Cell::VisitGridObjects(caster, searcher, 60.0f);
1023
1024 return target;
1025 }
1026
1027 static Unit* GetHealTarget(SpellInfo const* spellInfo, Unit* caster)
1028 {
1029 Unit* healTarget = nullptr;
1030 if (!spellInfo->HasAttribute(SPELL_ATTR1_EXCLUDE_CASTER) && !roll_chance(caster->GetHealthPct()) && ((caster->GetHealth() + GetRemainingHealOn(caster) + GetTotalHeal(spellInfo, caster)) <= caster->GetMaxHealth()))
1031 healTarget = caster;
1032 else
1033 healTarget = GetUnitWithMostMissingHp(spellInfo, caster);
1034
1035 return healTarget;
1036 }
1037 };
1038
1039 bool UseAbility(uint32 spellId)
1040 {
1041 SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId, GetDifficulty());
1042 if (!spellInfo)
1043 return false;
1044
1045 Unit* target = nullptr;
1046 if (AIHelper::GetTotalHeal(spellInfo, me))
1047 target = AIHelper::GetHealTarget(spellInfo, me);
1048 else
1049 target = me->GetVictim();
1050
1051 if (!target)
1052 return false;
1053
1055 {
1056 bool allowMove = true;
1057 auto [minRange, maxRange] = spellInfo->GetMinMaxRange();
1058 if (me->IsInRange(target, minRange, maxRange))
1059 allowMove = false;
1060
1061 if (IsCombatMovementAllowed() != allowMove)
1062 {
1063 SetCombatMovement(allowMove);
1064
1065 // need relaunch movement
1067
1068 // give some time to allow reposition, try again in a second
1069 if (allowMove)
1070 return false;
1071 }
1072 }
1073
1074 DoCast(target, spellId);
1075 return true;
1076 }
1077
1078 void UpdateAI(uint32 diff) final override
1079 {
1080 if (!UpdateVictim())
1081 return;
1082
1083 _events.Update(diff);
1084
1086 return;
1087
1088 while (uint32 eventId = _events.ExecuteEvent())
1089 {
1090 ExecuteEvent(eventId);
1091
1093 return;
1094 }
1095
1098 }
1099
1100 virtual void ExecuteEvent(uint32 eventId) = 0;
1101
1102protected:
1105
1106 ThorimTrashInfo const* _info = nullptr;
1107};
1108
1110{
1111 public:
1112 npc_thorim_pre_phase() : CreatureScript("npc_thorim_pre_phase") { }
1113
1115 {
1117 {
1118 me->setActive(true); // prevent grid unload
1119 me->SetFarVisible(true);
1120 }
1121
1122 void Reset() override
1123 {
1124 _events.Reset();
1125 if (_info->PrimaryAbility)
1128 {
1131 else
1133 }
1134 if (_info->ThirdAbility)
1137 SetCombatMovement(false);
1138 }
1139
1140 void JustDied(Unit* /*killer*/) override
1141 {
1142 if (Creature* thorim = _instance->GetCreature(DATA_THORIM))
1143 thorim->AI()->DoAction(ACTION_INCREASE_PREADDS_COUNT);
1144 }
1145
1146 void DamageTaken(Unit* attacker, uint32& damage, DamageEffectType /*damageType*/, SpellInfo const* /*spellInfo = nullptr*/) override
1147 {
1148 // nullify spell damage
1149 if (!attacker || !attacker->GetAffectingPlayer())
1150 damage = 0;
1151 }
1152
1153 void ExecuteEvent(uint32 eventId) override
1154 {
1155 switch (eventId)
1156 {
1159 _events.ScheduleEvent(eventId, 15s, 20s);
1160 else
1161 _events.ScheduleEvent(eventId, 1s);
1162 break;
1165 {
1167 _events.ScheduleEvent(eventId, 2s);
1168 else
1169 _events.ScheduleEvent(eventId, 4s, 8s);
1170 }
1171 else
1172 _events.ScheduleEvent(eventId, 1s);
1173 break;
1176 _events.ScheduleEvent(eventId, 6s, 8s);
1177 else
1178 _events.ScheduleEvent(eventId, 1s);
1179 break;
1180 default:
1181 break;
1182 }
1183 }
1184 };
1185
1186 CreatureAI* GetAI(Creature* creature) const override
1187 {
1188 return GetUlduarAI<npc_thorim_pre_phaseAI>(creature);
1189 }
1190};
1191
1193{
1194 public:
1195 npc_thorim_arena_phase() : CreatureScript("npc_thorim_arena_phase") { }
1196
1198 {
1200 {
1201 switch (_info->Type)
1202 {
1203 case DARK_RUNE_CHAMPION:
1205 case DARK_RUNE_COMMONER:
1206 case DARK_RUNE_EVOKER:
1207 _isInArena = true;
1208 break;
1209 case DARK_RUNE_ACOLYTE:
1210 {
1213 break;
1214 }
1215 default:
1216 _isInArena = false;
1217 break;
1218 }
1219 }
1220
1221 bool CanAIAttack(Unit const* who) const override
1222 {
1223 // don't try to attack players in balcony
1224 if (_isInArena && HeightPositionCheck(true)(who))
1225 return false;
1226
1227 return IsInBoundary(who);
1228 }
1229
1242
1243 void JustEngagedWith(Unit* /*who*/) override
1244 {
1247
1248 if (!_isInArena)
1250 colossus->AI()->DoAction(ACTION_ACTIVATE_RUNIC_SMASH);
1251 }
1252
1253 void EnterEvadeMode(EvadeReason why) override
1254 {
1256 return;
1257
1258 // this should only happen if theres no alive player in the arena -> summon orb
1259 if (Creature* thorim = _instance->GetCreature(DATA_THORIM))
1260 thorim->AI()->DoAction(ACTION_BERSERK);
1262 }
1263
1264 void ExecuteEvent(uint32 eventId) override
1265 {
1266 switch (eventId)
1267 {
1270 _events.Repeat(3s, 6s);
1271 else
1272 _events.Repeat(1s);
1273 break;
1276 _events.Repeat(12s, 16s);
1277 else
1278 _events.Repeat(1s);
1279 break;
1282 _events.Repeat(6s, 8s);
1283 else
1284 _events.Repeat(1s);
1285 break;
1287 {
1288 Unit* referer = me;
1289 if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, [referer](Unit* unit){ return unit->GetTypeId() == TYPEID_PLAYER && unit->IsInRange(referer, 8.0f, 25.0f); }))
1290 DoCast(target, SPELL_CHARGE);
1291 _events.ScheduleEvent(eventId, 12s);
1292 break;
1293 }
1294 default:
1295 break;
1296 }
1297 }
1298
1299 private:
1301 };
1302
1303 CreatureAI* GetAI(Creature* creature) const override
1304 {
1305 return GetUlduarAI<npc_thorim_arena_phaseAI>(creature);
1306 }
1307};
1308
1310{
1312 {
1313 _instance = creature->GetInstanceScript();
1314
1316 }
1317
1318 bool CanAIAttack(Unit const* who) const final override
1319 {
1320 return IsInBoundary(who);
1321 }
1322
1323 void JustSummoned(Creature* summon) final override
1324 {
1325 _summons.Summon(summon);
1326 }
1327
1328 void SummonedCreatureDespawn(Creature* summon) final override
1329 {
1330 _summons.Despawn(summon);
1331 }
1332
1333 void DoAction(int32 action) override
1334 {
1335 if (action == ACTION_ACTIVATE_ADDS)
1336 {
1337 for (ObjectGuid const& guid : _summons)
1338 if (Creature* summon = ObjectAccessor::GetCreature(*me, guid))
1339 summon->SetImmuneToPC(false);
1340 }
1341 }
1342
1343protected:
1347};
1348
1350{
1351 public:
1352 npc_runic_colossus() : CreatureScript("npc_runic_colossus") { }
1353
1355 {
1357 {
1358 Initialize();
1359 }
1360
1362 {
1363 _runicActive = false;
1364 }
1365
1366 void Reset() override
1367 {
1368 Initialize();
1369 _events.Reset();
1370
1371 // close the Runic Door
1373
1374 // Spawn trashes
1376 for (SummonLocation const& s : ColossusAddLocations)
1378 }
1379
1380 void MoveInLineOfSight(Unit* /*who*/) override
1381 {
1382 // don't enter combat
1383 }
1384
1385 void DoAction(int32 action) override
1386 {
1388
1389 if (_runicActive)
1390 return;
1391
1392 if (action == ACTION_ACTIVATE_RUNIC_SMASH)
1393 {
1394 _runicActive = true;
1396 }
1397 }
1398
1399 void JustDied(Unit* /*killer*/) override
1400 {
1401 // open the Runic Door
1403
1404 if (Creature* thorim = _instance->GetCreature(DATA_THORIM))
1405 thorim->AI()->Talk(SAY_SPECIAL);
1406
1408 {
1409 giant->SetImmuneToPC(false);
1410 giant->AI()->DoAction(ACTION_ACTIVATE_ADDS);
1411 }
1412 }
1413
1414 void JustEngagedWith(Unit* /*who*/) override
1415 {
1417 _events.Reset();
1421 }
1422
1423 void UpdateAI(uint32 diff) override
1424 {
1425 _events.Update(diff);
1426
1428 return;
1429
1430 while (uint32 eventId = _events.ExecuteEvent())
1431 {
1432 switch (eventId)
1433 {
1437 _events.Repeat(35s, 45s);
1438 break;
1439 case EVENT_SMASH:
1441 _events.Repeat(15s, 18s);
1442 break;
1443 case EVENT_RUNIC_CHARGE:
1444 {
1445 Unit* referer = me;
1446 if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, [referer](Unit* unit){ return unit->GetTypeId() == TYPEID_PLAYER && unit->IsInRange(referer, 8.0f, 40.0f); }))
1447 DoCast(target, SPELL_RUNIC_CHARGE);
1448 _events.Repeat(20s);
1449 break;
1450 }
1451 case EVENT_RUNIC_SMASH:
1453 _events.Repeat(6s);
1454 break;
1455 default:
1456 break;
1457 }
1458
1460 return;
1461 }
1462
1463 if (!UpdateVictim())
1464 return;
1465 }
1466
1467 private:
1469 };
1470
1471 CreatureAI* GetAI(Creature* creature) const override
1472 {
1473 return GetUlduarAI<npc_runic_colossusAI>(creature);
1474 }
1475};
1476
1478{
1479 public:
1480 npc_ancient_rune_giant() : CreatureScript("npc_ancient_rune_giant") { }
1481
1483 {
1485
1486 void Reset() override
1487 {
1488 _events.Reset();
1489
1490 // close the Stone Door
1492
1493 // Spawn trashes
1495 for (SummonLocation const& s : GiantAddLocations)
1497 }
1498
1507
1508 void JustDied(Unit* /*killer*/) override
1509 {
1510 // opem the Stone Door
1512 }
1513
1514 void UpdateAI(uint32 diff) override
1515 {
1516 if (!UpdateVictim())
1517 return;
1518
1519 _events.Update(diff);
1520
1522 return;
1523
1524 while (uint32 eventId = _events.ExecuteEvent())
1525 {
1526 switch (eventId)
1527 {
1531 break;
1532 case EVENT_STOMP:
1534 _events.Repeat(10s, 12s);
1535 break;
1537 if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 60.0f, true))
1539 _events.Repeat(10s, 12s);
1540 break;
1541 default:
1542 break;
1543 }
1544
1546 return;
1547 }
1548 }
1549 };
1550
1551 CreatureAI* GetAI(Creature* creature) const override
1552 {
1553 return GetUlduarAI<npc_ancient_rune_giantAI>(creature);
1554 }
1555};
1556
1558{
1559 public:
1560 npc_sif() : CreatureScript("npc_sif") { }
1561
1562 struct npc_sifAI : public ScriptedAI
1563 {
1564 npc_sifAI(Creature* creature) : ScriptedAI(creature)
1565 {
1566 SetCombatMovement(false);
1567 _instance = creature->GetInstanceScript();
1568 }
1569
1570 void Reset() override
1571 {
1572 _events.Reset();
1573 }
1574
1575 void SpellHit(WorldObject* /*caster*/, SpellInfo const* spellInfo) override
1576 {
1577 if (spellInfo->Id == SPELL_STORMHAMMER_SIF)
1578 {
1581 me->AttackStop();
1582 }
1583 }
1584
1585 void DoAction(int32 action) override
1586 {
1587 if (action == ACTION_START_HARD_MODE)
1588 {
1592 _events.Reset();
1597 }
1598 }
1599
1600 void UpdateAI(uint32 diff) override
1601 {
1602 if (!UpdateVictim())
1603 return;
1604
1605 _events.Update(diff);
1606
1608 return;
1609
1610 while (uint32 eventId = _events.ExecuteEvent())
1611 {
1612 switch (eventId)
1613 {
1614 case EVENT_BLINK:
1615 if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 100.0f, true))
1616 DoCast(target, SPELL_BLINK);
1618 _events.Repeat(20s, 25s);
1619 return;
1620 case EVENT_FROST_NOVA:
1622 return;
1623 case EVENT_FROSTBOLT:
1624 if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 100.0f, true))
1625 DoCast(target, SPELL_FROSTBOLT);
1626 _events.Repeat(2s);
1627 return;
1630 _events.Repeat(15s, 20s);
1631 return;
1632 case EVENT_BLIZZARD:
1634 _events.Repeat(35s, 45s);
1635 return;
1636 default:
1637 break;
1638 }
1639
1641 return;
1642 }
1643
1644 // no melee attack
1645 }
1646
1647 private:
1650 };
1651
1652 CreatureAI* GetAI(Creature* creature) const override
1653 {
1654 return GetUlduarAI<npc_sifAI>(creature);
1655 }
1656};
1657
1658// 62576 - Blizzard
1659// 62602 - Blizzard
1661{
1662 public:
1663 spell_thorim_blizzard_effect() : SpellScriptLoader("spell_thorim_blizzard_effect") { }
1664
1666 {
1667 bool CheckAreaTarget(Unit* target)
1668 {
1670 if (target != GetOwner())
1671 {
1672 // check if not stacking aura already on target
1673 // this one prevents overriding auras periodically by 2 near area aura owners
1674 Unit::AuraApplicationMap const& auraMap = target->GetAppliedAuras();
1675 for (Unit::AuraApplicationMap::const_iterator iter = auraMap.begin(); iter != auraMap.end(); ++iter)
1676 {
1677 Aura const* aura = iter->second->GetBase();
1678 if (GetId() == aura->GetId() && GetOwner() != aura->GetOwner() )
1679 return false;
1680 }
1681 }
1682
1683 return true;
1684 }
1685
1690 };
1691
1692 AuraScript* GetAuraScript() const override
1693 {
1695 }
1696};
1697
1698// 62580, 62604 - Frostbolt Volley
1700{
1701 public:
1702 spell_thorim_frostbolt_volley() : SpellScriptLoader("spell_thorim_frostbolt_volley") { }
1703
1705 {
1706 void FilterTargets(std::list<WorldObject*>& targets)
1707 {
1708 targets.remove_if([](WorldObject* object) -> bool
1709 {
1710 if (object->GetTypeId() == TYPEID_PLAYER)
1711 return false;
1712
1713 if (Creature* creature = object->ToCreature())
1714 return !creature->IsPet();
1715
1716 return true;
1717 });
1718 }
1719
1724 };
1725
1726 SpellScript* GetSpellScript() const override
1727 {
1729 }
1730};
1731
1732// 62016 - Charge Orb
1734{
1735 public:
1736 spell_thorim_charge_orb() : SpellScriptLoader("spell_thorim_charge_orb") { }
1737
1739 {
1740 bool Validate(SpellInfo const* /*spellInfo*/) override
1741 {
1743 }
1744
1745 void FilterTargets(std::list<WorldObject*>& targets)
1746 {
1747 targets.remove_if(HeightPositionCheck(false));
1748
1749 if (targets.empty())
1750 return;
1751
1753 targets.clear();
1754 targets.push_back(target);
1755 }
1756
1758 {
1759 if (Unit* target = GetHitUnit())
1760 target->CastSpell(nullptr, SPELL_LIGHTNING_PILLAR_1, true);
1761 }
1762
1768 };
1769
1770 SpellScript* GetSpellScript() const override
1771 {
1773 }
1774};
1775
1776// 62466 - Lightning Charge
1778{
1779 public:
1780 spell_thorim_lightning_charge() : SpellScriptLoader("spell_thorim_lightning_charge") { }
1781
1783 {
1784 bool Validate(SpellInfo const* /*spellInfo*/) override
1785 {
1787 }
1788
1790 {
1792 if (Creature* creature = GetCaster()->ToCreature())
1793 creature->SetSpellFocus(GetSpell(), GetExplTargetWorldObject());
1794 }
1795
1800
1806 };
1807
1808 SpellScript* GetSpellScript() const override
1809 {
1811 }
1812};
1813
1814// 61934 - Leap
1816{
1817 public:
1818 spell_thorim_arena_leap() : SpellScriptLoader("spell_thorim_arena_leap") { }
1819
1821 {
1822 bool Load() override
1823 {
1824 return GetCaster()->GetTypeId() == TYPEID_UNIT;
1825 }
1826
1827 void HandleScript(SpellEffIndex /*effIndex*/)
1828 {
1829 if (Position const* pos = GetHitDest())
1831 }
1832
1837 };
1838
1839 SpellScript* GetSpellScript() const override
1840 {
1842 }
1843};
1844
1846{
1847 bool operator()(Position const* who) const
1848 {
1850 }
1851};
1852
1853// 62042 - Stormhammer
1855{
1856 public:
1857 spell_thorim_stormhammer() : SpellScriptLoader("spell_thorim_stormhammer") { }
1858
1860 {
1861 bool Validate(SpellInfo const* /*spellInfo*/) override
1862 {
1864 }
1865
1866 void FilterTargets(std::list<WorldObject*>& targets)
1867 {
1868 targets.remove_if([](WorldObject* target) -> bool { return HeightPositionCheck(true)(target) || OutOfArenaCheck()(target); });
1869
1870 if (targets.empty())
1871 {
1873 return;
1874 }
1875
1877 targets.clear();
1878 targets.push_back(target);
1879 }
1880
1881 void HandleScript(SpellEffIndex /*effIndex*/)
1882 {
1883 if (Unit* target = GetHitUnit())
1884 {
1885 target->CastSpell(target, SPELL_DEAFENING_THUNDER, true);
1886 target->CastSpell(GetCaster(), SPELL_STORMHAMMER_BOOMERANG, true);
1887 }
1888 }
1889
1891 {
1892 GetCaster()->SetVirtualItem(0, 0);
1893 }
1894
1901 };
1902
1903 SpellScript* GetSpellScript() const override
1904 {
1906 }
1907};
1908
1909// 64767 - Stormhammer
1911{
1912 public:
1913 spell_thorim_stormhammer_sif() : SpellScriptLoader("spell_thorim_stormhammer_sif") { }
1914
1916 {
1917 bool Validate(SpellInfo const* /*spellInfo*/) override
1918 {
1920 }
1921
1922 void HandleScript(SpellEffIndex /*effIndex*/)
1923 {
1924 if (Unit* target = GetHitUnit())
1925 {
1926 target->CastSpell(GetCaster(), SPELL_STORMHAMMER_BOOMERANG, true);
1927 target->CastSpell(target, SPELL_SIF_TRANSFORM, true);
1928 }
1929 }
1930
1932 {
1933 GetCaster()->SetVirtualItem(0, 0);
1934 }
1935
1941 };
1942
1943 SpellScript* GetSpellScript() const override
1944 {
1946 }
1947};
1948
1949// 64909 - Stormhammer
1951{
1952 public:
1953 spell_thorim_stormhammer_boomerang() : SpellScriptLoader("spell_thorim_stormhammer_boomerang") { }
1954
1956 {
1957 void RecoverHammer(SpellEffIndex /*effIndex*/)
1958 {
1959 if (Unit* target = GetHitUnit())
1960 target->SetVirtualItem(0, THORIM_WEAPON_DISPLAY_ID);
1961 }
1962
1967 };
1968
1969 SpellScript* GetSpellScript() const override
1970 {
1972 }
1973};
1974
1975// 62057, 62058 - Runic Smash
1977{
1978 public:
1979 spell_thorim_runic_smash() : SpellScriptLoader("spell_thorim_runic_smash") { }
1980
1982 {
1983 bool Validate(SpellInfo const* /*spellInfo*/) override
1984 {
1986 }
1987
1989 {
1990 PreventHitDefaultEffect(effIndex);
1991
1992 std::vector<Creature*> triggers;
1994 for (Creature* trigger : triggers)
1995 {
1996 Milliseconds time = Milliseconds(uint64(GetCaster()->GetExactDist(trigger) * 30.f));
1997 trigger->m_Events.AddEvent(new RunicSmashExplosionEvent(trigger), trigger->m_Events.CalculateTime(time));
1998 };
1999 }
2000
2005 };
2006
2007 SpellScript* GetSpellScript() const override
2008 {
2010 }
2011};
2012
2014{
2015 public:
2016 UpperOrbCheck() : _check(true) { }
2017
2018 bool operator() (Creature* target) const
2019 {
2020 return target->GetEntry() == NPC_THUNDER_ORB && _check(target);
2021 }
2022
2023 private:
2025};
2026
2027// 62184 - Activate Lightning Orb Periodic
2029{
2030 public:
2031 spell_thorim_activate_lightning_orb_periodic() : SpellScriptLoader("spell_thorim_activate_lightning_orb_periodic") { }
2032
2034 {
2036
2037 void PeriodicTick(AuraEffect const* /*aurEff*/)
2038 {
2040
2041 Unit* caster = GetCaster();
2042 std::vector<Creature*> triggers;
2043
2044 UpperOrbCheck check;
2045 Trinity::CreatureListSearcher<UpperOrbCheck> searcher(caster, triggers, check);
2046 Cell::VisitGridObjects(caster, searcher, 100.f);
2047
2048 if (!triggers.empty())
2049 {
2051 if (Creature* thorim = instance->GetCreature(DATA_THORIM))
2052 thorim->AI()->SetGUID(target->GetGUID(), DATA_CHARGED_PILLAR);
2053 }
2054 }
2055
2056 bool Load() override
2057 {
2058 if (Unit* caster = GetCaster())
2059 instance = caster->GetInstanceScript();
2060
2061 return instance != nullptr;
2062 }
2063
2068 };
2069
2074};
2075
2076// 62320 - Aura of Celerity
2094
2096{
2097 public:
2098 condition_thorim_arena_leap() : ConditionScript("condition_thorim_arena_leap"), _check(false) { }
2099
2100 bool OnConditionCheck(Condition const* condition, ConditionSourceInfo& sourceInfo) override
2101 {
2102 WorldObject const* target = sourceInfo.mConditionTargets[condition->ConditionTarget];
2103 InstanceScript* instance = target->GetInstanceScript();
2104
2105 if (!instance)
2106 return false;
2107
2108 return _check(target);
2109 }
2110
2111 private:
2113};
2114
First const & RAND(First const &first, Second const &second, Rest const &... rest)
std::vector< AreaBoundary const * > CreatureBoundary
Definition CreatureAI.h:39
uint8_t uint8
Definition Define.h:156
int32_t int32
Definition Define.h:150
uint64_t uint64
Definition Define.h:153
uint32_t uint32
Definition Define.h:154
std::chrono::milliseconds Milliseconds
Milliseconds shorthand typedef.
Definition Duration.h:24
#define ASSERT
Definition Errors.h:72
@ IN_PROGRESS
@ MOTION_PRIORITY_NORMAL
@ POINT_MOTION_TYPE
@ EFFECT_MOTION_TYPE
@ TEMPSUMMON_CORPSE_TIMED_DESPAWN
@ TYPEID_UNIT
Definition ObjectGuid.h:43
@ TYPEID_PLAYER
Definition ObjectGuid.h:44
Spells
Definition PlayerAI.cpp:32
bool roll_chance(float chance, PseudoRandomDistributionState &state)
Definition Random.cpp:131
uint32 urand(uint32 min, uint32 max)
Definition Random.cpp:43
#define RegisterSpellScript(spell_script)
Definition ScriptMgr.h:1383
SpellEffIndex
@ EFFECT_0
@ EFFECT_2
@ SPELL_EFFECT_DUMMY
@ SPELL_EFFECT_SCRIPT_EFFECT
@ SPELL_EFFECT_HEAL
@ SPELL_EFFECT_TRIGGER_SPELL
@ SPELL_EFFECT_JUMP_DEST
@ SPELL_EFFECT_APPLY_AURA
@ TARGET_UNIT_SRC_AREA_ENTRY
@ TARGET_UNIT_SRC_AREA_ENEMY
@ EVENT_JUMP
@ SPELL_ATTR1_EXCLUDE_CASTER
@ SPELL_FAILED_NO_VALID_TARGETS
@ GO_FLAG_NOT_SELECTABLE
@ FACTION_FRIENDLY
#define EFFECT_ALL
AuraEffectHandleModes
@ AURA_EFFECT_HANDLE_REAL
@ SPELL_AURA_PERIODIC_HEAL
@ SPELL_AURA_PERIODIC_TRIGGER_SPELL
@ SPELL_AURA_MOD_MELEE_RANGED_CASTING_HASTE
double SpellEffectValue
This is a double instead of float to be able to store full range of int32.
#define sSpellMgr
Definition SpellMgr.h:812
#define SpellEffectFn(F, I, N)
#define SpellObjectAreaTargetSelectFn(F, I, N)
#define AuraEffectPeriodicFn(F, I, N)
#define SpellCastFn(F)
#define SpellHitFn(F)
#define AuraCheckAreaTargetFn(F)
#define AuraEffectRemoveFn(F, I, N, M)
EvadeReason
@ REACT_PASSIVE
@ REACT_AGGRESSIVE
@ UNIT_STAND_STATE_DEAD
Definition UnitDefines.h:49
DamageEffectType
@ UNIT_FLAG_RENAME
@ CURRENT_GENERIC_SPELL
Definition Unit.h:610
@ UNIT_STATE_ROOT
Definition Unit.h:285
@ UNIT_STATE_CASTING
Definition Unit.h:290
SummonLocation const ColossusAddLocations[]
@ ACTION_PILLAR_CHARGED
@ ACTION_BERSERK
@ ACTION_INCREASE_PREADDS_COUNT
@ ACTION_START_HARD_MODE
@ ACTION_ACTIVATE_RUNIC_SMASH
@ ACTION_ACTIVATE_ADDS
@ SAY_DEATH
@ SAY_AGGRO_2
@ EMOTE_RUNIC_MIGHT
@ SAY_SIF_EVENT
@ SAY_WIPE
@ EMOTE_RUNIC_BARRIER
@ SAY_END_HARD_3
@ SAY_SIF_START
@ SAY_SPECIAL
@ SAY_END_NORMAL_3
@ SAY_END_NORMAL_2
@ SAY_END_NORMAL_1
@ SAY_SLAY
@ SAY_END_HARD_1
@ SAY_AGGRO_1
@ SAY_SIF_DESPAWN
@ SAY_BERSERK
@ SAY_JUMPDOWN
@ SAY_END_HARD_2
uint8 const ThorimTrashCount
@ SPELL_BLINK
@ SPELL_RUNE_DETONATION
@ SPELL_TOUCH_OF_DOMINION
@ SPELL_LIGHTNING_BEAM_CHANNEL
@ SPELL_SHEATH_OF_LIGHTNING
@ SPELL_LIGHTNING_PILLAR_2
@ SPELL_LIGHTNING_FIELD
@ SPELL_FROSTBOLT
@ SPELL_BERSERK_PHASE_2
@ SPELL_TOUCH_OF_DOMINION_TRIGGERED
@ SPELL_RUNIC_SMASH_LEFT
@ SPELL_UNBALANCING_STRIKE
@ SPELL_DEAFENING_THUNDER
@ SPELL_BERSERK_PHASE_1
@ SPELL_STORMHAMMER_SIF
@ SPELL_RUNIC_FORTIFICATION
@ SPELL_STORMHAMMER
@ SPELL_ACTIVATE_LIGHTNING_ORB_PERIODIC
@ SPELL_SUMMON_LIGHTNING_ORB
@ SPELL_CHARGE_ORB
@ SPELL_LIGHTNING_ORB_CHARGED
@ SPELL_BLIZZARD
@ SPELL_SMASH
@ SPELL_FROSTBOLT_VOLLEY
@ SPELL_LIGHTNING_PILLAR_1
@ SPELL_LIGHTNING_CHARGE
@ SPELL_SIF_TRANSFORM
@ SPELL_STORMHAMMER_BOOMERANG
@ SPELL_CHAIN_LIGHTNING
@ SPELL_FROSTNOVA
@ SPELL_LIGHTNING_DESTRUCTION
@ SPELL_LIGHTNING_RELEASE
@ SPELL_RUNIC_CHARGE
@ SPELL_RUNIC_SMASH_RIGHT
@ SPELL_CREDIT_KILL
@ SPELL_RUNIC_SMASH
@ SPELL_RUNIC_BARRIER
@ SPELL_CREDIT_SIFFED
@ PHASE_NULL
@ PHASE_2
@ PHASE_1
CreatureBoundary const ArenaBoundaries
CircleBoundary const InvertedBalconyCircle(LightningFieldCenter, 32.0f, true)
Position const ArenaCenter
void AddSC_boss_thorim()
Position const LightningFieldCenter
ThorimTrashInfo const StaticThorimTrashInfo[ThorimTrashCount]
PreAddSpells
@ SPELL_CIRCLE_OF_HEALING
61965
@ SPELL_RUNIC_STRIKE
@ SPELL_HAMSTRING
@ SPELL_CLEAVE
@ SPELL_GREATER_HEAL
@ SPELL_SHOOT
@ SPELL_CHARGE
@ SPELL_RUNIC_MENDING
@ SPELL_AURA_OF_CELERITY_VISUAL
@ SPELL_SWEEP
@ SPELL_BARBED_SHOT
@ SPELL_PUMMEL
@ SPELL_HEROIC_SWIPE
@ SPELL_RUNIC_LIGHTNING
@ SPELL_HOLY_SMITE
@ SPELL_MORTAL_STRIKE
@ SPELL_SUNDER_ARMOR
@ SPELL_RUNIC_SHIELD
@ SPELL_RENEW
@ SPELL_LEAP
@ SPELL_LOW_BLOW
@ SPELL_AURA_OF_CELERITY
@ SPELL_SHIELD_SMASH
@ SPELL_WHIRLING_TRIP
@ SPELL_DEVASTATE
@ SPELL_WHIRLWIND
@ SPELL_IMPALE
@ SPELL_ACID_BREATH
#define SPELL_STOMP
G3D::Vector3 const LightningOrbPath[]
TrashTypes
@ DARK_RUNE_EVOKER
@ MERCENARY_CAPTAIN
@ DARK_RUNE_ACOLYTE
@ IRON_RING_GUARD
@ DARK_RUNE_CHAMPION
@ BEHEMOTH
@ DARK_RUNE_COMMONER
@ MERCENARY_SOLDIER
@ IRON_HONOR_GUARD
@ DARK_RUNE_WARBRINGER
CircleBoundary const ArenaFloorCircle(ArenaCenter, 45.4f)
DisplayIds
@ THORIM_WEAPON_DISPLAY_ID
SummonLocation const GiantAddLocations[]
Position const SifSpawnPosition
@ DATA_CHARGED_PILLAR
@ EVENT_CHAIN_LIGHTNING
@ EVENT_BLINK
@ EVENT_ACTIVATE_LIGHTNING_FIELD
@ EVENT_CHARGE_ORB
@ EVENT_RUNIC_BARRIER
@ EVENT_OUTRO_2
@ EVENT_OUTRO_3
@ EVENT_JUMPDOWN
@ EVENT_FROSTBOLT_VOLLEY
@ EVENT_SAY_SIF_START
@ EVENT_RUNIC_FORTIFICATION
@ EVENT_ABILITY_CHARGE
@ EVENT_SMASH
@ EVENT_RUNE_DETONATION
@ EVENT_SECONDARY_ABILITY
@ EVENT_BERSERK
@ EVENT_SUMMON_ADDS
@ EVENT_START_PERIODIC_CHARGE
@ EVENT_RUNIC_CHARGE
@ EVENT_STOMP
@ EVENT_FROST_NOVA
@ EVENT_BLIZZARD
@ EVENT_OUTRO_1
@ EVENT_START_SIF_CHANNEL
@ EVENT_STORMHAMMER
@ EVENT_RUNIC_SMASH
@ EVENT_LIGHTNING_CHARGE
@ EVENT_THIRD_ABILITY
@ EVENT_PRIMARY_ABILITY
@ EVENT_FROSTBOLT
@ EVENT_SAY_AGGRO_2
@ EVENT_UNBALANCING_STRIKE
SummonLocation const PreAddLocations[]
Yells
void PreventDefaultAction()
HookList< EffectApplyHandler > AfterEffectRemove
HookList< EffectPeriodicHandler > OnEffectPeriodic
WorldObject * GetOwner() const
Unit * GetCaster() const
HookList< CheckAreaTargetHandler > DoCheckAreaTarget
Unit * GetTarget() const
uint32 GetId() const
WorldObject * GetOwner() const
Definition SpellAuras.h:195
uint32 GetId() const
Definition SpellAuras.h:183
ObjectGuid const & GetGUID() const
Definition BaseEntity.h:163
TypeID GetTypeId() const
Definition BaseEntity.h:166
InstanceScript *const instance
void JustEngagedWith(Unit *who) override
void JustSummoned(Creature *summon) override
void _DespawnAtEvade(Seconds delayToRespawn=30s, Creature *who=nullptr)
SummonList summons
EventMap events
void DoZoneInCombat()
Definition CreatureAI.h:169
static bool IsInBounds(CreatureBoundary const &boundary, Position const *who)
virtual void EnterEvadeMode(EvadeReason why=EvadeReason::Other)
bool IsInBoundary(Position const *who=nullptr) const
bool UpdateVictim()
void SetBoundary(CreatureBoundary const *boundary, bool negativeBoundaries=false)
Creature *const me
Definition CreatureAI.h:63
void SetHomePosition(float x, float y, float z, float o)
Definition Creature.h:394
void SetCanMelee(bool canMelee, bool fleeFromMelee=false)
void SetImmuneToPC(bool apply) override
Definition Creature.h:190
void SetReactState(ReactStates st)
Definition Creature.h:180
CreatureAI * AI() const
Definition Creature.h:235
void Update(uint32 time)
Definition EventMap.h:77
void Repeat(Milliseconds time)
Definition EventMap.cpp:67
EventId ExecuteEvent()
Definition EventMap.cpp:77
bool IsInPhase(PhaseIndex phase) const
Definition EventMap.h:246
void RescheduleEvent(EventId eventId, Milliseconds time, GroupIndex group=0u, PhaseIndex phase=0u)
Definition EventMap.cpp:56
void SetPhase(PhaseIndex phase)
Definition EventMap.cpp:32
void ScheduleEvent(EventId eventId, Milliseconds time, GroupIndex group=0u, PhaseIndex phase=0u)
Definition EventMap.cpp:40
void Reset()
Definition EventMap.cpp:25
void AddEvent(BasicEvent *event, Milliseconds e_time, bool set_addtime=true)
Milliseconds CalculateTime(Milliseconds t_offset) const
HeightPositionCheck(bool ret)
bool operator()(Position const *pos) const
static float const THORIM_BALCONY_Z_CHECK
Creature * GetCreature(uint32 type)
void HandleGameObject(ObjectGuid guid, bool open, GameObject *go=nullptr)
virtual ObjectGuid GetGuidData(uint32 type) const override
GameObject * GetGameObject(uint32 type)
bool Execute(uint64 eventTime, uint32) override
LightningFieldEvent(Creature *owner)
void LaunchMoveSpline(std::function< void(Movement::MoveSplineInit &init)> &&initializer, uint32 id=0, MovementGeneratorPriority priority=MOTION_PRIORITY_NORMAL, MovementGeneratorType type=EFFECT_MOTION_TYPE, Scripting::v2::ActionResultSetter< MovementStopReason > &&scriptResult={})
void MoveJump(uint32 id, Position const &pos, std::variant< std::monostate, float, Milliseconds > speedOrTime={}, Optional< float > minHeight={}, Optional< float > maxHeight={}, MovementFacingTarget const &facing={}, bool orientationFixed=false, bool unlimitedSpeed=false, Optional< float > speedMultiplier={}, JumpArrivalCastArgs const *arrivalCast=nullptr, Movement::SpellEffectExtraData const *spellEffectExtraData=nullptr, Scripting::v2::ActionResultSetter< MovementStopReason > &&scriptResult={})
void Clear()
Definition ObjectGuid.h:329
uint32 GetEntry() const
Definition Object.h:89
Creature * ToCreature()
Definition Object.h:121
RunicSmashExplosionEvent(Creature *owner)
bool Execute(uint64, uint32) override
SpellRange GetMinMaxRange(bool positive=false, WorldObject const *caster=nullptr, Spell *spell=nullptr) const
float GetMaxRange(bool positive=false, WorldObject const *caster=nullptr, Spell *spell=nullptr) const
uint32 const Id
Definition SpellInfo.h:328
bool HasAttribute(SpellAttr0 attribute) const
Definition SpellInfo.h:456
std::vector< SpellEffectInfo > const & GetEffects() const
Definition SpellInfo.h:589
static bool ValidateSpellInfo(std::initializer_list< uint32 > spellIds)
HookList< CastHandler > AfterCast
WorldLocation * GetHitDest() const
Unit * GetCaster() const
HookList< HitHandler > AfterHit
void PreventHitDefaultEffect(SpellEffIndex effIndex)
Unit * GetHitUnit() const
HookList< EffectHandler > OnEffectHitTarget
HookList< CastHandler > BeforeCast
Spell * GetSpell() const
void FinishCast(SpellCastResult result, int32 *param1=nullptr, int32 *param2=nullptr)
WorldObject * GetExplTargetWorldObject() const
HookList< EffectHandler > OnEffectLaunch
SpellInfo const * GetSpellInfo() const
HookList< ObjectAreaTargetSelectHandler > OnObjectAreaTargetSelect
void Despawn(Creature const *summon)
void Summon(Creature const *summon)
bool Execute(uint64 eventTime, uint32) override
TrashJumpEvent(Creature *owner)
Creature * _owner
bool DoSpellAttackIfReady(uint32 spellId)
Definition UnitAI.cpp:53
SpellCastResult DoCastVictim(uint32 spellId, CastSpellExtraArgs const &args={})
Definition UnitAI.cpp:172
Unit * SelectTarget(SelectTargetMethod targetType, uint32 offset=0, float dist=0.0f, bool playerOnly=false, bool withTank=true, int32 aura=0)
Definition UnitAI.cpp:71
SpellCastResult DoCastAOE(uint32 spellId, CastSpellExtraArgs const &args={})
Definition UnitAI.h:162
SpellCastResult DoCast(uint32 spellId)
Definition UnitAI.cpp:81
Definition Unit.h:647
AuraEffectList const & GetAuraEffectsByType(AuraType type) const
Definition Unit.h:1362
float GetHealthPct() const
Definition Unit.h:808
void SetVirtualItem(uint32 slot, uint32 itemId, uint16 appearanceModId=0, uint16 itemVisual=0)
Definition Unit.cpp:14521
void SetControlled(bool apply, UnitState state)
Definition Unit.cpp:11631
std::multimap< uint32, AuraApplication * > AuraApplicationMap
Definition Unit.h:657
void SetFaction(uint32 faction) override
Definition Unit.h:887
std::forward_list< AuraEffect * > AuraEffectList
Definition Unit.h:664
void InterruptNonMeleeSpells(bool withDelayed, uint32 spellid=0, bool withInstant=true)
Definition Unit.cpp:3253
MotionMaster * GetMotionMaster()
Definition Unit.h:1750
void InterruptSpell(CurrentSpellTypes spellType, bool withDelayed=true, bool withInstant=true, SpellCastResult result=SPELL_FAILED_INTERRUPTED, Optional< SpellCastResult > resultOther={}, ObjectGuid const &interrupter=ObjectGuid::Empty)
Definition Unit.cpp:3158
bool IsAlive() const
Definition Unit.h:1205
uint64 GetMaxHealth() const
Definition Unit.h:801
uint64 GetHealth() const
Definition Unit.h:800
bool HealthBelowPctDamaged(float pct, uint32 damage) const
Definition Unit.h:805
Unit * GetVictim() const
Definition Unit.h:738
bool HasUnitState(const uint32 f) const
Definition Unit.h:755
void RemoveAllAttackers()
Definition Unit.cpp:6085
bool HasAura(uint32 spellId, ObjectGuid casterGUID=ObjectGuid::Empty, ObjectGuid itemCasterGUID=ObjectGuid::Empty, uint32 reqEffMask=0) const
Definition Unit.cpp:4822
void RemoveAllAuras()
Definition Unit.cpp:4400
void SetUnitFlag(UnitFlags flags)
Definition Unit.h:861
AuraApplicationMap & GetAppliedAuras()
Definition Unit.h:1315
bool SetDisableGravity(bool disable, bool updateAnimTier=true, bool updatePlayHoverAnim=true)
Definition Unit.cpp:13440
bool AttackStop()
Definition Unit.cpp:5984
void RemoveAurasDueToSpell(uint32 spellId, ObjectGuid casterGUID=ObjectGuid::Empty, uint32 reqEffMask=0, AuraRemoveMode removeMode=AURA_REMOVE_BY_DEFAULT)
Definition Unit.cpp:3992
HeightPositionCheck const _check
bool operator()(Creature *target) const
InstanceScript * GetInstanceScript() const
Definition Object.cpp:394
void GetCreatureListWithEntryInGrid(Container &creatureContainer, uint32 entry, float maxSearchRange=250.0f) const
Definition Object.cpp:2663
SpellCastResult CastSpell(CastSpellTargetArg const &targets, uint32 spellId, CastSpellExtraArgs const &args={ })
Definition Object.cpp:2222
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:1403
void setActive(bool isActiveObject)
Definition Object.cpp:274
void SetFarVisible(bool on)
Definition Object.cpp:325
bool IsWithinDistInMap(WorldObject const *obj, float dist2compare, bool is3D=true, bool incOwnRadius=true, bool incTargetRadius=true) const
Definition Object.cpp:499
bool IsInRange(WorldObject const *obj, float minRange, float maxRange, bool is3D=true) const
Definition Object.cpp:590
EventProcessor m_Events
Definition Object.h:561
bool IsFriendlyTo(WorldObject const *target) const
Definition Object.cpp:2191
Player * GetAffectingPlayer() const
Definition Object.cpp:1635
CreatureAI * GetAI(Creature *creature) const override
HeightPositionCheck _check
bool OnConditionCheck(Condition const *condition, ConditionSourceInfo &sourceInfo) override
CreatureAI * GetAI(Creature *creature) const override
CreatureAI * GetAI(Creature *creature) const override
CreatureAI * GetAI(Creature *creature) const override
CreatureAI * GetAI(Creature *creature) const override
CreatureAI * GetAI(Creature *creature) const override
MostHPMissingInRange(Unit const *referer, float range, uint32 hp, uint32 exclAura=0, bool exclSelf=false)
AuraScript * GetAuraScript() const override
SpellScript * GetSpellScript() const override
bool Validate(SpellInfo const *) override
void AfterRemove(AuraEffect const *, AuraEffectHandleModes)
AuraScript * GetAuraScript() const override
void FilterTargets(std::list< WorldObject * > &targets)
SpellScript * GetSpellScript() const override
SpellScript * GetSpellScript() const override
SpellScript * GetSpellScript() const override
SpellScript * GetSpellScript() const override
void FilterTargets(std::list< WorldObject * > &targets)
SpellScript * GetSpellScript() const override
SpellScript * GetSpellScript() const override
SpellScript * GetSpellScript() const override
TC_GAME_API Creature * GetCreature(WorldObject const &u, ObjectGuid const &guid)
auto SelectRandomContainerElement(C const &container) -> std::add_const_t< decltype(*std::ranges::begin(container))> &
Definition Containers.h:110
void RandomResize(C &container, std::size_t requestedSize)
Definition Containers.h:67
static void VisitGridObjects(WorldObject const *obj, T &visitor, float radius)
Definition CellImpl.h:140
std::array< WorldObject const *, MAX_CONDITION_TARGETS > mConditionTargets
uint8 ConditionTarget
bool operator()(Position const *who) const
constexpr float GetPositionX() const
Definition Position.h:87
constexpr float GetExactDist2dSq(const float x, const float y) const
Definition Position.h:108
constexpr float GetPositionZ() const
Definition Position.h:89
void AttackStart(Unit *) override
== Triggered Actions Requested ==================
void SetCombatMovement(bool allowMovement)
bool IsCombatMovementAllowed() const
Difficulty GetDifficulty() const
void ResetThreatList(Unit *who=nullptr)
void DamageTaken(Unit *attacker, uint32 &damage, DamageEffectType, SpellInfo const *) override
void UpdateAI(uint32 diff) override
boss_thorimAI(Creature *creature)
void KilledUnit(Unit *who) override
void GetTrashSpawnTriggers(std::list< Creature * > &triggerList, uint32 count=1)
void EnterEvadeMode(EvadeReason) override
void SpellHitTarget(WorldObject *target, SpellInfo const *spellInfo) override
void MovementInform(uint32 type, uint32 id) override
void SetGUID(ObjectGuid const &guid, int32 id) override
bool CanStartPhase2(Unit *actor) const
void JustSummoned(Creature *summon) override
void JustEngagedWith(Unit *who) override
void SpellHit(WorldObject *, SpellInfo const *spellInfo) override
void DoAction(int32 action) override
void DoAction(int32 action) override
void SpellHit(WorldObject *, SpellInfo const *spellInfo) override
void DoAction(int32 action) override
void Reset() override
void UpdateAI(uint32 diff) override
npc_sifAI(Creature *creature)
InstanceScript * _instance
void EnterEvadeMode(EvadeReason why) override
bool CanAIAttack(Unit const *who) const override
void JustSummoned(Creature *summon) final override
npc_thorim_minibossAI(Creature *creature)
bool CanAIAttack(Unit const *who) const final override
void SummonedCreatureDespawn(Creature *summon) final override
void DoAction(int32 action) override
InstanceScript * _instance
void ExecuteEvent(uint32 eventId) override
void DamageTaken(Unit *attacker, uint32 &damage, DamageEffectType, SpellInfo const *) override
static uint32 GetRemainingHealOn(Unit *target)
returns remaining heal amount on given target
static Unit * GetUnitWithMostMissingHp(SpellInfo const *spellInfo, Unit *caster)
static Unit * GetHealTarget(SpellInfo const *spellInfo, Unit *caster)
static uint32 GetTotalHeal(SpellInfo const *spellInfo, Unit const *caster)
returns heal amount of the given spell including hots
npc_thorim_trashAI(Creature *creature)
void UpdateAI(uint32 diff) final override
InstanceScript * _instance
ThorimTrashInfo const * _info
virtual void ExecuteEvent(uint32 eventId)=0
bool UseAbility(uint32 spellId)
@ DATA_THORIM
Definition ulduar.h:45
@ DATA_THORIM_LEVER
Definition ulduar.h:456
@ DATA_RUNIC_DOOR
Definition ulduar.h:459
@ DATA_RUNE_GIANT
Definition ulduar.h:458
@ DATA_STONE_DOOR
Definition ulduar.h:460
@ DATA_SIF
Definition ulduar.h:455
@ DATA_THORIM_CONTROLLER
Definition ulduar.h:462
@ DATA_RUNIC_COLOSSUS
Definition ulduar.h:457
@ NPC_THORIM_EVENT_BUNNY
Definition ulduar.h:189
@ NPC_GOLEM_LEFT_HAND_BUNNY
Definition ulduar.h:192
@ NPC_IRON_RING_GUARD
Definition ulduar.h:182
@ NPC_DARK_RUNE_WARBRINGER
Definition ulduar.h:185
@ NPC_DARK_RUNE_ACOLYTE_PRE
Definition ulduar.h:179
@ NPC_DARK_RUNE_CHAMPION
Definition ulduar.h:184
@ NPC_MERCENARY_CAPTAIN_A
Definition ulduar.h:175
@ NPC_MERCENARY_SOLDIER_H
Definition ulduar.h:178
@ NPC_JORMUNGAR_BEHEMOTH
Definition ulduar.h:174
@ NPC_DARK_RUNE_ACOLYTE
Definition ulduar.h:188
@ NPC_THUNDER_ORB
Definition ulduar.h:194
@ NPC_IRON_HONOR_GUARD
Definition ulduar.h:183
@ NPC_DARK_RUNE_EVOKER
Definition ulduar.h:186
@ NPC_MERCENARY_CAPTAIN_H
Definition ulduar.h:176
@ NPC_SIF
Definition ulduar.h:193
@ NPC_MERCENARY_SOLDIER_A
Definition ulduar.h:177
@ NPC_GOLEM_RIGHT_HAND_BUNNY
Definition ulduar.h:191
@ NPC_DARK_RUNE_COMMONER
Definition ulduar.h:187
@ NPC_LIGHTNING_ORB
Definition ulduar.h:190