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
213
234
243
266
276
282
284{
285 { { 2149.68f, -263.477f, 419.679f, 3.120f }, NPC_JORMUNGAR_BEHEMOTH },
286 { { 2131.31f, -271.640f, 419.840f, 2.188f }, NPC_MERCENARY_CAPTAIN_A },
287 { { 2127.24f, -259.182f, 419.974f, 5.917f }, NPC_MERCENARY_SOLDIER_A },
288 { { 2123.32f, -254.770f, 419.840f, 6.170f }, NPC_MERCENARY_SOLDIER_A },
289 { { 2120.10f, -258.990f, 419.840f, 6.250f }, NPC_MERCENARY_SOLDIER_A },
290 { { 2129.09f, -277.142f, 419.756f, 1.222f }, NPC_DARK_RUNE_ACOLYTE_PRE }
291};
292
294{
295 { { 2218.38f, -297.50f, 412.18f, 1.030f }, NPC_IRON_RING_GUARD },
296 { { 2235.07f, -297.98f, 412.18f, 1.613f }, NPC_IRON_RING_GUARD },
297 { { 2235.26f, -338.34f, 412.18f, 1.589f }, NPC_IRON_RING_GUARD },
298 { { 2217.69f, -337.39f, 412.18f, 1.241f }, NPC_IRON_RING_GUARD },
299 { { 2227.58f, -308.30f, 412.18f, 1.591f }, NPC_DARK_RUNE_ACOLYTE },
300 { { 2227.47f, -345.37f, 412.18f, 1.566f }, NPC_DARK_RUNE_ACOLYTE }
301};
302
304{
305 { { 2198.05f, -428.77f, 419.95f, 6.056f }, NPC_IRON_HONOR_GUARD },
306 { { 2220.31f, -436.22f, 412.26f, 1.064f }, NPC_IRON_HONOR_GUARD },
307 { { 2158.88f, -441.73f, 438.25f, 0.127f }, NPC_IRON_HONOR_GUARD },
308 { { 2198.29f, -436.92f, 419.95f, 0.261f }, NPC_DARK_RUNE_ACOLYTE },
309 { { 2230.93f, -434.27f, 412.26f, 1.931f }, NPC_DARK_RUNE_ACOLYTE }
310};
311
312Position const SifSpawnPosition = { 2148.301f, -297.8453f, 438.3308f, 2.687807f };
313
315{
318
323
324G3D::Vector3 const LightningOrbPath[] =
325{
326 { 2134.889893f, -298.632996f, 438.247467f },
327 { 2134.570068f, -440.317993f, 438.247467f },
328 { 2167.820312f, -440.330261f, 438.247589f },
329 { 2213.394287f, -433.318298f, 412.665863f },
330 { 2227.766113f, -433.275818f, 412.177032f },
331 { 2227.551270f, -263.081085f, 412.176880f },
332 { 2202.208008f, -262.939270f, 412.168976f },
333 { 2182.310059f, -263.233093f, 414.739410f }
334};
335
336// used for trash jump calculation
337Position const ArenaCenter = { 2134.77f, -262.307f };
338
339// used for lightning field calculation
340Position const LightningFieldCenter = { 2135.178f, -321.122f };
341
344
350
352{
353 public:
354 HeightPositionCheck(bool ret) : _ret(ret) { }
355
356 bool operator()(Position const* pos) const
357 {
358 return (pos->GetPositionZ() > THORIM_BALCONY_Z_CHECK) == _ret;
359 }
360
361 private:
362 bool _ret;
363
364 static float const THORIM_BALCONY_Z_CHECK;
365};
367
369{
370 public:
372
373 bool Execute(uint64 /*eventTime*/, uint32 /*updateTime*/) override
374 {
376 return true;
377 }
378
379 private:
381};
382
384{
385 public:
386 TrashJumpEvent(Creature* owner) : _owner(owner), _stage(0) { }
387
388 bool Execute(uint64 eventTime, uint32 /*updateTime*/) override
389 {
390 switch (_stage)
391 {
392 case 0:
393 _owner->CastSpell(nullptr, SPELL_LEAP);
394 ++_stage;
395 _owner->m_Events.AddEvent(this, Milliseconds(eventTime) + 2s);
396 return false;
397 case 1:
401 return true;
402 default:
403 break;
404 }
405
406 return true;
407 }
408
409 private:
412};
413
415{
416 public:
418
419 bool Execute(uint64 eventTime, uint32 /*updateTime*/) override
420 {
421 if (InstanceScript* instance = _owner->GetInstanceScript())
422 {
423 if (instance->GetBossState(DATA_THORIM) == IN_PROGRESS)
424 {
426 _owner->m_Events.AddEvent(this, Milliseconds(eventTime) + 1s);
427 return false;
428 }
429 }
430
433 return true;
434 }
435
436 private:
438};
439
441{
442 public:
443 boss_thorim() : CreatureScript("boss_thorim") { }
444
445 struct boss_thorimAI : public BossAI
446 {
447 boss_thorimAI(Creature* creature) : BossAI(creature, DATA_THORIM)
448 {
449 _encounterFinished = false;
450 Initialize();
451 }
452
454 {
455 _killedCount = 0;
456 _waveType = 0;
457 _hardMode = true;
458 _orbSummoned = false;
460 }
461
462 void Reset() override
463 {
465 return;
466
467 SetBoundary(nullptr);
468 _Reset();
469 Initialize();
470
472 me->SetDisableGravity(true);
474 me->SetImmuneToPC(true);
475
477
478 // Respawn Mini Bosses
479 for (uint8 i = DATA_RUNIC_COLOSSUS; i <= DATA_RUNE_GIANT; ++i)
481 miniBoss->Respawn(true);
482
483 // Spawn Pre Phase Adds
484 for (SummonLocation const& s : PreAddLocations)
486
488 lever->SetFlag(GO_FLAG_NOT_SELECTABLE);
489
490 // Remove trigger auras
492 pillar->RemoveAllAuras();
493
495 controller->RemoveAllAuras();
496
498 }
499
500 void EnterEvadeMode(EvadeReason /*why*/) override
501 {
504 }
505
506 void SetGUID(ObjectGuid const& guid, int32 id) override
507 {
508 if (id == DATA_CHARGED_PILLAR)
509 {
510 _activePillarGUID = guid;
511
513 {
514 pillar->CastSpell(pillar, SPELL_LIGHTNING_ORB_CHARGED, true);
515 pillar->CastSpell(nullptr, SPELL_LIGHTNING_PILLAR_2);
517 }
518 }
519 }
520
521 void KilledUnit(Unit* who) override
522 {
523 if (who->GetTypeId() == TYPEID_PLAYER)
524 Talk(SAY_SLAY);
525 }
526
527 void SpellHit(WorldObject* /*caster*/, SpellInfo const* spellInfo) override
528 {
529 if (spellInfo->Id == SPELL_TOUCH_OF_DOMINION_TRIGGERED)
530 {
532 {
533 sif->AI()->Talk(SAY_SIF_DESPAWN);
534 sif->DespawnOrUnsummon(6s);
535 _hardMode = false;
536 }
537 }
538 }
539
540 void SpellHitTarget(WorldObject* target, SpellInfo const* spellInfo) override
541 {
542 if (target->GetTypeId() == TYPEID_PLAYER && spellInfo->Id == SPELL_LIGHTNING_RELEASE)
544 }
545
547 {
549 return;
550
551 _encounterFinished = true;
552
553 DoCastAOE(SPELL_CREDIT_KILL, true); // before change faction
554
558 me->AttackStop();
561
563 controller->RemoveAllAuras();
565 pillar->RemoveAllAuras();
566
567 if (_hardMode)
568 {
570 {
571 summons.Despawn(sif);
572 sif->DespawnOrUnsummon(10s);
573 }
574 }
575
576 _JustDied();
577
582
584 }
585
586 void MovementInform(uint32 type, uint32 id) override
587 {
588 if (type != EFFECT_MOTION_TYPE || id != EVENT_JUMP)
589 return;
590
593 }
594
595 void JustEngagedWith(Unit* who) override
596 {
599
601
605
610
612
613 if (Creature* runicColossus = instance->GetCreature(DATA_RUNIC_COLOSSUS))
614 {
615 runicColossus->SetImmuneToPC(false);
616 runicColossus->AI()->DoAction(ACTION_ACTIVATE_ADDS);
617 }
618
620 lever->RemoveFlag(GO_FLAG_NOT_SELECTABLE);
621
622 // Summon Sif
624 }
625
626 void JustSummoned(Creature* summon) override
627 {
628 switch (summon->GetEntry())
629 {
631 {
633 summon->CastSpell(summon, SPELL_LIGHTNING_DESTRUCTION, true);
634
635 std::function<void(Movement::MoveSplineInit&)> initializer = [](Movement::MoveSplineInit& init)
636 {
637 init.MovebyPath(LightningOrbPath);
638 };
639 summon->GetMotionMaster()->LaunchMoveSpline(std::move(initializer), 0, MOTION_PRIORITY_NORMAL, POINT_MOTION_TYPE);
640 break;
641 }
647 summon->m_Events.AddEvent(new TrashJumpEvent(summon), summon->m_Events.CalculateTime(3s));
648 break;
649 case NPC_SIF:
651 break;
652 default:
653 break;
654 }
655
656 BossAI::JustSummoned(summon);
657 }
658
659 void UpdateAI(uint32 diff) override
660 {
661 if (!UpdateVictim())
662 return;
663
664 events.Update(diff);
665
667 return;
668
669 while (uint32 eventId = events.ExecuteEvent())
670 {
671 switch (eventId)
672 {
675 break;
678 sif->AI()->Talk(SAY_SIF_START);
679 break;
682 sif->CastSpell(me, SPELL_TOUCH_OF_DOMINION);
683 break;
686 events.Repeat(15s, 20s);
687 break;
688 case EVENT_CHARGE_ORB:
690 events.Repeat(15s, 20s);
691 break;
693 SummonWave();
694 events.Repeat(_orbSummoned ? 3s : 10s);
695 break;
696 case EVENT_JUMPDOWN:
697 if (_hardMode)
699 sif->AI()->DoAction(ACTION_START_HARD_MODE);
702 me->SetDisableGravity(false);
704 me->GetMotionMaster()->MoveJump(EVENT_JUMP, { 2134.8f, -263.056f, 419.983f }, {}, 5.0f);
708 break;
711 events.Repeat(15s, 20s);
712 break;
714 if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 100.0f, true))
716 events.Repeat(7s, 15s);
717 break;
720 controller->CastSpell(controller, SPELL_ACTIVATE_LIGHTNING_ORB_PERIODIC, true);
721 break;
725 break;
726 case EVENT_BERSERK:
728 {
729 Talk(SAY_WIPE);
732 }
733 else
734 {
737 }
738 break;
740 {
741 std::list<Creature*> triggers;
743 triggers.remove_if([](Creature* bunny)
744 {
745 if (HeightPositionCheck(false)(bunny))
746 return true;
747 return LightningFieldCenter.GetExactDist2dSq(bunny) > 1296.0f;
748 });
749
750 Milliseconds timer = 1s;
751 for (Creature* bunny : triggers)
752 bunny->m_Events.AddEvent(new LightningFieldEvent(bunny), bunny->m_Events.CalculateTime(timer += 100ms));
753
754 triggers.remove_if([](Creature* bunny)
755 {
756 return LightningFieldCenter.GetExactDist2dSq(bunny) < 576.0f;
757 });
758
759 triggers.sort([](Creature* a, Creature* b)
760 {
761 return a->GetPositionX() < b->GetPositionX();
762 });
763
764 for (auto itr = triggers.cbegin(); itr != triggers.cend();)
765 {
766 auto prev = itr++;
767 if (itr != triggers.cend())
768 (*prev)->CastSpell(*itr, SPELL_LIGHTNING_BEAM_CHANNEL);
769 }
770 break;
771 }
772 case EVENT_OUTRO_1:
774 if (_hardMode)
776 break;
777 case EVENT_OUTRO_2:
779 if (_hardMode)
781 sif->SetStandState(UNIT_STAND_STATE_DEAD);
782 break;
783 case EVENT_OUTRO_3:
785 break;
786 default:
787 break;
788 }
789
791 return;
792 }
793 }
794
795 void DoAction(int32 action) override
796 {
797 switch (action)
798 {
799 case ACTION_BERSERK:
801 return;
802
803 if (!_orbSummoned)
804 {
805 _orbSummoned = true;
807 }
808 return;
810 if (++_killedCount >= 6)
811 {
812 // Event starts
813 me->SetImmuneToPC(false);
815 }
816 break;
817 default:
818 break;
819 }
820 }
821
822 void GetTrashSpawnTriggers(std::list<Creature*>& triggerList, uint32 count = 1)
823 {
825 triggerList.remove_if([](Creature* bunny)
826 {
827 if (HeightPositionCheck(false)(bunny))
828 return true;
829 return ArenaCenter.GetExactDist2dSq(bunny) < 3025.0f;
830 });
831
832 if (triggerList.empty())
833 return;
834
835 if (count == 1)
836 {
838 triggerList.clear();
839 triggerList.push_back(bunny);
840 }
841 else
842 Trinity::Containers::RandomResize(triggerList, count);
843 }
844
846 {
847 switch (_waveType)
848 {
849 case 0:
850 {
851 // Dark Rune Commoner
852 std::list<Creature*> triggers;
853 GetTrashSpawnTriggers(triggers, urand(5, 6));
854
855 for (Creature* bunny : triggers)
857
858 ++_waveType;
859 break;
860 }
861 case 1:
862 if (urand(0, 1))
863 {
864 // Dark Rune Champion or Dark Rune Evoker
865 std::list<Creature*> triggers;
866 GetTrashSpawnTriggers(triggers, urand(2, 4));
867
868 for (Creature* bunny : triggers)
870 }
871 else
872 {
873 // Dark Rune Warbringer
874 std::list<Creature*> triggers;
875 GetTrashSpawnTriggers(triggers);
876
877 for (Creature* bunny : triggers)
879 }
880 --_waveType;
881 break;
882 }
883 }
884
885 bool CanStartPhase2(Unit* actor) const
886 {
887 if (!actor || actor->GetTypeId() != TYPEID_PLAYER || !me->IsWithinDistInMap(actor, 10.0f))
888 return false;
889
892 return runicColossus && !runicColossus->IsAlive() && runeGiant && !runeGiant->IsAlive();
893 }
894
895 void DamageTaken(Unit* attacker, uint32& damage, DamageEffectType /*damageType*/, SpellInfo const* /*spellInfo = nullptr*/) override
896 {
897 if (events.IsInPhase(PHASE_1) && CanStartPhase2(attacker))
898 {
904
906 sif->InterruptNonMeleeSpells(false);
907
908 // Hard Mode
909 if (_hardMode)
911 }
912 else if (me->HealthBelowPctDamaged(1, damage))
913 {
914 damage = 0;
916 }
917 }
918
919 private:
927 };
928
929 CreatureAI* GetAI(Creature* creature) const override
930 {
931 return GetUlduarAI<boss_thorimAI>(creature);
932 }
933};
934
936{
938 {
939 _instance = creature->GetInstanceScript();
940 for (uint8 i = 0; i < ThorimTrashCount; ++i)
943
944 ASSERT(_info);
946 me->SetCanMelee(false); // DoSpellAttackIfReady
947 }
948
949 struct AIHelper
950 {
952 static uint32 GetTotalHeal(SpellInfo const* spellInfo, Unit const* caster)
953 {
954 SpellEffectValue heal = 0;
955 for (SpellEffectInfo const& spellEffectInfo : spellInfo->GetEffects())
956 {
957 if (spellEffectInfo.IsEffect(SPELL_EFFECT_HEAL))
958 heal += spellEffectInfo.CalcValue(caster);
959
960 if (spellEffectInfo.IsEffect(SPELL_EFFECT_APPLY_AURA) && spellEffectInfo.IsAura(SPELL_AURA_PERIODIC_HEAL))
961 heal += spellEffectInfo.GetPeriodicTickCount() * spellEffectInfo.CalcValue(caster);
962 }
963 return static_cast<uint32>(heal);
964 }
965
968 {
969 SpellEffectValue heal = 0;
971 for (AuraEffect const* aurEff : auras)
972 heal += aurEff->GetAmount() * aurEff->GetRemainingTicks();
973
974 return static_cast<uint32>(heal);
975 }
976
978 {
979 public:
980 MostHPMissingInRange(Unit const* referer, float range, uint32 hp, uint32 exclAura = 0, bool exclSelf = false)
981 : _referer(referer), _range(range), _hp(hp), _exclAura(exclAura), _exclSelf(exclSelf) { }
982
984 {
985 if (_exclSelf && u == _referer)
986 return false;
987
988 if (_exclAura && u->HasAura(_exclAura))
989 return false;
990
991 if ((u->GetHealth() + GetRemainingHealOn(u) + _hp) > u->GetMaxHealth())
992 return false;
993
994 uint32 missingHP = u->GetMaxHealth() - u->GetHealth();
995 if (u->IsAlive() && _referer->IsFriendlyTo(u) && _referer->IsWithinDistInMap(u, _range) && missingHP > _hp)
996 {
997 _hp = missingHP;
998 return true;
999 }
1000
1001 return false;
1002 }
1003
1004 private:
1006 float _range;
1010 };
1011
1012 static Unit* GetUnitWithMostMissingHp(SpellInfo const* spellInfo, Unit* caster)
1013 {
1014 // use positive range, it's a healing spell
1015 float const range = spellInfo->GetMaxRange(true);
1016 uint32 const heal = GetTotalHeal(spellInfo, caster);
1017
1018 Unit* target = nullptr;
1019 Trinity::MostHPMissingInRange checker(caster, range, heal);
1020 Trinity::UnitLastSearcher<Trinity::MostHPMissingInRange> searcher(caster, target, checker);
1021 Cell::VisitGridObjects(caster, searcher, 60.0f);
1022
1023 return target;
1024 }
1025
1026 static Unit* GetHealTarget(SpellInfo const* spellInfo, Unit* caster)
1027 {
1028 Unit* healTarget = nullptr;
1029 if (!spellInfo->HasAttribute(SPELL_ATTR1_EXCLUDE_CASTER) && !roll_chance(caster->GetHealthPct()) && ((caster->GetHealth() + GetRemainingHealOn(caster) + GetTotalHeal(spellInfo, caster)) <= caster->GetMaxHealth()))
1030 healTarget = caster;
1031 else
1032 healTarget = GetUnitWithMostMissingHp(spellInfo, caster);
1033
1034 return healTarget;
1035 }
1036 };
1037
1038 bool UseAbility(uint32 spellId)
1039 {
1040 SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId, GetDifficulty());
1041 if (!spellInfo)
1042 return false;
1043
1044 Unit* target = nullptr;
1045 if (AIHelper::GetTotalHeal(spellInfo, me))
1046 target = AIHelper::GetHealTarget(spellInfo, me);
1047 else
1048 target = me->GetVictim();
1049
1050 if (!target)
1051 return false;
1052
1054 {
1055 bool allowMove = true;
1056 auto [minRange, maxRange] = spellInfo->GetMinMaxRange();
1057 if (me->IsInRange(target, minRange, maxRange))
1058 allowMove = false;
1059
1060 if (IsCombatMovementAllowed() != allowMove)
1061 {
1062 SetCombatMovement(allowMove);
1063
1064 // need relaunch movement
1066
1067 // give some time to allow reposition, try again in a second
1068 if (allowMove)
1069 return false;
1070 }
1071 }
1072
1073 DoCast(target, spellId);
1074 return true;
1075 }
1076
1077 void UpdateAI(uint32 diff) final override
1078 {
1079 if (!UpdateVictim())
1080 return;
1081
1082 _events.Update(diff);
1083
1085 return;
1086
1087 while (uint32 eventId = _events.ExecuteEvent())
1088 {
1089 ExecuteEvent(eventId);
1090
1092 return;
1093 }
1094
1097 }
1098
1099 virtual void ExecuteEvent(uint32 eventId) = 0;
1100
1101protected:
1104
1105 ThorimTrashInfo const* _info = nullptr;
1106};
1107
1109{
1110 public:
1111 npc_thorim_pre_phase() : CreatureScript("npc_thorim_pre_phase") { }
1112
1114 {
1116 {
1117 me->setActive(true); // prevent grid unload
1118 me->SetFarVisible(true);
1119 }
1120
1121 void Reset() override
1122 {
1123 _events.Reset();
1124 if (_info->PrimaryAbility)
1127 {
1130 else
1132 }
1133 if (_info->ThirdAbility)
1136 SetCombatMovement(false);
1137 }
1138
1139 void JustDied(Unit* /*killer*/) override
1140 {
1141 if (Creature* thorim = _instance->GetCreature(DATA_THORIM))
1142 thorim->AI()->DoAction(ACTION_INCREASE_PREADDS_COUNT);
1143 }
1144
1145 void DamageTaken(Unit* attacker, uint32& damage, DamageEffectType /*damageType*/, SpellInfo const* /*spellInfo = nullptr*/) override
1146 {
1147 // nullify spell damage
1148 if (!attacker || !attacker->GetAffectingPlayer())
1149 damage = 0;
1150 }
1151
1152 void ExecuteEvent(uint32 eventId) override
1153 {
1154 switch (eventId)
1155 {
1158 _events.ScheduleEvent(eventId, 15s, 20s);
1159 else
1160 _events.ScheduleEvent(eventId, 1s);
1161 break;
1164 {
1166 _events.ScheduleEvent(eventId, 2s);
1167 else
1168 _events.ScheduleEvent(eventId, 4s, 8s);
1169 }
1170 else
1171 _events.ScheduleEvent(eventId, 1s);
1172 break;
1175 _events.ScheduleEvent(eventId, 6s, 8s);
1176 else
1177 _events.ScheduleEvent(eventId, 1s);
1178 break;
1179 default:
1180 break;
1181 }
1182 }
1183 };
1184
1185 CreatureAI* GetAI(Creature* creature) const override
1186 {
1187 return GetUlduarAI<npc_thorim_pre_phaseAI>(creature);
1188 }
1189};
1190
1192{
1193 public:
1194 npc_thorim_arena_phase() : CreatureScript("npc_thorim_arena_phase") { }
1195
1197 {
1199 {
1200 switch (_info->Type)
1201 {
1202 case DARK_RUNE_CHAMPION:
1204 case DARK_RUNE_COMMONER:
1205 case DARK_RUNE_EVOKER:
1206 _isInArena = true;
1207 break;
1208 case DARK_RUNE_ACOLYTE:
1209 {
1212 break;
1213 }
1214 default:
1215 _isInArena = false;
1216 break;
1217 }
1218 }
1219
1220 bool CanAIAttack(Unit const* who) const override
1221 {
1222 // don't try to attack players in balcony
1223 if (_isInArena && HeightPositionCheck(true)(who))
1224 return false;
1225
1226 return IsInBoundary(who);
1227 }
1228
1241
1242 void JustEngagedWith(Unit* /*who*/) override
1243 {
1246
1247 if (!_isInArena)
1249 colossus->AI()->DoAction(ACTION_ACTIVATE_RUNIC_SMASH);
1250 }
1251
1252 void EnterEvadeMode(EvadeReason why) override
1253 {
1255 return;
1256
1257 // this should only happen if theres no alive player in the arena -> summon orb
1258 if (Creature* thorim = _instance->GetCreature(DATA_THORIM))
1259 thorim->AI()->DoAction(ACTION_BERSERK);
1261 }
1262
1263 void ExecuteEvent(uint32 eventId) override
1264 {
1265 switch (eventId)
1266 {
1269 _events.Repeat(3s, 6s);
1270 else
1271 _events.Repeat(1s);
1272 break;
1275 _events.Repeat(12s, 16s);
1276 else
1277 _events.Repeat(1s);
1278 break;
1281 _events.Repeat(6s, 8s);
1282 else
1283 _events.Repeat(1s);
1284 break;
1286 {
1287 Unit* referer = me;
1288 if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, [referer](Unit* unit){ return unit->GetTypeId() == TYPEID_PLAYER && unit->IsInRange(referer, 8.0f, 25.0f); }))
1289 DoCast(target, SPELL_CHARGE);
1290 _events.ScheduleEvent(eventId, 12s);
1291 break;
1292 }
1293 default:
1294 break;
1295 }
1296 }
1297
1298 private:
1300 };
1301
1302 CreatureAI* GetAI(Creature* creature) const override
1303 {
1304 return GetUlduarAI<npc_thorim_arena_phaseAI>(creature);
1305 }
1306};
1307
1309{
1311 {
1312 _instance = creature->GetInstanceScript();
1313
1315 }
1316
1317 bool CanAIAttack(Unit const* who) const final override
1318 {
1319 return IsInBoundary(who);
1320 }
1321
1322 void JustSummoned(Creature* summon) final override
1323 {
1324 _summons.Summon(summon);
1325 }
1326
1327 void SummonedCreatureDespawn(Creature* summon) final override
1328 {
1329 _summons.Despawn(summon);
1330 }
1331
1332 void DoAction(int32 action) override
1333 {
1334 if (action == ACTION_ACTIVATE_ADDS)
1335 {
1336 for (ObjectGuid const& guid : _summons)
1337 if (Creature* summon = ObjectAccessor::GetCreature(*me, guid))
1338 summon->SetImmuneToPC(false);
1339 }
1340 }
1341
1342protected:
1346};
1347
1349{
1350 public:
1351 npc_runic_colossus() : CreatureScript("npc_runic_colossus") { }
1352
1354 {
1356 {
1357 Initialize();
1358 }
1359
1361 {
1362 _runicActive = false;
1363 }
1364
1365 void Reset() override
1366 {
1367 Initialize();
1368 _events.Reset();
1369
1370 // close the Runic Door
1372
1373 // Spawn trashes
1375 for (SummonLocation const& s : ColossusAddLocations)
1377 }
1378
1379 void MoveInLineOfSight(Unit* /*who*/) override
1380 {
1381 // don't enter combat
1382 }
1383
1384 void DoAction(int32 action) override
1385 {
1387
1388 if (_runicActive)
1389 return;
1390
1391 if (action == ACTION_ACTIVATE_RUNIC_SMASH)
1392 {
1393 _runicActive = true;
1395 }
1396 }
1397
1398 void JustDied(Unit* /*killer*/) override
1399 {
1400 // open the Runic Door
1402
1403 if (Creature* thorim = _instance->GetCreature(DATA_THORIM))
1404 thorim->AI()->Talk(SAY_SPECIAL);
1405
1407 {
1408 giant->SetImmuneToPC(false);
1409 giant->AI()->DoAction(ACTION_ACTIVATE_ADDS);
1410 }
1411 }
1412
1413 void JustEngagedWith(Unit* /*who*/) override
1414 {
1416 _events.Reset();
1420 }
1421
1422 void UpdateAI(uint32 diff) override
1423 {
1424 _events.Update(diff);
1425
1427 return;
1428
1429 while (uint32 eventId = _events.ExecuteEvent())
1430 {
1431 switch (eventId)
1432 {
1436 _events.Repeat(35s, 45s);
1437 break;
1438 case EVENT_SMASH:
1440 _events.Repeat(15s, 18s);
1441 break;
1442 case EVENT_RUNIC_CHARGE:
1443 {
1444 Unit* referer = me;
1445 if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, [referer](Unit* unit){ return unit->GetTypeId() == TYPEID_PLAYER && unit->IsInRange(referer, 8.0f, 40.0f); }))
1446 DoCast(target, SPELL_RUNIC_CHARGE);
1447 _events.Repeat(20s);
1448 break;
1449 }
1450 case EVENT_RUNIC_SMASH:
1452 _events.Repeat(6s);
1453 break;
1454 default:
1455 break;
1456 }
1457
1459 return;
1460 }
1461
1462 if (!UpdateVictim())
1463 return;
1464 }
1465
1466 private:
1468 };
1469
1470 CreatureAI* GetAI(Creature* creature) const override
1471 {
1472 return GetUlduarAI<npc_runic_colossusAI>(creature);
1473 }
1474};
1475
1477{
1478 public:
1479 npc_ancient_rune_giant() : CreatureScript("npc_ancient_rune_giant") { }
1480
1482 {
1484
1485 void Reset() override
1486 {
1487 _events.Reset();
1488
1489 // close the Stone Door
1491
1492 // Spawn trashes
1494 for (SummonLocation const& s : GiantAddLocations)
1496 }
1497
1506
1507 void JustDied(Unit* /*killer*/) override
1508 {
1509 // opem the Stone Door
1511 }
1512
1513 void UpdateAI(uint32 diff) override
1514 {
1515 if (!UpdateVictim())
1516 return;
1517
1518 _events.Update(diff);
1519
1521 return;
1522
1523 while (uint32 eventId = _events.ExecuteEvent())
1524 {
1525 switch (eventId)
1526 {
1530 break;
1531 case EVENT_STOMP:
1533 _events.Repeat(10s, 12s);
1534 break;
1536 if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 60.0f, true))
1538 _events.Repeat(10s, 12s);
1539 break;
1540 default:
1541 break;
1542 }
1543
1545 return;
1546 }
1547 }
1548 };
1549
1550 CreatureAI* GetAI(Creature* creature) const override
1551 {
1552 return GetUlduarAI<npc_ancient_rune_giantAI>(creature);
1553 }
1554};
1555
1557{
1558 public:
1559 npc_sif() : CreatureScript("npc_sif") { }
1560
1561 struct npc_sifAI : public ScriptedAI
1562 {
1563 npc_sifAI(Creature* creature) : ScriptedAI(creature)
1564 {
1565 SetCombatMovement(false);
1566 _instance = creature->GetInstanceScript();
1567 }
1568
1569 void Reset() override
1570 {
1571 _events.Reset();
1572 }
1573
1574 void SpellHit(WorldObject* /*caster*/, SpellInfo const* spellInfo) override
1575 {
1576 if (spellInfo->Id == SPELL_STORMHAMMER_SIF)
1577 {
1580 me->AttackStop();
1581 }
1582 }
1583
1584 void DoAction(int32 action) override
1585 {
1586 if (action == ACTION_START_HARD_MODE)
1587 {
1591 _events.Reset();
1596 }
1597 }
1598
1599 void UpdateAI(uint32 diff) override
1600 {
1601 if (!UpdateVictim())
1602 return;
1603
1604 _events.Update(diff);
1605
1607 return;
1608
1609 while (uint32 eventId = _events.ExecuteEvent())
1610 {
1611 switch (eventId)
1612 {
1613 case EVENT_BLINK:
1614 if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 100.0f, true))
1615 DoCast(target, SPELL_BLINK);
1617 _events.Repeat(20s, 25s);
1618 return;
1619 case EVENT_FROST_NOVA:
1621 return;
1622 case EVENT_FROSTBOLT:
1623 if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 100.0f, true))
1624 DoCast(target, SPELL_FROSTBOLT);
1625 _events.Repeat(2s);
1626 return;
1629 _events.Repeat(15s, 20s);
1630 return;
1631 case EVENT_BLIZZARD:
1633 _events.Repeat(35s, 45s);
1634 return;
1635 default:
1636 break;
1637 }
1638
1640 return;
1641 }
1642
1643 // no melee attack
1644 }
1645
1646 private:
1649 };
1650
1651 CreatureAI* GetAI(Creature* creature) const override
1652 {
1653 return GetUlduarAI<npc_sifAI>(creature);
1654 }
1655};
1656
1657// 62576 - Blizzard
1658// 62602 - Blizzard
1660{
1661 public:
1662 spell_thorim_blizzard_effect() : SpellScriptLoader("spell_thorim_blizzard_effect") { }
1663
1665 {
1666 bool CheckAreaTarget(Unit* target)
1667 {
1669 if (target != GetOwner())
1670 {
1671 // check if not stacking aura already on target
1672 // this one prevents overriding auras periodically by 2 near area aura owners
1673 Unit::AuraApplicationMap const& auraMap = target->GetAppliedAuras();
1674 for (Unit::AuraApplicationMap::const_iterator iter = auraMap.begin(); iter != auraMap.end(); ++iter)
1675 {
1676 Aura const* aura = iter->second->GetBase();
1677 if (GetId() == aura->GetId() && GetOwner() != aura->GetOwner() )
1678 return false;
1679 }
1680 }
1681
1682 return true;
1683 }
1684
1689 };
1690
1691 AuraScript* GetAuraScript() const override
1692 {
1694 }
1695};
1696
1697// 62580, 62604 - Frostbolt Volley
1699{
1700 public:
1701 spell_thorim_frostbolt_volley() : SpellScriptLoader("spell_thorim_frostbolt_volley") { }
1702
1704 {
1705 void FilterTargets(std::list<WorldObject*>& targets)
1706 {
1707 targets.remove_if([](WorldObject* object) -> bool
1708 {
1709 if (object->GetTypeId() == TYPEID_PLAYER)
1710 return false;
1711
1712 if (Creature* creature = object->ToCreature())
1713 return !creature->IsPet();
1714
1715 return true;
1716 });
1717 }
1718
1723 };
1724
1725 SpellScript* GetSpellScript() const override
1726 {
1728 }
1729};
1730
1731// 62016 - Charge Orb
1733{
1734 public:
1735 spell_thorim_charge_orb() : SpellScriptLoader("spell_thorim_charge_orb") { }
1736
1738 {
1739 bool Validate(SpellInfo const* /*spellInfo*/) override
1740 {
1742 }
1743
1744 void FilterTargets(std::list<WorldObject*>& targets)
1745 {
1746 targets.remove_if(HeightPositionCheck(false));
1747
1748 if (targets.empty())
1749 return;
1750
1752 targets.clear();
1753 targets.push_back(target);
1754 }
1755
1757 {
1758 if (Unit* target = GetHitUnit())
1759 target->CastSpell(nullptr, SPELL_LIGHTNING_PILLAR_1, true);
1760 }
1761
1767 };
1768
1769 SpellScript* GetSpellScript() const override
1770 {
1772 }
1773};
1774
1775// 62466 - Lightning Charge
1777{
1778 public:
1779 spell_thorim_lightning_charge() : SpellScriptLoader("spell_thorim_lightning_charge") { }
1780
1782 {
1783 bool Validate(SpellInfo const* /*spellInfo*/) override
1784 {
1786 }
1787
1789 {
1791 if (Creature* creature = GetCaster()->ToCreature())
1792 creature->SetSpellFocus(GetSpell(), GetExplTargetWorldObject());
1793 }
1794
1799
1805 };
1806
1807 SpellScript* GetSpellScript() const override
1808 {
1810 }
1811};
1812
1813// 61934 - Leap
1815{
1816 public:
1817 spell_thorim_arena_leap() : SpellScriptLoader("spell_thorim_arena_leap") { }
1818
1820 {
1821 bool Load() override
1822 {
1823 return GetCaster()->GetTypeId() == TYPEID_UNIT;
1824 }
1825
1826 void HandleScript(SpellEffIndex /*effIndex*/)
1827 {
1828 if (Position const* pos = GetHitDest())
1830 }
1831
1836 };
1837
1838 SpellScript* GetSpellScript() const override
1839 {
1841 }
1842};
1843
1845{
1846 bool operator()(Position const* who) const
1847 {
1849 }
1850};
1851
1852// 62042 - Stormhammer
1854{
1855 public:
1856 spell_thorim_stormhammer() : SpellScriptLoader("spell_thorim_stormhammer") { }
1857
1859 {
1860 bool Validate(SpellInfo const* /*spellInfo*/) override
1861 {
1863 }
1864
1865 void FilterTargets(std::list<WorldObject*>& targets)
1866 {
1867 targets.remove_if([](WorldObject* target) -> bool { return HeightPositionCheck(true)(target) || OutOfArenaCheck()(target); });
1868
1869 if (targets.empty())
1870 {
1872 return;
1873 }
1874
1876 targets.clear();
1877 targets.push_back(target);
1878 }
1879
1880 void HandleScript(SpellEffIndex /*effIndex*/)
1881 {
1882 if (Unit* target = GetHitUnit())
1883 {
1884 target->CastSpell(target, SPELL_DEAFENING_THUNDER, true);
1885 target->CastSpell(GetCaster(), SPELL_STORMHAMMER_BOOMERANG, true);
1886 }
1887 }
1888
1890 {
1891 GetCaster()->SetVirtualItem(0, 0);
1892 }
1893
1900 };
1901
1902 SpellScript* GetSpellScript() const override
1903 {
1905 }
1906};
1907
1908// 64767 - Stormhammer
1910{
1911 public:
1912 spell_thorim_stormhammer_sif() : SpellScriptLoader("spell_thorim_stormhammer_sif") { }
1913
1915 {
1916 bool Validate(SpellInfo const* /*spellInfo*/) override
1917 {
1919 }
1920
1921 void HandleScript(SpellEffIndex /*effIndex*/)
1922 {
1923 if (Unit* target = GetHitUnit())
1924 {
1925 target->CastSpell(GetCaster(), SPELL_STORMHAMMER_BOOMERANG, true);
1926 target->CastSpell(target, SPELL_SIF_TRANSFORM, true);
1927 }
1928 }
1929
1931 {
1932 GetCaster()->SetVirtualItem(0, 0);
1933 }
1934
1940 };
1941
1942 SpellScript* GetSpellScript() const override
1943 {
1945 }
1946};
1947
1948// 64909 - Stormhammer
1950{
1951 public:
1952 spell_thorim_stormhammer_boomerang() : SpellScriptLoader("spell_thorim_stormhammer_boomerang") { }
1953
1955 {
1956 void RecoverHammer(SpellEffIndex /*effIndex*/)
1957 {
1958 if (Unit* target = GetHitUnit())
1959 target->SetVirtualItem(0, THORIM_WEAPON_DISPLAY_ID);
1960 }
1961
1966 };
1967
1968 SpellScript* GetSpellScript() const override
1969 {
1971 }
1972};
1973
1974// 62057, 62058 - Runic Smash
1976{
1977 public:
1978 spell_thorim_runic_smash() : SpellScriptLoader("spell_thorim_runic_smash") { }
1979
1981 {
1982 bool Validate(SpellInfo const* /*spellInfo*/) override
1983 {
1985 }
1986
1988 {
1989 PreventHitDefaultEffect(effIndex);
1990
1991 std::vector<Creature*> triggers;
1993 for (Creature* trigger : triggers)
1994 {
1995 Milliseconds time = Milliseconds(uint64(GetCaster()->GetExactDist(trigger) * 30.f));
1996 trigger->m_Events.AddEvent(new RunicSmashExplosionEvent(trigger), trigger->m_Events.CalculateTime(time));
1997 };
1998 }
1999
2004 };
2005
2006 SpellScript* GetSpellScript() const override
2007 {
2009 }
2010};
2011
2013{
2014 public:
2015 UpperOrbCheck() : _check(true) { }
2016
2017 bool operator() (Creature* target) const
2018 {
2019 return target->GetEntry() == NPC_THUNDER_ORB && _check(target);
2020 }
2021
2022 private:
2024};
2025
2026// 62184 - Activate Lightning Orb Periodic
2028{
2029 public:
2030 spell_thorim_activate_lightning_orb_periodic() : SpellScriptLoader("spell_thorim_activate_lightning_orb_periodic") { }
2031
2033 {
2035
2036 void PeriodicTick(AuraEffect const* /*aurEff*/)
2037 {
2039
2040 Unit* caster = GetCaster();
2041 std::vector<Creature*> triggers;
2042
2043 UpperOrbCheck check;
2044 Trinity::CreatureListSearcher<UpperOrbCheck> searcher(caster, triggers, check);
2045 Cell::VisitGridObjects(caster, searcher, 100.f);
2046
2047 if (!triggers.empty())
2048 {
2050 if (Creature* thorim = instance->GetCreature(DATA_THORIM))
2051 thorim->AI()->SetGUID(target->GetGUID(), DATA_CHARGED_PILLAR);
2052 }
2053 }
2054
2055 bool Load() override
2056 {
2057 if (Unit* caster = GetCaster())
2058 instance = caster->GetInstanceScript();
2059
2060 return instance != nullptr;
2061 }
2062
2067 };
2068
2073};
2074
2076{
2077 public:
2078 condition_thorim_arena_leap() : ConditionScript("condition_thorim_arena_leap"), _check(false) { }
2079
2080 bool OnConditionCheck(Condition const* condition, ConditionSourceInfo& sourceInfo) override
2081 {
2082 WorldObject const* target = sourceInfo.mConditionTargets[condition->ConditionTarget];
2083 InstanceScript* instance = target->GetInstanceScript();
2084
2085 if (!instance)
2086 return false;
2087
2088 return _check(target);
2089 }
2090
2091 private:
2093};
2094
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:80
@ 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
uint32 urand(uint32 min, uint32 max)
Definition Random.cpp:42
bool roll_chance(T chance)
Definition Random.h:55
SpellEffIndex
@ EFFECT_0
@ EFFECT_2
@ TARGET_UNIT_SRC_AREA_ENTRY
@ TARGET_UNIT_SRC_AREA_ENEMY
@ EVENT_JUMP
@ SPELL_ATTR1_EXCLUDE_CASTER
@ SPELL_EFFECT_DUMMY
@ SPELL_EFFECT_SCRIPT_EFFECT
@ SPELL_EFFECT_HEAL
@ SPELL_EFFECT_TRIGGER_SPELL
@ SPELL_EFFECT_JUMP_DEST
@ SPELL_EFFECT_APPLY_AURA
@ SPELL_FAILED_NO_VALID_TARGETS
@ GO_FLAG_NOT_SELECTABLE
@ FACTION_FRIENDLY
#define EFFECT_ALL
@ SPELL_AURA_PERIODIC_HEAL
@ SPELL_AURA_PERIODIC_TRIGGER_SPELL
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)
EvadeReason
@ REACT_PASSIVE
@ REACT_AGGRESSIVE
@ UNIT_STAND_STATE_DEAD
Definition UnitDefines.h:49
DamageEffectType
@ UNIT_FLAG_RENAME
@ CURRENT_GENERIC_SPELL
Definition Unit.h:598
@ UNIT_STATE_ROOT
Definition Unit.h:271
@ UNIT_STATE_CASTING
Definition Unit.h:276
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_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< EffectPeriodicHandler > OnEffectPeriodic
WorldObject * GetOwner() const
Unit * GetCaster() const
HookList< CheckAreaTargetHandler > DoCheckAreaTarget
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:386
void SetCanMelee(bool canMelee, bool fleeFromMelee=false)
void SetImmuneToPC(bool apply) override
Definition Creature.h:184
void SetReactState(ReactStates st)
Definition Creature.h:174
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 SetPhase(uint8 phase)
Definition EventMap.cpp:32
void RescheduleEvent(uint32 eventId, Milliseconds time, uint32 group=0, uint8 phase=0)
Definition EventMap.cpp:56
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:587
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:61
SpellCastResult DoCastVictim(uint32 spellId, CastSpellExtraArgs const &args={})
Definition UnitAI.cpp:180
Unit * SelectTarget(SelectTargetMethod targetType, uint32 offset=0, float dist=0.0f, bool playerOnly=false, bool withTank=true, int32 aura=0)
Definition UnitAI.cpp:79
SpellCastResult DoCastAOE(uint32 spellId, CastSpellExtraArgs const &args={})
Definition UnitAI.h:162
SpellCastResult DoCast(uint32 spellId)
Definition UnitAI.cpp:89
Definition Unit.h:635
AuraEffectList const & GetAuraEffectsByType(AuraType type) const
Definition Unit.h:1342
float GetHealthPct() const
Definition Unit.h:796
void SetVirtualItem(uint32 slot, uint32 itemId, uint16 appearanceModId=0, uint16 itemVisual=0)
Definition Unit.cpp:14374
void SetControlled(bool apply, UnitState state)
Definition Unit.cpp:11545
std::multimap< uint32, AuraApplication * > AuraApplicationMap
Definition Unit.h:645
void SetFaction(uint32 faction) override
Definition Unit.h:872
std::forward_list< AuraEffect * > AuraEffectList
Definition Unit.h:652
void InterruptNonMeleeSpells(bool withDelayed, uint32 spellid=0, bool withInstant=true)
Definition Unit.cpp:3231
MotionMaster * GetMotionMaster()
Definition Unit.h:1723
bool IsAlive() const
Definition Unit.h:1185
bool SetDisableGravity(bool disable, bool updateAnimTier=true)
Definition Unit.cpp:13361
uint64 GetMaxHealth() const
Definition Unit.h:789
uint64 GetHealth() const
Definition Unit.h:788
bool HealthBelowPctDamaged(float pct, uint32 damage) const
Definition Unit.h:793
Unit * GetVictim() const
Definition Unit.h:726
bool HasUnitState(const uint32 f) const
Definition Unit.h:743
void RemoveAllAttackers()
Definition Unit.cpp:6066
bool HasAura(uint32 spellId, ObjectGuid casterGUID=ObjectGuid::Empty, ObjectGuid itemCasterGUID=ObjectGuid::Empty, uint32 reqEffMask=0) const
Definition Unit.cpp:4804
void RemoveAllAuras()
Definition Unit.cpp:4382
void SetUnitFlag(UnitFlags flags)
Definition Unit.h:846
AuraApplicationMap & GetAppliedAuras()
Definition Unit.h:1295
bool AttackStop()
Definition Unit.cpp:5965
void RemoveAurasDueToSpell(uint32 spellId, ObjectGuid casterGUID=ObjectGuid::Empty, uint32 reqEffMask=0, AuraRemoveMode removeMode=AURA_REMOVE_BY_DEFAULT)
Definition Unit.cpp:3974
void InterruptSpell(CurrentSpellTypes spellType, bool withDelayed=true, bool withInstant=true)
Definition Unit.cpp:3159
HeightPositionCheck const _check
bool operator()(Creature *target) const
InstanceScript * GetInstanceScript() const
Definition Object.cpp:396
void GetCreatureListWithEntryInGrid(Container &creatureContainer, uint32 entry, float maxSearchRange=250.0f) const
Definition Object.cpp:2658
SpellCastResult CastSpell(CastSpellTargetArg const &targets, uint32 spellId, CastSpellExtraArgs const &args={ })
Definition Object.cpp:2217
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:1398
void setActive(bool isActiveObject)
Definition Object.cpp:276
void SetFarVisible(bool on)
Definition Object.cpp:327
bool IsWithinDistInMap(WorldObject const *obj, float dist2compare, bool is3D=true, bool incOwnRadius=true, bool incTargetRadius=true) const
Definition Object.cpp:501
bool IsInRange(WorldObject const *obj, float minRange, float maxRange, bool is3D=true) const
Definition Object.cpp:592
EventProcessor m_Events
Definition Object.h:561
bool IsFriendlyTo(WorldObject const *target) const
Definition Object.cpp:2186
Player * GetAffectingPlayer() const
Definition Object.cpp:1630
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
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, bool dont_load=true)
Definition CellImpl.h:179
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:453
@ DATA_RUNIC_DOOR
Definition ulduar.h:456
@ DATA_RUNE_GIANT
Definition ulduar.h:455
@ DATA_STONE_DOOR
Definition ulduar.h:457
@ DATA_SIF
Definition ulduar.h:452
@ DATA_THORIM_CONTROLLER
Definition ulduar.h:459
@ DATA_RUNIC_COLOSSUS
Definition ulduar.h:454
@ 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