aboutsummaryrefslogtreecommitdiff
path: root/src/server/scripts/Northrend
diff options
context:
space:
mode:
authorShauren <shauren.trinity@gmail.com>2020-06-15 00:26:08 +0200
committerGitHub <noreply@github.com>2020-06-15 00:26:08 +0200
commitc715e635cf3feb50ac61d30659e614aaa2cc0c63 (patch)
tree5af30c80f8b1df3f60852adde4680951f6f55442 /src/server/scripts/Northrend
parentabff505a6eaf3e649be506c802b80eed3dd35f3a (diff)
parentcf88f0a9735f9ba010a4ae46e848c8f1a86e17fa (diff)
Merge pull request #24554 from funjoker/cherry-picks
Diffstat (limited to 'src/server/scripts/Northrend')
-rw-r--r--src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheChampion/boss_argent_challenge.cpp4
-rw-r--r--src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_anubarak_trial.cpp2
-rw-r--r--src/server/scripts/Northrend/IcecrownCitadel/boss_deathbringer_saurfang.cpp5
-rw-r--r--src/server/scripts/Northrend/IcecrownCitadel/boss_lady_deathwhisper.cpp102
-rw-r--r--src/server/scripts/Northrend/IcecrownCitadel/boss_valithria_dreamwalker.cpp2
-rw-r--r--src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel.cpp2
-rw-r--r--src/server/scripts/Northrend/Nexus/EyeOfEternity/boss_malygos.cpp6
-rw-r--r--src/server/scripts/Northrend/Nexus/Nexus/boss_magus_telestra.cpp2
-rw-r--r--src/server/scripts/Northrend/Nexus/Nexus/instance_nexus.cpp15
-rw-r--r--src/server/scripts/Northrend/Ulduar/Ulduar/boss_algalon_the_observer.cpp2
-rw-r--r--src/server/scripts/Northrend/Ulduar/Ulduar/boss_flame_leviathan.cpp2
-rw-r--r--src/server/scripts/Northrend/Ulduar/Ulduar/boss_freya.cpp22
-rw-r--r--src/server/scripts/Northrend/Ulduar/Ulduar/boss_hodir.cpp2
-rw-r--r--src/server/scripts/Northrend/Ulduar/Ulduar/boss_ignis.cpp2
-rw-r--r--src/server/scripts/Northrend/Ulduar/Ulduar/boss_mimiron.cpp2
-rw-r--r--src/server/scripts/Northrend/Ulduar/Ulduar/boss_thorim.cpp2117
-rw-r--r--src/server/scripts/Northrend/Ulduar/Ulduar/boss_yogg_saron.cpp4
-rw-r--r--src/server/scripts/Northrend/Ulduar/Ulduar/instance_ulduar.cpp61
-rw-r--r--src/server/scripts/Northrend/Ulduar/Ulduar/ulduar.h76
-rw-r--r--src/server/scripts/Northrend/VaultOfArchavon/boss_toravon.cpp2
-rw-r--r--src/server/scripts/Northrend/VioletHold/boss_ichoron.cpp9
-rw-r--r--src/server/scripts/Northrend/northrend_script_loader.cpp2
-rw-r--r--src/server/scripts/Northrend/zone_borean_tundra.cpp13
-rw-r--r--src/server/scripts/Northrend/zone_dragonblight.cpp6
-rw-r--r--src/server/scripts/Northrend/zone_grizzly_hills.cpp4
-rw-r--r--src/server/scripts/Northrend/zone_howling_fjord.cpp3
-rw-r--r--src/server/scripts/Northrend/zone_icecrown.cpp6
-rw-r--r--src/server/scripts/Northrend/zone_sholazar_basin.cpp2
-rw-r--r--src/server/scripts/Northrend/zone_storm_peaks.cpp2
-rw-r--r--src/server/scripts/Northrend/zone_zuldrak.cpp2
30 files changed, 2337 insertions, 144 deletions
diff --git a/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheChampion/boss_argent_challenge.cpp b/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheChampion/boss_argent_challenge.cpp
index 81dcf1846a6..895b9e15cc4 100644
--- a/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheChampion/boss_argent_challenge.cpp
+++ b/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheChampion/boss_argent_challenge.cpp
@@ -195,7 +195,7 @@ public:
{
damage = 0;
EnterEvadeMode();
- me->SetFaction(35);
+ me->SetFaction(FACTION_FRIENDLY);
bDone = true;
}
}
@@ -323,7 +323,7 @@ public:
{
damage = 0;
EnterEvadeMode();
- me->SetFaction(35);
+ me->SetFaction(FACTION_FRIENDLY);
bDone = true;
}
}
diff --git a/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_anubarak_trial.cpp b/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_anubarak_trial.cpp
index 868bb4e07c8..34af2872fdd 100644
--- a/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_anubarak_trial.cpp
+++ b/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_anubarak_trial.cpp
@@ -226,7 +226,7 @@ class boss_anubarak_trial : public CreatureScript
for (int i = 0; i < 10; i++)
if (Creature* scarab = me->SummonCreature(NPC_SCARAB, AnubarakLoc[1].GetPositionX()+urand(0, 50)-25, AnubarakLoc[1].GetPositionY()+urand(0, 50)-25, AnubarakLoc[1].GetPositionZ()))
{
- scarab->SetFaction(31);
+ scarab->SetFaction(FACTION_PREY);
scarab->GetMotionMaster()->MoveRandom(10);
}
}
diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_deathbringer_saurfang.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_deathbringer_saurfang.cpp
index d4976c75255..cdf2feee3e8 100644
--- a/src/server/scripts/Northrend/IcecrownCitadel/boss_deathbringer_saurfang.cpp
+++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_deathbringer_saurfang.cpp
@@ -204,7 +204,6 @@ enum Actions
enum Misc
{
DATA_MADE_A_MESS = 45374613, // 4537, 4613 are achievement IDs
- FACTION_SCOURGE = 974,
GOSSIP_MENU_MURADIN_BRONZEBEARD = 10934,
GOSSIP_MENU_HIGH_OVERLORD_SAURFANG = 10952
@@ -463,7 +462,7 @@ class boss_deathbringer_saurfang : public CreatureScript
{
case EVENT_INTRO_ALLIANCE_2:
me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
- me->SetFaction(FACTION_SCOURGE);
+ me->SetFaction(FACTION_UNDEAD_SCOURGE);
Talk(SAY_INTRO_ALLIANCE_2);
break;
case EVENT_INTRO_ALLIANCE_3:
@@ -476,7 +475,7 @@ class boss_deathbringer_saurfang : public CreatureScript
break;
case EVENT_INTRO_HORDE_2:
me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
- me->SetFaction(FACTION_SCOURGE);
+ me->SetFaction(FACTION_UNDEAD_SCOURGE);
Talk(SAY_INTRO_HORDE_2);
break;
case EVENT_INTRO_HORDE_4:
diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_lady_deathwhisper.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_lady_deathwhisper.cpp
index f4e8d4e10b1..638c600905f 100644
--- a/src/server/scripts/Northrend/IcecrownCitadel/boss_lady_deathwhisper.cpp
+++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_lady_deathwhisper.cpp
@@ -57,62 +57,68 @@ enum ScriptTexts
enum Spells
{
// Lady Deathwhisper
- SPELL_MANA_BARRIER = 70842,
- SPELL_SHADOW_BOLT = 71254,
- SPELL_DEATH_AND_DECAY = 71001,
- SPELL_DOMINATE_MIND = 71289,
- SPELL_DOMINATE_MIND_SCALE = 71290,
- SPELL_FROSTBOLT = 71420,
- SPELL_FROSTBOLT_VOLLEY = 72905,
- SPELL_TOUCH_OF_INSIGNIFICANCE = 71204,
- SPELL_SUMMON_SHADE = 71363,
- SPELL_SHADOW_CHANNELING = 43897,
- SPELL_DARK_TRANSFORMATION_T = 70895,
- SPELL_DARK_EMPOWERMENT_T = 70896,
- SPELL_DARK_MARTYRDOM_T = 70897,
- SPELL_SUMMON_SPIRITS = 72478,
+ SPELL_MANA_BARRIER = 70842,
+ SPELL_SHADOW_BOLT = 71254,
+ SPELL_DEATH_AND_DECAY = 71001,
+ SPELL_DOMINATE_MIND = 71289,
+ SPELL_DOMINATE_MIND_SCALE = 71290,
+ SPELL_FROSTBOLT = 71420,
+ SPELL_FROSTBOLT_VOLLEY = 72905,
+ SPELL_TOUCH_OF_INSIGNIFICANCE = 71204,
+ SPELL_SUMMON_SHADE = 71363,
+ SPELL_SHADOW_CHANNELING = 43897,
+ SPELL_DARK_TRANSFORMATION_T = 70895,
+ SPELL_DARK_EMPOWERMENT_T = 70896,
+ SPELL_DARK_MARTYRDOM_T = 70897,
+ SPELL_SUMMON_SPIRITS = 72478,
// Achievement
- SPELL_FULL_HOUSE = 72827, // does not exist in dbc but still can be used for criteria check
+ SPELL_FULL_HOUSE = 72827, // does not exist in dbc but still can be used for criteria check
// Both Adds
- SPELL_TELEPORT_VISUAL = 41236,
- SPELL_CLEAR_ALL_DEBUFFS = 34098,
- SPELL_FULL_HEAL = 17683,
- SPELL_PERMANENT_FEIGN_DEATH = 70628,
+ SPELL_TELEPORT_VISUAL = 41236,
+ SPELL_CLEAR_ALL_DEBUFFS = 34098,
+ SPELL_FULL_HEAL = 17683,
+ SPELL_PERMANENT_FEIGN_DEATH = 70628,
// Fanatics
- SPELL_DARK_TRANSFORMATION = 70900,
- SPELL_NECROTIC_STRIKE = 70659,
- SPELL_SHADOW_CLEAVE = 70670,
- SPELL_VAMPIRIC_MIGHT = 70674,
- SPELL_FANATIC_S_DETERMINATION = 71235,
- SPELL_DARK_MARTYRDOM_FANATIC = 71236,
+ SPELL_DARK_TRANSFORMATION = 70900,
+ SPELL_NECROTIC_STRIKE = 70659,
+ SPELL_SHADOW_CLEAVE = 70670,
+ SPELL_VAMPIRIC_MIGHT = 70674,
+ SPELL_FANATIC_S_DETERMINATION = 71235,
+ SPELL_DARK_MARTYRDOM_FANATIC = 71236,
+ SPELL_DARK_MARTYRDOM_FANATIC_25N = 72495,
+ SPELL_DARK_MARTYRDOM_FANATIC_10H = 72496,
+ SPELL_DARK_MARTYRDOM_FANATIC_25H = 72497,
// Adherents
- SPELL_DARK_EMPOWERMENT = 70901,
- SPELL_FROST_FEVER = 67767,
- SPELL_DEATHCHILL_BOLT = 70594,
- SPELL_DEATHCHILL_BLAST = 70906,
- SPELL_CURSE_OF_TORPOR = 71237,
- SPELL_SHROUD_OF_THE_OCCULT = 70768,
- SPELL_ADHERENT_S_DETERMINATION = 71234,
- SPELL_DARK_MARTYRDOM_ADHERENT = 70903,
+ SPELL_DARK_EMPOWERMENT = 70901,
+ SPELL_FROST_FEVER = 67767,
+ SPELL_DEATHCHILL_BOLT = 70594,
+ SPELL_DEATHCHILL_BLAST = 70906,
+ SPELL_CURSE_OF_TORPOR = 71237,
+ SPELL_SHROUD_OF_THE_OCCULT = 70768,
+ SPELL_ADHERENT_S_DETERMINATION = 71234,
+ SPELL_DARK_MARTYRDOM_ADHERENT = 70903,
+ SPELL_DARK_MARTYRDOM_ADHERENT_25N = 72498,
+ SPELL_DARK_MARTYRDOM_ADHERENT_10H = 72499,
+ SPELL_DARK_MARTYRDOM_ADHERENT_25H = 72500,
// Vengeful Shade
- SPELL_VENGEFUL_BLAST = 71544,
- SPELL_VENGEFUL_BLAST_PASSIVE = 71494,
- SPELL_VENGEFUL_BLAST_25N = 72010,
- SPELL_VENGEFUL_BLAST_10H = 72011,
- SPELL_VENGEFUL_BLAST_25H = 72012,
+ SPELL_VENGEFUL_BLAST = 71544,
+ SPELL_VENGEFUL_BLAST_PASSIVE = 71494,
+ SPELL_VENGEFUL_BLAST_25N = 72010,
+ SPELL_VENGEFUL_BLAST_10H = 72011,
+ SPELL_VENGEFUL_BLAST_25H = 72012,
// Darnavan
- SPELL_BLADESTORM = 65947,
- SPELL_CHARGE = 65927,
- SPELL_INTIMIDATING_SHOUT = 65930,
- SPELL_MORTAL_STRIKE = 65926,
- SPELL_SHATTERING_THROW = 65940,
- SPELL_SUNDER_ARMOR = 65936,
+ SPELL_BLADESTORM = 65947,
+ SPELL_CHARGE = 65927,
+ SPELL_INTIMIDATING_SHOUT = 65930,
+ SPELL_MORTAL_STRIKE = 65926,
+ SPELL_SHATTERING_THROW = 65940,
+ SPELL_SUNDER_ARMOR = 65936,
};
enum EventTypes
@@ -359,7 +365,7 @@ class boss_lady_deathwhisper : public CreatureScript
{
if (darnavan->IsAlive())
{
- darnavan->SetFaction(35);
+ darnavan->SetFaction(FACTION_FRIENDLY);
darnavan->CombatStop(true);
darnavan->GetMotionMaster()->MoveIdle();
darnavan->SetReactState(REACT_PASSIVE);
@@ -640,6 +646,9 @@ class npc_cult_fanatic : public CreatureScript
DoCastSelf(SPELL_DARK_MARTYRDOM_FANATIC);
break;
case SPELL_DARK_MARTYRDOM_FANATIC:
+ case SPELL_DARK_MARTYRDOM_FANATIC_25N:
+ case SPELL_DARK_MARTYRDOM_FANATIC_10H:
+ case SPELL_DARK_MARTYRDOM_FANATIC_25H:
_scheduler
.Schedule(Seconds(2), [this](TaskContext /*context*/)
{
@@ -739,6 +748,9 @@ class npc_cult_adherent : public CreatureScript
DoCastSelf(SPELL_DARK_MARTYRDOM_ADHERENT);
break;
case SPELL_DARK_MARTYRDOM_ADHERENT:
+ case SPELL_DARK_MARTYRDOM_ADHERENT_25N:
+ case SPELL_DARK_MARTYRDOM_ADHERENT_10H:
+ case SPELL_DARK_MARTYRDOM_ADHERENT_25H:
_scheduler
.Schedule(Seconds(2), [this](TaskContext /*context*/)
{
diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_valithria_dreamwalker.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_valithria_dreamwalker.cpp
index 0a7857225ad..97ba864358a 100644
--- a/src/server/scripts/Northrend/IcecrownCitadel/boss_valithria_dreamwalker.cpp
+++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_valithria_dreamwalker.cpp
@@ -264,7 +264,7 @@ class ValithriaDespawner : public BasicEvent
creature->SetRespawnDelay(10);
if (CreatureData const* data = creature->GetCreatureData())
- creature->SetPosition(data->posX, data->posY, data->posZ, data->orientation);
+ creature->UpdatePosition(data->posX, data->posY, data->posZ, data->orientation);
creature->DespawnOrUnsummon();
creature->SetCorpseDelay(corpseDelay);
diff --git a/src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel.cpp b/src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel.cpp
index 1e857d6164c..1462ebc1df1 100644
--- a/src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel.cpp
+++ b/src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel.cpp
@@ -358,7 +358,7 @@ class FrostwingGauntletRespawner
creature->SetRespawnDelay(2);
if (CreatureData const* data = creature->GetCreatureData())
- creature->SetPosition(data->posX, data->posY, data->posZ, data->orientation);
+ creature->UpdatePosition(data->posX, data->posY, data->posZ, data->orientation);
creature->DespawnOrUnsummon();
creature->SetCorpseDelay(corpseDelay);
diff --git a/src/server/scripts/Northrend/Nexus/EyeOfEternity/boss_malygos.cpp b/src/server/scripts/Northrend/Nexus/EyeOfEternity/boss_malygos.cpp
index 0aa77ef0eb2..cb85a35c884 100644
--- a/src/server/scripts/Northrend/Nexus/EyeOfEternity/boss_malygos.cpp
+++ b/src/server/scripts/Northrend/Nexus/EyeOfEternity/boss_malygos.cpp
@@ -175,12 +175,6 @@ enum Seats
SEAT_0 = 0
};
-enum Factions
-{
- // Needed for melee hover disks /when Nexus Lords die/
- FACTION_FRIENDLY = 35
-};
-
enum Actions
{
// Malygos
diff --git a/src/server/scripts/Northrend/Nexus/Nexus/boss_magus_telestra.cpp b/src/server/scripts/Northrend/Nexus/Nexus/boss_magus_telestra.cpp
index a75650dd6ba..48b1772ea95 100644
--- a/src/server/scripts/Northrend/Nexus/Nexus/boss_magus_telestra.cpp
+++ b/src/server/scripts/Northrend/Nexus/Nexus/boss_magus_telestra.cpp
@@ -261,7 +261,7 @@ public:
for (uint8 n = 0; n < 3; ++n)
time[n] = 0;
me->GetMotionMaster()->Clear();
- me->SetPosition(CenterOfRoom.GetPositionX(), CenterOfRoom.GetPositionY(), CenterOfRoom.GetPositionZ(), CenterOfRoom.GetOrientation());
+ me->UpdatePosition(CenterOfRoom.GetPositionX(), CenterOfRoom.GetPositionY(), CenterOfRoom.GetPositionZ(), CenterOfRoom.GetOrientation());
DoCast(me, SPELL_TELESTRA_BACK);
me->SetVisible(true);
if (Phase == 1)
diff --git a/src/server/scripts/Northrend/Nexus/Nexus/instance_nexus.cpp b/src/server/scripts/Northrend/Nexus/Nexus/instance_nexus.cpp
index 857ce9c32b4..5b3228e6413 100644
--- a/src/server/scripts/Northrend/Nexus/Nexus/instance_nexus.cpp
+++ b/src/server/scripts/Northrend/Nexus/Nexus/instance_nexus.cpp
@@ -23,11 +23,6 @@
#include "nexus.h"
#include "Player.h"
-enum Factions
-{
- FACTION_HOSTILE_FOR_ALL = 16
-};
-
class instance_nexus : public InstanceMapScript
{
public:
@@ -61,31 +56,31 @@ class instance_nexus : public InstanceMapScript
// Alliance npcs are spawned by default, if you are alliance, you will fight against horde npcs.
case NPC_ALLIANCE_BERSERKER:
if (ServerAllowsTwoSideGroups())
- creature->SetFaction(FACTION_HOSTILE_FOR_ALL);
+ creature->SetFaction(FACTION_MONSTER_2);
if (_teamInInstance == ALLIANCE)
creature->UpdateEntry(NPC_HORDE_BERSERKER);
break;
case NPC_ALLIANCE_RANGER:
if (ServerAllowsTwoSideGroups())
- creature->SetFaction(FACTION_HOSTILE_FOR_ALL);
+ creature->SetFaction(FACTION_MONSTER_2);
if (_teamInInstance == ALLIANCE)
creature->UpdateEntry(NPC_HORDE_RANGER);
break;
case NPC_ALLIANCE_CLERIC:
if (ServerAllowsTwoSideGroups())
- creature->SetFaction(FACTION_HOSTILE_FOR_ALL);
+ creature->SetFaction(FACTION_MONSTER_2);
if (_teamInInstance == ALLIANCE)
creature->UpdateEntry(NPC_HORDE_CLERIC);
break;
case NPC_ALLIANCE_COMMANDER:
if (ServerAllowsTwoSideGroups())
- creature->SetFaction(FACTION_HOSTILE_FOR_ALL);
+ creature->SetFaction(FACTION_MONSTER_2);
if (_teamInInstance == ALLIANCE)
creature->UpdateEntry(NPC_HORDE_COMMANDER);
break;
case NPC_COMMANDER_STOUTBEARD:
if (ServerAllowsTwoSideGroups())
- creature->SetFaction(FACTION_HOSTILE_FOR_ALL);
+ creature->SetFaction(FACTION_MONSTER_2);
if (_teamInInstance == ALLIANCE)
creature->UpdateEntry(NPC_COMMANDER_KOLURG);
break;
diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_algalon_the_observer.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_algalon_the_observer.cpp
index 3f622a72c83..201655985d1 100644
--- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_algalon_the_observer.cpp
+++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_algalon_the_observer.cpp
@@ -538,7 +538,7 @@ class boss_algalon_the_observer : public CreatureScript
damage = 0;
me->SetReactState(REACT_PASSIVE);
me->AttackStop();
- me->SetFaction(35);
+ me->SetFaction(FACTION_FRIENDLY);
me->AddUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
DoCast(me, SPELL_SELF_STUN);
events.Reset();
diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_flame_leviathan.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_flame_leviathan.cpp
index 09240de5649..004760c07ee 100644
--- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_flame_leviathan.cpp
+++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_flame_leviathan.cpp
@@ -780,7 +780,7 @@ class boss_flame_leviathan_safety_container : public CreatureScript
me->GetPosition(x, y, z);
z = me->GetMap()->GetHeight(me->GetPhaseShift(), x, y, z);
me->GetMotionMaster()->MovePoint(0, x, y, z);
- me->SetPosition(x, y, z, 0);
+ me->UpdatePosition(x, y, z, 0);
}
void UpdateAI(uint32 /*diff*/) override
diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_freya.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_freya.cpp
index 33e346e0c94..e0a73d09571 100644
--- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_freya.cpp
+++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_freya.cpp
@@ -226,7 +226,7 @@ class npc_iron_roots : public CreatureScript
SetCombatMovement(false);
me->ApplySpellImmune(0, IMMUNITY_ID, 49560, true); // Death Grip
- me->SetFaction(14);
+ me->SetFaction(FACTION_MONSTER);
me->SetReactState(REACT_PASSIVE);
}
@@ -270,6 +270,7 @@ class boss_freya : public CreatureScript
{
boss_freyaAI(Creature* creature) : BossAI(creature, BOSS_FREYA)
{
+ _encounterFinished = false;
Initialize();
memset(elementalTimer, 0, sizeof(elementalTimer));
diffTimer = 0;
@@ -312,9 +313,13 @@ class boss_freya : public CreatureScript
bool checkElementalAlive[2];
bool trioDefeated[2];
bool random[3];
+ bool _encounterFinished;
void Reset() override
{
+ if (_encounterFinished)
+ return;
+
_Reset();
Initialize();
}
@@ -595,6 +600,11 @@ class boss_freya : public CreatureScript
void JustDied(Unit* /*killer*/) override
{
+ if (_encounterFinished)
+ return;
+
+ _encounterFinished = true;
+
//! Freya's chest is dynamically spawned on death by different spells.
const uint32 summonSpell[2][4] =
{
@@ -606,15 +616,15 @@ class boss_freya : public CreatureScript
me->CastSpell((Unit*)NULL, summonSpell[me->GetMap()->GetDifficultyID() - DIFFICULTY_10_N][elderCount], true);
Talk(SAY_DEATH);
+
me->SetReactState(REACT_PASSIVE);
- _JustDied();
- me->RemoveAllAuras();
+ me->InterruptNonMeleeSpells(true);
+ me->RemoveAllAttackers();
me->AttackStop();
- me->SetFaction(35);
- me->DeleteThreatList();
- me->CombatStop(true);
+ me->SetFaction(FACTION_FRIENDLY);
me->DespawnOrUnsummon(7500);
me->CastSpell(me, SPELL_KNOCK_ON_WOOD_CREDIT, true);
+ _JustDied();
for (uint8 n = 0; n < 3; ++n)
{
diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_hodir.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_hodir.cpp
index a320994dc07..6635ece7ee9 100644
--- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_hodir.cpp
+++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_hodir.cpp
@@ -408,7 +408,7 @@ class boss_hodir : public CreatureScript
DoCastAOE(SPELL_KILL_CREDIT, true); /// need to be cast before changing boss faction
/// spell will target enemies only
- me->SetFaction(35);
+ me->SetFaction(FACTION_FRIENDLY);
me->DespawnOrUnsummon(10000);
_JustDied();
diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_ignis.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_ignis.cpp
index cfe2d3879d1..76acc9e7c45 100644
--- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_ignis.cpp
+++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_ignis.cpp
@@ -180,7 +180,7 @@ class boss_ignis : public CreatureScript
{
if (summon->GetEntry() == NPC_IRON_CONSTRUCT)
{
- summon->SetFaction(16);
+ summon->SetFaction(FACTION_MONSTER_2);
summon->SetReactState(REACT_AGGRESSIVE);
summon->RemoveUnitFlag(UnitFlags(UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_PACIFIED | UNIT_FLAG_STUNNED | UNIT_FLAG_IMMUNE_TO_PC));
summon->SetControlled(false, UNIT_STATE_ROOT);
diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_mimiron.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_mimiron.cpp
index 690a1ecdbfc..b23e296f0df 100644
--- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_mimiron.cpp
+++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_mimiron.cpp
@@ -638,7 +638,7 @@ class boss_mimiron : public CreatureScript
case EVENT_OUTTRO_1:
me->RemoveAurasDueToSpell(SPELL_SLEEP_VISUAL_1);
DoCast(me, SPELL_SLEEP_VISUAL_2);
- me->SetFaction(35);
+ me->SetFaction(FACTION_FRIENDLY);
events.ScheduleEvent(EVENT_OUTTRO_2, 3000);
break;
case EVENT_OUTTRO_2:
diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_thorim.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_thorim.cpp
index a833e13aeec..825718bd3ee 100644
--- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_thorim.cpp
+++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_thorim.cpp
@@ -15,27 +15,427 @@
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+#include "MoveSplineInit.h"
+#include "Player.h"
#include "ScriptMgr.h"
#include "ScriptedCreature.h"
+#include "SpellScript.h"
+#include "SpellAuraEffects.h"
+#include "TypeContainerVisitor.h"
+#include "CellImpl.h"
+#include "GridNotifiersImpl.h"
#include "ulduar.h"
+#include "SpellAuras.h"
+#include "SpellMgr.h"
+#include <G3D/Vector3.h>
+#include "AreaBoundary.h"
+#include "InstanceScript.h"
+#include "ObjectAccessor.h"
+#include "MotionMaster.h"
+
+enum Spells
+{
+ // Thorim
+ SPELL_SHEATH_OF_LIGHTNING = 62276,
+ SPELL_STORMHAMMER = 62042,
+ SPELL_STORMHAMMER_SIF = 64767,
+ SPELL_STORMHAMMER_BOOMERANG = 64909,
+ SPELL_DEAFENING_THUNDER = 62470,
+ SPELL_CHARGE_ORB = 62016,
+ SPELL_SUMMON_LIGHTNING_ORB = 62391,
+ SPELL_LIGHTNING_DESTRUCTION = 62393,
+ SPELL_TOUCH_OF_DOMINION = 62507,
+ SPELL_TOUCH_OF_DOMINION_TRIGGERED = 62565,
+ SPELL_CHAIN_LIGHTNING = 62131,
+ SPELL_LIGHTNING_ORB_CHARGED = 62186, // wrong duration, triggered spell should handle lightning release
+ SPELL_LIGHTNING_CHARGE = 62279,
+ SPELL_LIGHTNING_RELEASE = 62466,
+ SPELL_LIGHTNING_PILLAR_2 = 62976, // caster high position, target low position
+ SPELL_LIGHTNING_PILLAR_1 = 63238, // caster high position, target low position
+ SPELL_UNBALANCING_STRIKE = 62130,
+ SPELL_BERSERK_PHASE_1 = 62560,
+ SPELL_BERSERK_PHASE_2 = 62555,
+ SPELL_ACTIVATE_LIGHTNING_ORB_PERIODIC = 62184,
+
+ // Credits
+ SPELL_CREDIT_SIFFED = 64980,
+ SPELL_CREDIT_KILL = 64985,
+
+ // Lightning Field
+ SPELL_LIGHTNING_FIELD = 64972,
+ SPELL_LIGHTNING_BEAM_CHANNEL = 45537,
+
+ // Sif
+ SPELL_BLIZZARD = 62577,
+ SPELL_BLINK = 62578,
+ SPELL_FROSTBOLT_VOLLEY = 62580,
+ SPELL_FROSTBOLT = 62583,
+ SPELL_FROSTNOVA = 62597,
+ SPELL_SIF_TRANSFORM = 64778,
+
+ // Runic Colossus
+ SPELL_SMASH = 62339,
+ SPELL_RUNIC_BARRIER = 62338,
+ SPELL_RUNIC_CHARGE = 62613,
+ SPELL_RUNIC_SMASH = 62465,
+ SPELL_RUNIC_SMASH_RIGHT = 62057,
+ SPELL_RUNIC_SMASH_LEFT = 62058,
+
+ // Ancient Rune Giant
+ SPELL_RUNIC_FORTIFICATION = 62942,
+ SPELL_RUNE_DETONATION = 62526,
+ SPELL_STOMP = 62411
+};
+
+enum Phases
+{
+ PHASE_NULL,
+ PHASE_1,
+ PHASE_2
+};
+
+enum Events
+{
+ // Thorim
+ EVENT_SAY_AGGRO_2 = 1,
+ EVENT_SAY_SIF_START,
+ EVENT_START_SIF_CHANNEL,
+ EVENT_STORMHAMMER,
+ EVENT_CHARGE_ORB,
+ EVENT_SUMMON_ADDS,
+ EVENT_BERSERK,
+ EVENT_JUMPDOWN,
+ EVENT_UNBALANCING_STRIKE,
+ EVENT_CHAIN_LIGHTNING,
+ EVENT_START_PERIODIC_CHARGE,
+ EVENT_LIGHTNING_CHARGE,
+ EVENT_ACTIVATE_LIGHTNING_FIELD,
+ EVENT_OUTRO_1,
+ EVENT_OUTRO_2,
+ EVENT_OUTRO_3,
+
+ // Runic Colossus
+ EVENT_RUNIC_BARRIER,
+ EVENT_SMASH,
+ EVENT_RUNIC_CHARGE,
+ EVENT_RUNIC_SMASH,
+
+ // Ancient Rune Giant
+ EVENT_RUNIC_FORTIFICATION,
+ EVENT_STOMP,
+ EVENT_RUNE_DETONATION,
+
+ // Arena NPC
+ EVENT_PRIMARY_ABILITY,
+ EVENT_SECONDARY_ABILITY,
+ EVENT_THIRD_ABILITY,
+ EVENT_ABILITY_CHARGE,
+
+ // Sif
+ EVENT_BLINK,
+ EVENT_FROST_NOVA,
+ EVENT_FROSTBOLT,
+ EVENT_FROSTBOLT_VOLLEY,
+ EVENT_BLIZZARD
+};
enum Yells
{
- SAY_AGGRO = 0,
- SAY_SPECIAL_1 = 1,
- SAY_SPECIAL_2 = 2,
- SAY_SPECIAL_3 = 3,
- SAY_JUMPDOWN = 4,
- SAY_SLAY = 5,
- SAY_BERSERK = 6,
- SAY_WIPE = 7,
- SAY_DEATH = 8,
- SAY_END_NORMAL_1 = 9,
- SAY_END_NORMAL_2 = 10,
- SAY_END_NORMAL_3 = 11,
- SAY_END_HARD_1 = 12,
- SAY_END_HARD_2 = 13,
- SAY_END_HARD_3 = 14
+ // Thorim
+ SAY_AGGRO_1 = 0,
+ SAY_AGGRO_2 = 1,
+ SAY_SPECIAL = 2,
+ SAY_JUMPDOWN = 3,
+ SAY_SLAY = 4,
+ SAY_BERSERK = 5,
+ SAY_WIPE = 6,
+ SAY_DEATH = 7,
+ SAY_END_NORMAL_1 = 8,
+ SAY_END_NORMAL_2 = 9,
+ SAY_END_NORMAL_3 = 10,
+ SAY_END_HARD_1 = 11,
+ SAY_END_HARD_2 = 12,
+ SAY_END_HARD_3 = 13,
+
+ // Runic Colossus
+ EMOTE_RUNIC_BARRIER = 0,
+
+ // Ancient Rune Giant
+ EMOTE_RUNIC_MIGHT = 0,
+
+ // Sif
+ SAY_SIF_START = 0,
+ SAY_SIF_DESPAWN = 1,
+ SAY_SIF_EVENT = 2
+};
+
+enum PreAddSpells
+{
+ SPELL_ACID_BREATH = 62315,
+ SPELL_SWEEP = 62316,
+
+ SPELL_DEVASTATE = 62317,
+ SPELL_HEROIC_SWIPE = 62444,
+ SPELL_SUNDER_ARMOR = 57807,
+
+ SPELL_BARBED_SHOT = 62318,
+ SPELL_SHOOT = 16496,
+
+ SPELL_RENEW = 62333,
+ SPELL_GREATER_HEAL = 62334, /// 61965
+ SPELL_CIRCLE_OF_HEALING = 61964,
+
+ SPELL_HOLY_SMITE = 62335,
+
+ SPELL_LEAP = 61934,
+
+ SPELL_CHARGE = 32323,
+ SPELL_MORTAL_STRIKE = 35054,
+ SPELL_WHIRLWIND = 33500,
+
+ SPELL_LOW_BLOW = 62326,
+ SPELL_PUMMEL = 38313,
+
+ SPELL_RUNIC_LIGHTNING = 62327,
+ SPELL_RUNIC_MENDING = 62328,
+ SPELL_RUNIC_SHIELD = 62321,
+
+ SPELL_RUNIC_STRIKE = 62322,
+ SPELL_AURA_OF_CELERITY = 62320,
+
+ SPELL_IMPALE = 62331,
+ SPELL_WHIRLING_TRIP = 64151,
+
+ SPELL_CLEAVE = 42724,
+ SPELL_HAMSTRING = 48639,
+ SPELL_SHIELD_SMASH = 62332,
+};
+
+enum TrashTypes
+{
+ // Pre Phase Trash
+ BEHEMOTH,
+ MERCENARY_CAPTAIN,
+ MERCENARY_SOLDIER,
+
+ // Arena Phase Trash
+ DARK_RUNE_CHAMPION,
+ DARK_RUNE_WARBRINGER,
+ DARK_RUNE_COMMONER,
+ DARK_RUNE_EVOKER,
+
+ // Hall Way Trash
+ IRON_RING_GUARD,
+ IRON_HONOR_GUARD,
+
+ // Shared
+ DARK_RUNE_ACOLYTE
+};
+
+struct ThorimTrashInfo
+{
+ uint32 Type;
+ uint32 Entry;
+ uint32 PrimaryAbility;
+ uint32 SecondaryAbility;
+ uint32 ThirdAbility;
+};
+
+uint8 const ThorimTrashCount = 13;
+ThorimTrashInfo const StaticThorimTrashInfo[ThorimTrashCount] =
+{
+ // Pre Phase
+ { BEHEMOTH, NPC_JORMUNGAR_BEHEMOTH, SPELL_ACID_BREATH, SPELL_SWEEP, 0 },
+ { MERCENARY_CAPTAIN, NPC_MERCENARY_CAPTAIN_A, SPELL_DEVASTATE, SPELL_HEROIC_SWIPE, SPELL_SUNDER_ARMOR },
+ { MERCENARY_SOLDIER, NPC_MERCENARY_SOLDIER_A, SPELL_BARBED_SHOT, SPELL_SHOOT, 0 },
+ { DARK_RUNE_ACOLYTE, NPC_DARK_RUNE_ACOLYTE_PRE, SPELL_RENEW, SPELL_GREATER_HEAL, SPELL_CIRCLE_OF_HEALING },
+ { MERCENARY_CAPTAIN, NPC_MERCENARY_CAPTAIN_H, SPELL_DEVASTATE, SPELL_HEROIC_SWIPE, SPELL_SUNDER_ARMOR },
+ { MERCENARY_SOLDIER, NPC_MERCENARY_SOLDIER_H, SPELL_BARBED_SHOT, SPELL_SHOOT, 0 },
+
+ // Arena Phase
+ { DARK_RUNE_CHAMPION, NPC_DARK_RUNE_CHAMPION, SPELL_MORTAL_STRIKE, SPELL_WHIRLWIND, 0 },
+ { DARK_RUNE_WARBRINGER, NPC_DARK_RUNE_WARBRINGER, SPELL_RUNIC_STRIKE, 0, 0 },
+ { DARK_RUNE_EVOKER, NPC_DARK_RUNE_EVOKER, SPELL_RUNIC_LIGHTNING, SPELL_RUNIC_SHIELD, SPELL_RUNIC_MENDING },
+ { DARK_RUNE_COMMONER, NPC_DARK_RUNE_COMMONER, SPELL_LOW_BLOW, SPELL_PUMMEL, 0 },
+
+ // Hall Way
+ { IRON_RING_GUARD, NPC_IRON_RING_GUARD, SPELL_WHIRLING_TRIP, SPELL_IMPALE, 0 },
+ { IRON_HONOR_GUARD, NPC_IRON_HONOR_GUARD, SPELL_CLEAVE, SPELL_SHIELD_SMASH, 0 },
+ { DARK_RUNE_ACOLYTE, NPC_DARK_RUNE_ACOLYTE, SPELL_RENEW, SPELL_GREATER_HEAL, 0 }
+};
+
+enum Actions
+{
+ ACTION_INCREASE_PREADDS_COUNT,
+ ACTION_ACTIVATE_RUNIC_SMASH,
+ ACTION_ACTIVATE_ADDS,
+ ACTION_PILLAR_CHARGED,
+ ACTION_START_HARD_MODE,
+ ACTION_BERSERK
+};
+
+struct SummonLocation
+{
+ Position pos;
+ uint32 entry;
+};
+
+SummonLocation const PreAddLocations[] =
+{
+ { { 2149.68f, -263.477f, 419.679f, 3.120f }, NPC_JORMUNGAR_BEHEMOTH },
+ { { 2131.31f, -271.640f, 419.840f, 2.188f }, NPC_MERCENARY_CAPTAIN_A },
+ { { 2127.24f, -259.182f, 419.974f, 5.917f }, NPC_MERCENARY_SOLDIER_A },
+ { { 2123.32f, -254.770f, 419.840f, 6.170f }, NPC_MERCENARY_SOLDIER_A },
+ { { 2120.10f, -258.990f, 419.840f, 6.250f }, NPC_MERCENARY_SOLDIER_A },
+ { { 2129.09f, -277.142f, 419.756f, 1.222f }, NPC_DARK_RUNE_ACOLYTE_PRE }
+};
+
+SummonLocation const ColossusAddLocations[] =
+{
+ { { 2218.38f, -297.50f, 412.18f, 1.030f }, NPC_IRON_RING_GUARD },
+ { { 2235.07f, -297.98f, 412.18f, 1.613f }, NPC_IRON_RING_GUARD },
+ { { 2235.26f, -338.34f, 412.18f, 1.589f }, NPC_IRON_RING_GUARD },
+ { { 2217.69f, -337.39f, 412.18f, 1.241f }, NPC_IRON_RING_GUARD },
+ { { 2227.58f, -308.30f, 412.18f, 1.591f }, NPC_DARK_RUNE_ACOLYTE },
+ { { 2227.47f, -345.37f, 412.18f, 1.566f }, NPC_DARK_RUNE_ACOLYTE }
+};
+
+SummonLocation const GiantAddLocations[] =
+{
+ { { 2198.05f, -428.77f, 419.95f, 6.056f }, NPC_IRON_HONOR_GUARD },
+ { { 2220.31f, -436.22f, 412.26f, 1.064f }, NPC_IRON_HONOR_GUARD },
+ { { 2158.88f, -441.73f, 438.25f, 0.127f }, NPC_IRON_HONOR_GUARD },
+ { { 2198.29f, -436.92f, 419.95f, 0.261f }, NPC_DARK_RUNE_ACOLYTE },
+ { { 2230.93f, -434.27f, 412.26f, 1.931f }, NPC_DARK_RUNE_ACOLYTE }
+};
+
+Position const SifSpawnPosition = { 2148.301f, -297.8453f, 438.3308f, 2.687807f };
+
+enum Data
+{
+ DATA_CHARGED_PILLAR = 1
+};
+
+enum DisplayIds
+{
+ THORIM_WEAPON_DISPLAY_ID = 45900
+};
+
+uint32 const LightningOrbPathSize = 8;
+G3D::Vector3 const LightningOrbPath[LightningOrbPathSize] =
+{
+ { 2134.889893f, -298.632996f, 438.247467f },
+ { 2134.570068f, -440.317993f, 438.247467f },
+ { 2167.820312f, -440.330261f, 438.247589f },
+ { 2213.394287f, -433.318298f, 412.665863f },
+ { 2227.766113f, -433.275818f, 412.177032f },
+ { 2227.551270f, -263.081085f, 412.176880f },
+ { 2202.208008f, -262.939270f, 412.168976f },
+ { 2182.310059f, -263.233093f, 414.739410f }
+};
+
+// used for trash jump calculation
+Position const ArenaCenter = { 2134.77f, -262.307f };
+
+// used for lightning field calculation
+Position const LightningFieldCenter = { 2135.178f, -321.122f };
+
+CircleBoundary const ArenaFloorCircle(ArenaCenter, 45.4);
+CircleBoundary const InvertedBalconyCircle(LightningFieldCenter, 32.0, true);
+
+CreatureBoundary const ArenaBoundaries =
+{
+ &ArenaFloorCircle,
+ &InvertedBalconyCircle
+};
+
+class HeightPositionCheck
+{
+ public:
+ HeightPositionCheck(bool ret) : _ret(ret) { }
+
+ bool operator()(Position const* pos) const
+ {
+ return pos->GetPositionZ() > THORIM_BALCONY_Z_CHECK == _ret;
+ }
+
+ private:
+ bool _ret;
+
+ static float const THORIM_BALCONY_Z_CHECK;
+};
+float const HeightPositionCheck::THORIM_BALCONY_Z_CHECK = 428.0f;
+
+class RunicSmashExplosionEvent : public BasicEvent
+{
+ public:
+ RunicSmashExplosionEvent(Creature* owner) : _owner(owner) { }
+
+ bool Execute(uint64 /*eventTime*/, uint32 /*updateTime*/) override
+ {
+ _owner->CastSpell((Unit*)nullptr, SPELL_RUNIC_SMASH);
+ return true;
+ }
+
+ private:
+ Creature* _owner;
+};
+
+class TrashJumpEvent : public BasicEvent
+{
+ public:
+ TrashJumpEvent(Creature* owner) : _owner(owner), _stage(0) { }
+
+ bool Execute(uint64 eventTime, uint32 /*updateTime*/) override
+ {
+ switch (_stage)
+ {
+ case 0:
+ _owner->CastSpell((Unit*)nullptr, SPELL_LEAP);
+ ++_stage;
+ _owner->m_Events.AddEvent(this, eventTime + 2000);
+ return false;
+ case 1:
+ _owner->SetReactState(REACT_AGGRESSIVE);
+ _owner->AI()->DoZoneInCombat(_owner);
+ _owner->AI()->SetBoundary(&ArenaBoundaries);
+ return true;
+ default:
+ break;
+ }
+
+ return true;
+ }
+
+ private:
+ Creature* _owner;
+ uint8 _stage;
+};
+
+class LightningFieldEvent : public BasicEvent
+{
+ public:
+ LightningFieldEvent(Creature* owner) : _owner(owner) { }
+
+ bool Execute(uint64 eventTime, uint32 /*updateTime*/) override
+ {
+ if (InstanceScript* instance = _owner->GetInstanceScript())
+ {
+ if (instance->GetBossState(BOSS_THORIM) == IN_PROGRESS)
+ {
+ _owner->CastSpell((Unit*)nullptr, SPELL_LIGHTNING_FIELD);
+ _owner->m_Events.AddEvent(this, eventTime + 1000);
+ return false;
+ }
+ }
+
+ _owner->InterruptNonMeleeSpells(false);
+ _owner->AI()->EnterEvadeMode();
+ return true;
+ }
+
+ private:
+ Creature* _owner;
};
class boss_thorim : public CreatureScript
@@ -47,17 +447,76 @@ class boss_thorim : public CreatureScript
{
boss_thorimAI(Creature* creature) : BossAI(creature, BOSS_THORIM)
{
+ _encounterFinished = false;
+ Initialize();
+ }
+
+ void Initialize()
+ {
+ _killedCount = 0;
+ _waveType = 0;
+ _hardMode = true;
+ _orbSummoned = false;
+ _dontStandInTheLightning = true;
}
void Reset() override
{
+ if (_encounterFinished)
+ return;
+
+ SetBoundary(nullptr);
_Reset();
+ Initialize();
+
+ me->SetReactState(REACT_PASSIVE);
+ me->SetDisableGravity(true);
+ me->SetControlled(true, UNIT_STATE_ROOT);
+ me->AddUnitFlag(UNIT_FLAG_IMMUNE_TO_PC);
+
+ events.SetPhase(PHASE_NULL);
+
+ // Respawn Mini Bosses
+ for (uint8 i = DATA_RUNIC_COLOSSUS; i <= DATA_RUNE_GIANT; ++i)
+ if (Creature* miniBoss = ObjectAccessor::GetCreature(*me, instance->GetGuidData(i)))
+ miniBoss->Respawn(true);
+
+ // Spawn Pre Phase Adds
+ for (SummonLocation const& s : PreAddLocations)
+ me->SummonCreature(s.entry, s.pos, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 3000);
+
+ if (GameObject* lever = instance->GetGameObject(DATA_THORIM_LEVER))
+ lever->AddFlag(GO_FLAG_NOT_SELECTABLE);
+
+ // Remove trigger auras
+ if (Creature* pillar = ObjectAccessor::GetCreature(*me, _activePillarGUID))
+ pillar->RemoveAllAuras();
+
+ if (Creature* controller = instance->GetCreature(DATA_THORIM_CONTROLLER))
+ controller->RemoveAllAuras();
+
+ _activePillarGUID.Clear();
}
- void EnterEvadeMode(EvadeReason why) override
+ void EnterEvadeMode(EvadeReason /*why*/) override
{
- Talk(SAY_WIPE);
- _EnterEvadeMode(why);
+ summons.DespawnAll();
+ _DespawnAtEvade();
+ }
+
+ void SetGUID(ObjectGuid guid, int32 type) override
+ {
+ if (type == DATA_CHARGED_PILLAR)
+ {
+ _activePillarGUID = guid;
+
+ if (Creature* pillar = ObjectAccessor::GetCreature(*me, _activePillarGUID))
+ {
+ pillar->CastSpell(pillar, SPELL_LIGHTNING_ORB_CHARGED, true);
+ pillar->CastSpell((Unit*)nullptr, SPELL_LIGHTNING_PILLAR_2);
+ events.ScheduleEvent(EVENT_LIGHTNING_CHARGE, 8000, 0, PHASE_2);
+ }
+ }
}
void KilledUnit(Unit* who) override
@@ -66,27 +525,410 @@ class boss_thorim : public CreatureScript
Talk(SAY_SLAY);
}
- void JustDied(Unit* /*killer*/) override
+ void SpellHit(Unit* /*caster*/, SpellInfo const* spellInfo) override
{
- Talk(SAY_DEATH);
+ if (spellInfo->Id == SPELL_TOUCH_OF_DOMINION_TRIGGERED)
+ {
+ if (Creature* sif = instance->GetCreature(DATA_SIF))
+ {
+ sif->AI()->Talk(SAY_SIF_DESPAWN);
+ sif->DespawnOrUnsummon(6000);
+ _hardMode = false;
+ }
+ }
+ }
+
+ void SpellHitTarget(Unit* who, SpellInfo const* spellInfo) override
+ {
+ if (who->GetTypeId() == TYPEID_PLAYER && spellInfo->Id == SPELL_LIGHTNING_RELEASE)
+ _dontStandInTheLightning = false;
+ }
+
+ void FinishEncounter()
+ {
+ if (_encounterFinished)
+ return;
+
+ _encounterFinished = true;
+
+ DoCastAOE(SPELL_CREDIT_KILL, true); // before change faction
+
+ me->SetReactState(REACT_PASSIVE);
+ me->InterruptNonMeleeSpells(true);
+ me->RemoveAllAttackers();
+ me->AttackStop();
+ me->SetFaction(FACTION_FRIENDLY);
+ me->AddUnitFlag(UNIT_FLAG_RENAME);
+
+ if (Creature* controller = instance->GetCreature(DATA_THORIM_CONTROLLER))
+ controller->RemoveAllAuras();
+ if (Creature* pillar = ObjectAccessor::GetCreature(*me, _activePillarGUID))
+ pillar->RemoveAllAuras();
+
+ if (_hardMode)
+ {
+ if (Creature* sif = instance->GetCreature(DATA_SIF))
+ {
+ summons.Despawn(sif);
+ sif->DespawnOrUnsummon(10000);
+ }
+ }
+
_JustDied();
+
+ Talk(SAY_DEATH);
+ events.ScheduleEvent(EVENT_OUTRO_1, 4000);
+ events.ScheduleEvent(EVENT_OUTRO_2, _hardMode ? 8000 : 11000);
+ events.ScheduleEvent(EVENT_OUTRO_3, _hardMode ? 19000 : 21000);
+
+ me->m_Events.AddEvent(new KeeperDespawnEvent(me), me->m_Events.CalculateTime(35000));
+ }
+
+ void MovementInform(uint32 type, uint32 id) override
+ {
+ if (type != EFFECT_MOTION_TYPE || id != EVENT_JUMP)
+ return;
+
+ me->getThreatManager().resetAllAggro();
+ SetBoundary(&ArenaBoundaries);
}
void EnterCombat(Unit* /*who*/) override
{
- Talk(SAY_AGGRO);
_EnterCombat();
+ Talk(SAY_AGGRO_1);
+
+ events.SetPhase(PHASE_1);
+
+ events.ScheduleEvent(EVENT_SAY_AGGRO_2, 9000, 0, PHASE_1);
+ events.ScheduleEvent(EVENT_SAY_SIF_START, 16500, 0, PHASE_1);
+ events.ScheduleEvent(EVENT_START_SIF_CHANNEL, 22500, 0, PHASE_1);
+
+ events.ScheduleEvent(EVENT_STORMHAMMER, 40000, 0, PHASE_1);
+ events.ScheduleEvent(EVENT_CHARGE_ORB, 30000, 0, PHASE_1);
+ events.ScheduleEvent(EVENT_SUMMON_ADDS, 15000, 0, PHASE_1);
+ events.ScheduleEvent(EVENT_BERSERK, 369000);
+
+ DoCast(me, SPELL_SHEATH_OF_LIGHTNING);
+
+ if (Creature* runicColossus = instance->GetCreature(DATA_RUNIC_COLOSSUS))
+ {
+ runicColossus->RemoveUnitFlag(UNIT_FLAG_IMMUNE_TO_PC);
+ runicColossus->AI()->DoAction(ACTION_ACTIVATE_ADDS);
+ }
+
+ if (GameObject* lever = instance->GetGameObject(DATA_THORIM_LEVER))
+ lever->RemoveFlag(GO_FLAG_NOT_SELECTABLE);
+
+ // Summon Sif
+ me->SummonCreature(NPC_SIF, SifSpawnPosition);
+ }
+
+ void JustSummoned(Creature* summon) override
+ {
+ switch (summon->GetEntry())
+ {
+ case NPC_LIGHTNING_ORB:
+ {
+ summon->SetReactState(REACT_PASSIVE);
+ summon->CastSpell(summon, SPELL_LIGHTNING_DESTRUCTION, true);
+
+ summon->GetMotionMaster()->MovePoint(EVENT_CHARGE_PREPATH, LightningOrbPath[LightningOrbPathSize - 1].x, LightningOrbPath[LightningOrbPathSize - 1].y, LightningOrbPath[LightningOrbPathSize - 1].z, false);
+
+ Movement::PointsArray path(LightningOrbPath, LightningOrbPath + LightningOrbPathSize);
+
+ Movement::MoveSplineInit init(summon);
+ init.MovebyPath(path);
+ init.Launch();
+ break;
+ }
+ case NPC_DARK_RUNE_CHAMPION:
+ case NPC_DARK_RUNE_WARBRINGER:
+ case NPC_DARK_RUNE_EVOKER:
+ case NPC_DARK_RUNE_COMMONER:
+ summon->SetReactState(REACT_PASSIVE);
+ summon->m_Events.AddEvent(new TrashJumpEvent(summon), summon->m_Events.CalculateTime(3000));
+ break;
+ case NPC_SIF:
+ summon->SetReactState(REACT_PASSIVE);
+ break;
+ default:
+ break;
+ }
+
+ BossAI::JustSummoned(summon);
}
- void UpdateAI(uint32 /*diff*/) override
+ void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
return;
- //SPELLS @todo
- //
+ events.Update(diff);
+
+ if (me->HasUnitState(UNIT_STATE_CASTING))
+ return;
+
+ while (uint32 eventId = events.ExecuteEvent())
+ {
+ switch (eventId)
+ {
+ case EVENT_SAY_AGGRO_2:
+ Talk(SAY_AGGRO_2);
+ break;
+ case EVENT_SAY_SIF_START:
+ if (Creature* sif = instance->GetCreature(DATA_SIF))
+ sif->AI()->Talk(SAY_SIF_START);
+ break;
+ case EVENT_START_SIF_CHANNEL:
+ if (Creature* sif = instance->GetCreature(DATA_SIF))
+ sif->CastSpell(me, SPELL_TOUCH_OF_DOMINION);
+ break;
+ case EVENT_STORMHAMMER:
+ DoCast(SPELL_STORMHAMMER);
+ events.Repeat(15000, 20000);
+ break;
+ case EVENT_CHARGE_ORB:
+ DoCastAOE(SPELL_CHARGE_ORB);
+ events.Repeat(15000, 20000);
+ break;
+ case EVENT_SUMMON_ADDS:
+ SummonWave();
+ events.Repeat(_orbSummoned ? 3000 : 10000);
+ break;
+ case EVENT_JUMPDOWN:
+ if (_hardMode)
+ if (Creature* sif = instance->GetCreature(DATA_SIF))
+ sif->AI()->DoAction(ACTION_START_HARD_MODE);
+ me->RemoveAurasDueToSpell(SPELL_SHEATH_OF_LIGHTNING);
+ me->SetReactState(REACT_AGGRESSIVE);
+ me->SetDisableGravity(false);
+ me->SetControlled(false, UNIT_STATE_ROOT);
+ me->GetMotionMaster()->MoveJump(2134.8f, -263.056f, 419.983f, me->GetOrientation(), 30.0f, 20.0f);
+ events.ScheduleEvent(EVENT_START_PERIODIC_CHARGE, 2000, 0, PHASE_2);
+ events.ScheduleEvent(EVENT_UNBALANCING_STRIKE, 15000, 0, PHASE_2);
+ events.ScheduleEvent(EVENT_CHAIN_LIGHTNING, 20000, 0, PHASE_2);
+ break;
+ case EVENT_UNBALANCING_STRIKE:
+ DoCastVictim(SPELL_UNBALANCING_STRIKE);
+ events.Repeat(15000, 20000);
+ break;
+ case EVENT_CHAIN_LIGHTNING:
+ if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100.0f, true))
+ DoCast(target, SPELL_CHAIN_LIGHTNING);
+ events.Repeat(7000, 15000);
+ break;
+ case EVENT_START_PERIODIC_CHARGE:
+ if (Creature* controller = instance->GetCreature(DATA_THORIM_CONTROLLER))
+ controller->CastSpell(controller, SPELL_ACTIVATE_LIGHTNING_ORB_PERIODIC, true);
+ break;
+ case EVENT_LIGHTNING_CHARGE:
+ if (Creature* pillar = ObjectAccessor::GetCreature(*me, _activePillarGUID))
+ DoCast(pillar, SPELL_LIGHTNING_RELEASE);
+ break;
+ case EVENT_BERSERK:
+ if (events.IsInPhase(PHASE_1))
+ {
+ Talk(SAY_WIPE);
+ DoCastAOE(SPELL_BERSERK_PHASE_1, true);
+ DoCast(me, SPELL_SUMMON_LIGHTNING_ORB, true);
+ }
+ else
+ {
+ Talk(SAY_BERSERK);
+ DoCast(me, SPELL_BERSERK_PHASE_2, true);
+ }
+ break;
+ case EVENT_ACTIVATE_LIGHTNING_FIELD:
+ {
+ std::list<Creature*> triggers;
+ me->GetCreatureListWithEntryInGrid(triggers, NPC_THORIM_EVENT_BUNNY, 100.0f);
+ triggers.remove_if([](Creature* bunny)
+ {
+ if (HeightPositionCheck(false)(bunny))
+ return true;
+ return LightningFieldCenter.GetExactDist2dSq(bunny) > 1296.0f;
+ });
+
+ uint64 timer = 1000;
+ for (Creature* bunny : triggers)
+ bunny->m_Events.AddEvent(new LightningFieldEvent(bunny), bunny->m_Events.CalculateTime(timer += 100));
+
+ triggers.remove_if([](Creature* bunny)
+ {
+ return LightningFieldCenter.GetExactDist2dSq(bunny) < 576.0f;
+ });
+
+ triggers.sort([](Creature* a, Creature* b)
+ {
+ return a->GetPositionX() < b->GetPositionX();
+ });
+
+ for (auto itr = triggers.cbegin(); itr != triggers.cend();)
+ {
+ auto prev = itr++;
+ if (itr != triggers.end())
+ (*prev)->CastSpell(*itr, SPELL_LIGHTNING_BEAM_CHANNEL);
+ }
+ break;
+ }
+ case EVENT_OUTRO_1:
+ Talk(_hardMode ? SAY_END_HARD_1 : SAY_END_NORMAL_1);
+ if (_hardMode)
+ DoCast(me, SPELL_STORMHAMMER_SIF);
+ break;
+ case EVENT_OUTRO_2:
+ Talk(_hardMode ? SAY_END_HARD_2 : SAY_END_NORMAL_2);
+ if (_hardMode)
+ if (Creature* sif = instance->GetCreature(DATA_SIF))
+ sif->SetStandState(UNIT_STAND_STATE_DEAD);
+ break;
+ case EVENT_OUTRO_3:
+ Talk(_hardMode ? SAY_END_HARD_3 : SAY_END_NORMAL_3);
+ break;
+ default:
+ break;
+ }
+
+ if (me->HasUnitState(UNIT_STATE_CASTING))
+ return;
+ }
+
DoMeleeAttackIfReady();
}
+
+ void DoAction(int32 action) override
+ {
+ switch (action)
+ {
+ case ACTION_BERSERK:
+ if (events.IsInPhase(PHASE_2))
+ return;
+
+ if (!_orbSummoned)
+ {
+ _orbSummoned = true;
+ events.RescheduleEvent(EVENT_BERSERK, 1000);
+ }
+ return;
+ case ACTION_INCREASE_PREADDS_COUNT:
+ if (++_killedCount >= 6)
+ {
+ // Event starts
+ me->RemoveUnitFlag(UNIT_FLAG_IMMUNE_TO_PC);
+ DoZoneInCombat(me);
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ void GetTrashSpawnTriggers(std::list<Creature*>& triggerList, uint32 count = 1)
+ {
+ me->GetCreatureListWithEntryInGrid(triggerList, NPC_THORIM_EVENT_BUNNY, 100.0f);
+ triggerList.remove_if([](Creature* bunny)
+ {
+ if (HeightPositionCheck(false)(bunny))
+ return true;
+ return ArenaCenter.GetExactDist2dSq(bunny) < 3025.0f;
+ });
+
+ if (triggerList.empty())
+ return;
+
+ if (count == 1)
+ {
+ Creature* bunny = Trinity::Containers::SelectRandomContainerElement(triggerList);
+ triggerList.clear();
+ triggerList.push_back(bunny);
+ }
+ else
+ Trinity::Containers::RandomResize(triggerList, count);
+ }
+
+ void SummonWave()
+ {
+ switch (_waveType)
+ {
+ case 0:
+ {
+ // Dark Rune Commoner
+ std::list<Creature*> triggers;
+ GetTrashSpawnTriggers(triggers, urand(5, 6));
+
+ for (Creature* bunny : triggers)
+ me->SummonCreature(StaticThorimTrashInfo[6 + 3].Entry, *bunny, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 3000);
+
+ ++_waveType;
+ break;
+ }
+ case 1:
+ if (urand(0, 1))
+ {
+ // Dark Rune Champion or Dark Rune Evoker
+ std::list<Creature*> triggers;
+ GetTrashSpawnTriggers(triggers, urand(2, 4));
+
+ for (Creature* bunny : triggers)
+ me->SummonCreature(StaticThorimTrashInfo[6 + RAND(0, 2)].Entry, *bunny, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 3000);
+ }
+ else
+ {
+ // Dark Rune Warbringer
+ std::list<Creature*> triggers;
+ GetTrashSpawnTriggers(triggers);
+
+ for (Creature* bunny : triggers)
+ me->SummonCreature(StaticThorimTrashInfo[6 + 1].Entry, *bunny, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 3000);
+ }
+ --_waveType;
+ break;
+ }
+ }
+
+ bool CanStartPhase2(Unit* actor) const
+ {
+ if (actor->GetTypeId() != TYPEID_PLAYER || !me->IsWithinDistInMap(actor, 10.0f))
+ return false;
+
+ Creature* runicColossus = instance->GetCreature(DATA_RUNIC_COLOSSUS);
+ Creature* runeGiant = instance->GetCreature(DATA_RUNE_GIANT);
+ return runicColossus && !runicColossus->IsAlive() && runeGiant && !runeGiant->IsAlive();
+ }
+
+ void DamageTaken(Unit* attacker, uint32& damage) override
+ {
+ if (events.IsInPhase(PHASE_1) && CanStartPhase2(attacker))
+ {
+ Talk(SAY_JUMPDOWN);
+ events.SetPhase(PHASE_2);
+ events.ScheduleEvent(EVENT_JUMPDOWN, 8000);
+ events.ScheduleEvent(EVENT_ACTIVATE_LIGHTNING_FIELD, 15000);
+ events.RescheduleEvent(EVENT_BERSERK, 300000, 0, PHASE_2);
+
+ if (Creature* sif = instance->GetCreature(DATA_SIF))
+ sif->InterruptNonMeleeSpells(false);
+
+ // Hard Mode
+ if (_hardMode)
+ DoCastAOE(SPELL_CREDIT_SIFFED, true);
+ }
+ else if (me->HealthBelowPctDamaged(1, damage))
+ {
+ damage = 0;
+ FinishEncounter();
+ }
+ }
+
+ private:
+ ObjectGuid _activePillarGUID;
+ uint8 _killedCount;
+ uint8 _waveType;
+ bool _hardMode;
+ bool _encounterFinished;
+ bool _orbSummoned;
+ bool _dontStandInTheLightning;
};
CreatureAI* GetAI(Creature* creature) const override
@@ -95,7 +937,1234 @@ class boss_thorim : public CreatureScript
}
};
+struct npc_thorim_trashAI : public ScriptedAI
+{
+ npc_thorim_trashAI(Creature* creature) : ScriptedAI(creature)
+ {
+ _instance = creature->GetInstanceScript();
+ for (uint8 i = 0; i < ThorimTrashCount; ++i)
+ if (me->GetEntry() == StaticThorimTrashInfo[i].Entry)
+ _info = &StaticThorimTrashInfo[i];
+
+ ASSERT(_info);
+ }
+
+ struct AIHelper
+ {
+ /// returns heal amount of the given spell including hots
+ static uint32 GetTotalHeal(SpellInfo const* spellInfo, Unit const* caster)
+ {
+ uint32 heal = 0;
+ for (SpellEffectInfo const* effect : spellInfo->GetEffects())
+ {
+ if (effect->IsEffect(SPELL_EFFECT_HEAL))
+ heal += effect->CalcValue(caster);
+
+ if (effect->IsEffect(SPELL_EFFECT_APPLY_AURA) && effect->IsAura(SPELL_AURA_PERIODIC_HEAL))
+ heal += spellInfo->GetMaxTicks() * effect->CalcValue(caster);
+ }
+ return heal;
+ }
+
+ /// returns remaining heal amount on given target
+ static uint32 GetRemainingHealOn(Unit* target)
+ {
+ uint32 heal = 0;
+ Unit::AuraEffectList const& auras = target->GetAuraEffectsByType(SPELL_AURA_PERIODIC_HEAL);
+ for (AuraEffect const* aurEff : auras)
+ heal += aurEff->GetAmount() * (aurEff->GetTotalTicks() - aurEff->GetTickNumber());
+
+ return heal;
+ }
+
+ class MostHPMissingInRange
+ {
+ public:
+ MostHPMissingInRange(Unit const* referer, float range, uint32 hp, uint32 exclAura = 0, bool exclSelf = false)
+ : _referer(referer), _range(range), _hp(hp), _exclAura(exclAura), _exclSelf(exclSelf) { }
+
+ bool operator()(Unit* u)
+ {
+ if (_exclSelf && u == _referer)
+ return false;
+
+ if (_exclAura && u->HasAura(_exclAura))
+ return false;
+
+ if ((u->GetHealth() + GetRemainingHealOn(u) + _hp) > u->GetMaxHealth())
+ return false;
+
+ uint32 missingHP = u->GetMaxHealth() - u->GetHealth();
+ if (u->IsAlive() && _referer->IsFriendlyTo(u) && _referer->IsWithinDistInMap(u, _range) && missingHP > _hp)
+ {
+ _hp = missingHP;
+ return true;
+ }
+
+ return false;
+ }
+
+ private:
+ Unit const* _referer;
+ float _range;
+ uint32 _hp;
+ uint32 _exclAura;
+ bool _exclSelf;
+ };
+
+ static Unit* GetUnitWithMostMissingHp(SpellInfo const* spellInfo, Unit* caster)
+ {
+ // use positive range, it's a healing spell
+ float const range = spellInfo->GetMaxRange(true);
+ uint32 const heal = GetTotalHeal(spellInfo, caster);
+
+ Unit* target = nullptr;
+ Trinity::MostHPMissingInRange checker(caster, range, heal);
+ Trinity::UnitLastSearcher<Trinity::MostHPMissingInRange> searcher(caster, target, checker);
+ Cell::VisitGridObjects(caster, searcher, 60.0f);
+
+ return target;
+ }
+
+ static Unit* GetHealTarget(SpellInfo const* spellInfo, Unit* caster)
+ {
+ Unit* healTarget = nullptr;
+ if (!spellInfo->HasAttribute(SPELL_ATTR1_CANT_TARGET_SELF) && !roll_chance_f(caster->GetHealthPct()) && ((caster->GetHealth() + GetRemainingHealOn(caster) + GetTotalHeal(spellInfo, caster)) <= caster->GetMaxHealth()))
+ healTarget = caster;
+ else
+ healTarget = GetUnitWithMostMissingHp(spellInfo, caster);
+
+ return healTarget;
+ }
+ };
+
+ bool UseAbility(uint32 spellId)
+ {
+ SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId, GetDifficulty());
+ if (!spellInfo)
+ return false;
+
+ Unit* target = nullptr;
+ if (AIHelper::GetTotalHeal(spellInfo, me))
+ target = AIHelper::GetHealTarget(spellInfo, me);
+ else
+ target = me->GetVictim();
+
+ if (!target)
+ return false;
+
+ if (_info->Type == MERCENARY_SOLDIER)
+ {
+ bool allowMove = true;
+ if (me->IsInRange(target, spellInfo->GetMinRange(), spellInfo->GetMaxRange()))
+ allowMove = false;
+
+ if (IsCombatMovementAllowed() != allowMove)
+ {
+ SetCombatMovement(allowMove);
+
+ // need relaunch movement
+ ScriptedAI::AttackStart(target);
+
+ // give some time to allow reposition, try again in a second
+ if (allowMove)
+ return false;
+ }
+ }
+
+ DoCast(target, spellId);
+ return true;
+ }
+
+ void UpdateAI(uint32 diff) final override
+ {
+ if (!UpdateVictim())
+ return;
+
+ _events.Update(diff);
+
+ if (me->HasUnitState(UNIT_STATE_CASTING))
+ return;
+
+ while (uint32 eventId = _events.ExecuteEvent())
+ {
+ ExecuteEvent(eventId);
+
+ if (me->HasUnitState(UNIT_STATE_CASTING))
+ return;
+ }
+
+ if (_info->Type == DARK_RUNE_ACOLYTE)
+ DoSpellAttackIfReady(SPELL_HOLY_SMITE);
+ else
+ DoMeleeAttackIfReady();
+ }
+
+ virtual void ExecuteEvent(uint32 eventId) = 0;
+
+protected:
+ InstanceScript* _instance;
+ EventMap _events;
+
+ ThorimTrashInfo const* _info = nullptr;
+};
+
+class npc_thorim_pre_phase : public CreatureScript
+{
+ public:
+ npc_thorim_pre_phase() : CreatureScript("npc_thorim_pre_phase") { }
+
+ struct npc_thorim_pre_phaseAI : public npc_thorim_trashAI
+ {
+ npc_thorim_pre_phaseAI(Creature* creature) : npc_thorim_trashAI(creature)
+ {
+ me->setActive(true); // prevent grid unload
+ }
+
+ void Reset() override
+ {
+ _events.Reset();
+ if (_info->PrimaryAbility)
+ _events.ScheduleEvent(EVENT_PRIMARY_ABILITY, urand(3000, 6000));
+ if (_info->SecondaryAbility)
+ _events.ScheduleEvent(EVENT_SECONDARY_ABILITY, _info->SecondaryAbility == SPELL_SHOOT ? 2000 : urand(12000, 15000));
+ if (_info->ThirdAbility)
+ _events.ScheduleEvent(EVENT_THIRD_ABILITY, urand(6000, 8000));
+ if (_info->Type == MERCENARY_SOLDIER)
+ SetCombatMovement(false);
+ }
+
+ void JustDied(Unit* /*victim*/) override
+ {
+ if (Creature* thorim = _instance->GetCreature(BOSS_THORIM))
+ thorim->AI()->DoAction(ACTION_INCREASE_PREADDS_COUNT);
+ }
+
+ bool ShouldSparWith(Unit const* target) const override
+ {
+ return !target->GetAffectingPlayer();
+ }
+
+ void DamageTaken(Unit* attacker, uint32& damage) override
+ {
+ // nullify spell damage
+ if (!attacker->GetAffectingPlayer())
+ damage = 0;
+ }
+
+ void ExecuteEvent(uint32 eventId) override
+ {
+ switch (eventId)
+ {
+ case EVENT_PRIMARY_ABILITY:
+ if (UseAbility(_info->PrimaryAbility))
+ _events.ScheduleEvent(eventId, urand(15000, 20000));
+ else
+ _events.ScheduleEvent(eventId, 1000);
+ break;
+ case EVENT_SECONDARY_ABILITY:
+ if (UseAbility(_info->SecondaryAbility))
+ _events.ScheduleEvent(eventId, _info->SecondaryAbility == SPELL_SHOOT ? 2000 : urand(4000, 8000));
+ else
+ _events.ScheduleEvent(eventId, 1000);
+ break;
+ case EVENT_THIRD_ABILITY:
+ if (UseAbility(_info->ThirdAbility))
+ _events.ScheduleEvent(eventId, urand(6000, 8000));
+ else
+ _events.ScheduleEvent(eventId, 1000);
+ break;
+ default:
+ break;
+ }
+ }
+ };
+
+ CreatureAI* GetAI(Creature* creature) const override
+ {
+ return GetUlduarAI<npc_thorim_pre_phaseAI>(creature);
+ }
+};
+
+class npc_thorim_arena_phase : public CreatureScript
+{
+ public:
+ npc_thorim_arena_phase() : CreatureScript("npc_thorim_arena_phase") { }
+
+ struct npc_thorim_arena_phaseAI : public npc_thorim_trashAI
+ {
+ npc_thorim_arena_phaseAI(Creature* creature) : npc_thorim_trashAI(creature)
+ {
+ switch (_info->Type)
+ {
+ case DARK_RUNE_CHAMPION:
+ case DARK_RUNE_WARBRINGER:
+ case DARK_RUNE_COMMONER:
+ case DARK_RUNE_EVOKER:
+ _isInArena = true;
+ break;
+ case DARK_RUNE_ACOLYTE:
+ {
+ _isInArena = (_info->Entry == NPC_DARK_RUNE_ACOLYTE_PRE);
+ SetBoundary(&ArenaBoundaries, !_isInArena);
+ break;
+ }
+ default:
+ _isInArena = false;
+ break;
+ }
+ }
+
+ bool CanAIAttack(Unit const* who) const override
+ {
+ // don't try to attack players in balcony
+ if (_isInArena && HeightPositionCheck(true)(who))
+ return false;
+
+ return CheckBoundary(who);
+ }
+
+ void Reset() override
+ {
+ _events.Reset();
+ if (_info->PrimaryAbility)
+ _events.ScheduleEvent(EVENT_PRIMARY_ABILITY, urand(3000, 6000));
+ if (_info->SecondaryAbility)
+ _events.ScheduleEvent(EVENT_SECONDARY_ABILITY, urand(7000, 9000));
+ if (_info->ThirdAbility)
+ _events.ScheduleEvent(EVENT_THIRD_ABILITY, urand(6000, 8000));
+ if (_info->Type == DARK_RUNE_CHAMPION)
+ _events.ScheduleEvent(EVENT_ABILITY_CHARGE, 8000);
+ }
+
+ void EnterCombat(Unit* /*who*/) override
+ {
+ if (_info->Type == DARK_RUNE_WARBRINGER)
+ DoCast(me, SPELL_AURA_OF_CELERITY);
+
+ if (!_isInArena)
+ if (Creature* colossus = _instance->GetCreature(DATA_RUNIC_COLOSSUS))
+ colossus->AI()->DoAction(ACTION_ACTIVATE_RUNIC_SMASH);
+ }
+
+ void EnterEvadeMode(EvadeReason why) override
+ {
+ if (why != EVADE_REASON_NO_HOSTILES && why != EVADE_REASON_BOUNDARY)
+ return;
+
+ // this should only happen if theres no alive player in the arena -> summon orb
+ if (Creature* thorim = _instance->GetCreature(BOSS_THORIM))
+ thorim->AI()->DoAction(ACTION_BERSERK);
+ ScriptedAI::EnterEvadeMode(why);
+ }
+
+ void ExecuteEvent(uint32 eventId) override
+ {
+ switch (eventId)
+ {
+ case EVENT_PRIMARY_ABILITY:
+ if (UseAbility(_info->PrimaryAbility))
+ _events.Repeat(3000, 6000);
+ else
+ _events.Repeat(1000);
+ break;
+ case EVENT_SECONDARY_ABILITY:
+ if (UseAbility(_info->SecondaryAbility))
+ _events.Repeat(12000, 16000);
+ else
+ _events.Repeat(1000);
+ break;
+ case EVENT_THIRD_ABILITY:
+ if (UseAbility(_info->ThirdAbility))
+ _events.Repeat(6000, 8000);
+ else
+ _events.Repeat(1000);
+ break;
+ case EVENT_ABILITY_CHARGE:
+ {
+ Unit* referer = me;
+ if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, [referer](Unit* unit){ return unit->GetTypeId() == TYPEID_PLAYER && unit->IsInRange(referer, 8.0f, 25.0f); }))
+ DoCast(target, SPELL_CHARGE);
+ _events.ScheduleEvent(eventId, 12000);
+ break;
+ }
+ default:
+ break;
+ }
+ }
+
+ private:
+ bool _isInArena;
+ };
+
+ CreatureAI* GetAI(Creature* creature) const override
+ {
+ return GetUlduarAI<npc_thorim_arena_phaseAI>(creature);
+ }
+};
+
+struct npc_thorim_minibossAI : public ScriptedAI
+{
+ npc_thorim_minibossAI(Creature* creature) : ScriptedAI(creature), _summons(me)
+ {
+ _instance = creature->GetInstanceScript();
+
+ SetBoundary(&ArenaBoundaries, true);
+ }
+
+ bool CanAIAttack(Unit const* who) const final override
+ {
+ return CheckBoundary(who);
+ }
+
+ void JustSummoned(Creature* summon) final override
+ {
+ _summons.Summon(summon);
+ }
+
+ void SummonedCreatureDespawn(Creature* summon) final override
+ {
+ _summons.Despawn(summon);
+ }
+
+ void DoAction(int32 action) override
+ {
+ if (action == ACTION_ACTIVATE_ADDS)
+ {
+ for (ObjectGuid const& guid : _summons)
+ if (Creature* summon = ObjectAccessor::GetCreature(*me, guid))
+ summon->RemoveUnitFlag(UNIT_FLAG_IMMUNE_TO_PC);
+ }
+ }
+
+protected:
+ InstanceScript* _instance;
+ EventMap _events;
+ SummonList _summons;
+};
+
+class npc_runic_colossus : public CreatureScript
+{
+ public:
+ npc_runic_colossus() : CreatureScript("npc_runic_colossus") { }
+
+ struct npc_runic_colossusAI : public npc_thorim_minibossAI
+ {
+ npc_runic_colossusAI(Creature* creature) : npc_thorim_minibossAI(creature)
+ {
+ Initialize();
+ }
+
+ void Initialize()
+ {
+ _runicActive = false;
+ }
+
+ void Reset() override
+ {
+ Initialize();
+ _events.Reset();
+
+ // close the Runic Door
+ _instance->HandleGameObject(_instance->GetGuidData(DATA_RUNIC_DOOR), false);
+
+ // Spawn trashes
+ _summons.DespawnAll();
+ for (SummonLocation const& s : ColossusAddLocations)
+ me->SummonCreature(s.entry, s.pos, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 3000);
+ }
+
+ void MoveInLineOfSight(Unit* /*who*/) override
+ {
+ // don't enter combat
+ }
+
+ void DoAction(int32 action) override
+ {
+ npc_thorim_minibossAI::DoAction(action);
+
+ if (_runicActive)
+ return;
+
+ if (action == ACTION_ACTIVATE_RUNIC_SMASH)
+ {
+ _runicActive = true;
+ _events.ScheduleEvent(EVENT_RUNIC_SMASH, 7000);
+ }
+ }
+
+ void JustDied(Unit* /*victim*/) override
+ {
+ // open the Runic Door
+ _instance->HandleGameObject(_instance->GetGuidData(DATA_RUNIC_DOOR), true);
+
+ if (Creature* thorim = _instance->GetCreature(BOSS_THORIM))
+ thorim->AI()->Talk(SAY_SPECIAL);
+
+ if (Creature* giant = _instance->GetCreature(DATA_RUNE_GIANT))
+ {
+ giant->RemoveUnitFlag(UNIT_FLAG_IMMUNE_TO_PC);
+ giant->AI()->DoAction(ACTION_ACTIVATE_ADDS);
+ }
+ }
+
+ void EnterCombat(Unit* /*who*/) override
+ {
+ DoZoneInCombat();
+ _events.Reset();
+ _events.ScheduleEvent(EVENT_RUNIC_BARRIER, urand(12000, 15000));
+ _events.ScheduleEvent(EVENT_SMASH, urand(15000, 18000));
+ _events.ScheduleEvent(EVENT_RUNIC_CHARGE, urand(20000, 24000));
+ }
+
+ void UpdateAI(uint32 diff) override
+ {
+ _events.Update(diff);
+
+ if (me->HasUnitState(UNIT_STATE_CASTING))
+ return;
+
+ while (uint32 eventId = _events.ExecuteEvent())
+ {
+ switch (eventId)
+ {
+ case EVENT_RUNIC_BARRIER:
+ Talk(EMOTE_RUNIC_BARRIER);
+ DoCastAOE(SPELL_RUNIC_BARRIER);
+ _events.Repeat(35000, 45000);
+ break;
+ case EVENT_SMASH:
+ DoCastAOE(SPELL_SMASH);
+ _events.Repeat(15000, 18000);
+ break;
+ case EVENT_RUNIC_CHARGE:
+ {
+ Unit* referer = me;
+ if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, [referer](Unit* unit){ return unit->GetTypeId() == TYPEID_PLAYER && unit->IsInRange(referer, 8.0f, 40.0f); }))
+ DoCast(target, SPELL_RUNIC_CHARGE);
+ _events.Repeat(20000);
+ break;
+ }
+ case EVENT_RUNIC_SMASH:
+ DoCast(me, RAND(SPELL_RUNIC_SMASH_LEFT, SPELL_RUNIC_SMASH_RIGHT));
+ _events.Repeat(6000);
+ break;
+ default:
+ break;
+ }
+
+ if (me->HasUnitState(UNIT_STATE_CASTING))
+ return;
+ }
+
+ if (!UpdateVictim())
+ return;
+
+ DoMeleeAttackIfReady();
+ }
+
+ private:
+ bool _runicActive;
+ };
+
+ CreatureAI* GetAI(Creature* creature) const override
+ {
+ return GetUlduarAI<npc_runic_colossusAI>(creature);
+ }
+};
+
+class npc_ancient_rune_giant : public CreatureScript
+{
+ public:
+ npc_ancient_rune_giant() : CreatureScript("npc_ancient_rune_giant") { }
+
+ struct npc_ancient_rune_giantAI : public npc_thorim_minibossAI
+ {
+ npc_ancient_rune_giantAI(Creature* creature) : npc_thorim_minibossAI(creature) { }
+
+ void Reset() override
+ {
+ _events.Reset();
+
+ // close the Stone Door
+ _instance->HandleGameObject(_instance->GetGuidData(DATA_STONE_DOOR), false);
+
+ // Spawn trashes
+ _summons.DespawnAll();
+ for (SummonLocation const& s : GiantAddLocations)
+ me->SummonCreature(s.entry, s.pos, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 3000);
+ }
+
+ void EnterCombat(Unit* /*who*/) override
+ {
+ DoZoneInCombat();
+ _events.Reset();
+ _events.ScheduleEvent(EVENT_RUNIC_FORTIFICATION, 1);
+ _events.ScheduleEvent(EVENT_STOMP, urand(10000, 12000));
+ _events.ScheduleEvent(EVENT_RUNE_DETONATION, 25000);
+ }
+
+ void JustDied(Unit* /*victim*/) override
+ {
+ // opem the Stone Door
+ _instance->HandleGameObject(_instance->GetGuidData(DATA_STONE_DOOR), true);
+ }
+
+ void UpdateAI(uint32 diff) override
+ {
+ if (!UpdateVictim())
+ return;
+
+ _events.Update(diff);
+
+ if (me->HasUnitState(UNIT_STATE_CASTING))
+ return;
+
+ while (uint32 eventId = _events.ExecuteEvent())
+ {
+ switch (eventId)
+ {
+ case EVENT_RUNIC_FORTIFICATION:
+ Talk(EMOTE_RUNIC_MIGHT);
+ DoCastAOE(SPELL_RUNIC_FORTIFICATION);
+ break;
+ case EVENT_STOMP:
+ DoCastAOE(SPELL_STOMP);
+ _events.Repeat(10000, 12000);
+ break;
+ case EVENT_RUNE_DETONATION:
+ if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 60.0f, true))
+ DoCast(target, SPELL_RUNE_DETONATION);
+ _events.Repeat(10000, 12000);
+ break;
+ default:
+ break;
+ }
+
+ if (me->HasUnitState(UNIT_STATE_CASTING))
+ return;
+ }
+
+ DoMeleeAttackIfReady();
+ }
+ };
+
+ CreatureAI* GetAI(Creature* creature) const override
+ {
+ return GetUlduarAI<npc_ancient_rune_giantAI>(creature);
+ }
+};
+
+class npc_sif : public CreatureScript
+{
+ public:
+ npc_sif() : CreatureScript("npc_sif") { }
+
+ struct npc_sifAI : public ScriptedAI
+ {
+ npc_sifAI(Creature* creature) : ScriptedAI(creature)
+ {
+ SetCombatMovement(false);
+ _instance = creature->GetInstanceScript();
+ }
+
+ void Reset() override
+ {
+ _events.Reset();
+ }
+
+ void SpellHit(Unit* /*caster*/, SpellInfo const* spellInfo) override
+ {
+ if (spellInfo->Id == SPELL_STORMHAMMER_SIF)
+ {
+ me->InterruptSpell(CURRENT_GENERIC_SPELL);
+ me->SetReactState(REACT_PASSIVE);
+ me->AttackStop();
+ }
+ }
+
+ void DoAction(int32 action) override
+ {
+ if (action == ACTION_START_HARD_MODE)
+ {
+ me->SetReactState(REACT_AGGRESSIVE);
+ DoZoneInCombat(me, 250.0f);
+ Talk(SAY_SIF_EVENT);
+ _events.Reset();
+ _events.ScheduleEvent(EVENT_FROSTBOLT, 2000);
+ _events.ScheduleEvent(EVENT_FROSTBOLT_VOLLEY, 15000);
+ _events.ScheduleEvent(EVENT_BLINK, urand(20000, 25000));
+ _events.ScheduleEvent(EVENT_BLIZZARD, 30000);
+ }
+ }
+
+ void UpdateAI(uint32 diff) override
+ {
+ if (!UpdateVictim())
+ return;
+
+ _events.Update(diff);
+
+ if (me->HasUnitState(UNIT_STATE_CASTING))
+ return;
+
+ while (uint32 eventId = _events.ExecuteEvent())
+ {
+ switch (eventId)
+ {
+ case EVENT_BLINK:
+ if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100.0f, true))
+ DoCast(target, SPELL_BLINK);
+ _events.ScheduleEvent(EVENT_FROST_NOVA, 0);
+ _events.Repeat(20000, 25000);
+ return;
+ case EVENT_FROST_NOVA:
+ DoCastAOE(SPELL_FROSTNOVA);
+ return;
+ case EVENT_FROSTBOLT:
+ if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100.0f, true))
+ DoCast(target, SPELL_FROSTBOLT);
+ _events.Repeat(2000);
+ return;
+ case EVENT_FROSTBOLT_VOLLEY:
+ DoCastAOE(SPELL_FROSTBOLT_VOLLEY);
+ _events.Repeat(15000, 20000);
+ return;
+ case EVENT_BLIZZARD:
+ DoCastAOE(SPELL_BLIZZARD);
+ _events.Repeat(35000, 45000);
+ return;
+ default:
+ break;
+ }
+
+ if (me->HasUnitState(UNIT_STATE_CASTING))
+ return;
+ }
+
+ // no melee attack
+ }
+
+ private:
+ EventMap _events;
+ InstanceScript* _instance;
+ };
+
+ CreatureAI* GetAI(Creature* creature) const override
+ {
+ return GetUlduarAI<npc_sifAI>(creature);
+ }
+};
+
+// 62576 - Blizzard
+// 62602 - Blizzard
+class spell_thorim_blizzard_effect : public SpellScriptLoader
+{
+ public:
+ spell_thorim_blizzard_effect() : SpellScriptLoader("spell_thorim_blizzard_effect") { }
+
+ class spell_thorim_blizzard_effect_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_thorim_blizzard_effect_AuraScript);
+
+ bool CheckAreaTarget(Unit* target)
+ {
+ /// @todo: fix this for all dynobj auras
+ if (target != GetOwner())
+ {
+ // check if not stacking aura already on target
+ // this one prevents overriding auras periodically by 2 near area aura owners
+ Unit::AuraApplicationMap const& auraMap = target->GetAppliedAuras();
+ for (Unit::AuraApplicationMap::const_iterator iter = auraMap.begin(); iter != auraMap.end(); ++iter)
+ {
+ Aura const* aura = iter->second->GetBase();
+ if (GetId() == aura->GetId() && GetOwner() != aura->GetOwner() /*!GetAura()->CanStackWith(aura)*/)
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ void Register() override
+ {
+ DoCheckAreaTarget += AuraCheckAreaTargetFn(spell_thorim_blizzard_effect_AuraScript::CheckAreaTarget);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_thorim_blizzard_effect_AuraScript();
+ }
+};
+
+// 62580, 62604 - Frostbolt Volley
+class spell_thorim_frostbolt_volley : public SpellScriptLoader
+{
+ public:
+ spell_thorim_frostbolt_volley() : SpellScriptLoader("spell_thorim_frostbolt_volley") { }
+
+ class spell_thorim_frostbolt_volley_SpellScript : public SpellScript
+ {
+ PrepareSpellScript(spell_thorim_frostbolt_volley_SpellScript);
+
+ void FilterTargets(std::list<WorldObject*>& unitList)
+ {
+ unitList.remove_if([](WorldObject* target)
+ {
+ return target->GetTypeId() != TYPEID_PLAYER && (target->GetTypeId() != TYPEID_UNIT || !target->ToUnit()->IsPet());
+ });
+ }
+
+ void Register() override
+ {
+ OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_thorim_frostbolt_volley_SpellScript::FilterTargets, EFFECT_ALL, TARGET_UNIT_SRC_AREA_ENEMY);
+ }
+ };
+
+ SpellScript* GetSpellScript() const override
+ {
+ return new spell_thorim_frostbolt_volley_SpellScript();
+ }
+};
+
+// 62016 - Charge Orb
+class spell_thorim_charge_orb : public SpellScriptLoader
+{
+ public:
+ spell_thorim_charge_orb() : SpellScriptLoader("spell_thorim_charge_orb") { }
+
+ class spell_thorim_charge_orb_SpellScript : public SpellScript
+ {
+ PrepareSpellScript(spell_thorim_charge_orb_SpellScript);
+
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ return ValidateSpellInfo({ SPELL_LIGHTNING_PILLAR_1 });
+ }
+
+ void FilterTargets(std::list<WorldObject*>& targets)
+ {
+ targets.remove_if(HeightPositionCheck(false));
+
+ if (targets.empty())
+ return;
+
+ WorldObject* target = Trinity::Containers::SelectRandomContainerElement(targets);
+ targets.clear();
+ targets.push_back(target);
+ }
+
+ void HandleScript()
+ {
+ if (Unit* target = GetHitUnit())
+ target->CastSpell((Unit*)nullptr, SPELL_LIGHTNING_PILLAR_1, true);
+ }
+
+ void Register() override
+ {
+ OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_thorim_charge_orb_SpellScript::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENTRY);
+ AfterHit += SpellHitFn(spell_thorim_charge_orb_SpellScript::HandleScript);
+ }
+ };
+
+ SpellScript* GetSpellScript() const override
+ {
+ return new spell_thorim_charge_orb_SpellScript();
+ }
+};
+
+// 62466 - Lightning Charge
+class spell_thorim_lightning_charge : public SpellScriptLoader
+{
+ public:
+ spell_thorim_lightning_charge() : SpellScriptLoader("spell_thorim_lightning_charge") { }
+
+ class spell_thorim_lightning_charge_SpellScript : public SpellScript
+ {
+ PrepareSpellScript(spell_thorim_lightning_charge_SpellScript);
+
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ return ValidateSpellInfo({ SPELL_LIGHTNING_CHARGE });
+ }
+
+ void HandleFocus()
+ {
+ /// @workaround: focus target is not working because spell is triggered and instant
+ if (Creature* creature = GetCaster()->ToCreature())
+ creature->FocusTarget(GetSpell(), GetExplTargetWorldObject());
+ }
+
+ void HandleCharge()
+ {
+ GetCaster()->CastSpell(GetCaster(), SPELL_LIGHTNING_CHARGE);
+ }
+
+ void Register() override
+ {
+ BeforeCast += SpellCastFn(spell_thorim_lightning_charge_SpellScript::HandleFocus);
+ AfterCast += SpellCastFn(spell_thorim_lightning_charge_SpellScript::HandleCharge);
+ }
+ };
+
+ SpellScript* GetSpellScript() const override
+ {
+ return new spell_thorim_lightning_charge_SpellScript();
+ }
+};
+
+// 61934 - Leap
+class spell_thorim_arena_leap : public SpellScriptLoader
+{
+ public:
+ spell_thorim_arena_leap() : SpellScriptLoader("spell_thorim_arena_leap") { }
+
+ class spell_thorim_arena_leap_SpellScript : public SpellScript
+ {
+ PrepareSpellScript(spell_thorim_arena_leap_SpellScript);
+
+ bool Load() override
+ {
+ return GetCaster()->GetTypeId() == TYPEID_UNIT;
+ }
+
+ void HandleScript(SpellEffIndex /*effIndex*/)
+ {
+ if (Position const* pos = GetHitDest())
+ GetCaster()->ToCreature()->SetHomePosition(*pos);
+ }
+
+ void Register() override
+ {
+ OnEffectLaunch += SpellEffectFn(spell_thorim_arena_leap_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_JUMP_DEST);
+ }
+ };
+
+ SpellScript* GetSpellScript() const override
+ {
+ return new spell_thorim_arena_leap_SpellScript();
+ }
+};
+
+struct OutOfArenaCheck
+{
+ bool operator()(Position const* who) const
+ {
+ return !CreatureAI::IsInBounds(ArenaBoundaries, who);
+ }
+};
+
+// 62042 - Stormhammer
+class spell_thorim_stormhammer : public SpellScriptLoader
+{
+ public:
+ spell_thorim_stormhammer() : SpellScriptLoader("spell_thorim_stormhammer") { }
+
+ class spell_thorim_stormhammer_SpellScript : public SpellScript
+ {
+ PrepareSpellScript(spell_thorim_stormhammer_SpellScript);
+
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ return ValidateSpellInfo(
+ {
+ SPELL_STORMHAMMER_BOOMERANG,
+ SPELL_DEAFENING_THUNDER
+ });
+ }
+
+ void FilterTargets(std::list<WorldObject*>& targets)
+ {
+ targets.remove_if([](WorldObject* target) -> bool { return HeightPositionCheck(true)(target) || OutOfArenaCheck()(target); });
+
+ if (targets.empty())
+ {
+ FinishCast(SPELL_FAILED_NO_VALID_TARGETS);
+ return;
+ }
+
+ WorldObject* target = Trinity::Containers::SelectRandomContainerElement(targets);
+ targets.clear();
+ targets.push_back(target);
+ }
+
+ void HandleScript(SpellEffIndex /*effIndex*/)
+ {
+ if (Unit* target = GetHitUnit())
+ {
+ target->CastSpell(target, SPELL_DEAFENING_THUNDER, true);
+ target->CastSpell(GetCaster(), SPELL_STORMHAMMER_BOOMERANG, true);
+ }
+ }
+
+ void LoseHammer()
+ {
+ GetCaster()->SetVirtualItem(0, 0);
+ }
+
+ void Register() override
+ {
+ OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_thorim_stormhammer_SpellScript::FilterTargets, EFFECT_ALL, TARGET_UNIT_SRC_AREA_ENEMY);
+ AfterCast += SpellCastFn(spell_thorim_stormhammer_SpellScript::LoseHammer);
+ OnEffectHitTarget += SpellEffectFn(spell_thorim_stormhammer_SpellScript::HandleScript, EFFECT_2, SPELL_EFFECT_SCRIPT_EFFECT);
+ }
+ };
+
+ SpellScript* GetSpellScript() const override
+ {
+ return new spell_thorim_stormhammer_SpellScript();
+ }
+};
+
+// 64767 - Stormhammer
+class spell_thorim_stormhammer_sif : public SpellScriptLoader
+{
+ public:
+ spell_thorim_stormhammer_sif() : SpellScriptLoader("spell_thorim_stormhammer_sif") { }
+
+ class spell_thorim_stormhammer_sif_SpellScript : public SpellScript
+ {
+ PrepareSpellScript(spell_thorim_stormhammer_sif_SpellScript);
+
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ return ValidateSpellInfo(
+ {
+ SPELL_STORMHAMMER_BOOMERANG,
+ SPELL_SIF_TRANSFORM
+ });
+ }
+
+ void HandleScript(SpellEffIndex /*effIndex*/)
+ {
+ if (Unit* target = GetHitUnit())
+ {
+ target->CastSpell(GetCaster(), SPELL_STORMHAMMER_BOOMERANG, true);
+ target->CastSpell(target, SPELL_SIF_TRANSFORM, true);
+ }
+ }
+
+ void LoseHammer()
+ {
+ GetCaster()->SetVirtualItem(0, 0);
+ }
+
+ void Register() override
+ {
+ AfterCast += SpellCastFn(spell_thorim_stormhammer_sif_SpellScript::LoseHammer);
+ OnEffectHitTarget += SpellEffectFn(spell_thorim_stormhammer_sif_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT);
+ }
+ };
+
+ SpellScript* GetSpellScript() const override
+ {
+ return new spell_thorim_stormhammer_sif_SpellScript();
+ }
+};
+
+// 64909 - Stormhammer
+class spell_thorim_stormhammer_boomerang : public SpellScriptLoader
+{
+ public:
+ spell_thorim_stormhammer_boomerang() : SpellScriptLoader("spell_thorim_stormhammer_boomerang") { }
+
+ class spell_thorim_stormhammer_boomerang_SpellScript : public SpellScript
+ {
+ PrepareSpellScript(spell_thorim_stormhammer_boomerang_SpellScript);
+
+ void RecoverHammer(SpellEffIndex /*effIndex*/)
+ {
+ if (Unit* target = GetHitUnit())
+ target->SetVirtualItem(0, THORIM_WEAPON_DISPLAY_ID);
+ }
+
+ void Register() override
+ {
+ OnEffectHitTarget += SpellEffectFn(spell_thorim_stormhammer_boomerang_SpellScript::RecoverHammer, EFFECT_0, SPELL_EFFECT_DUMMY);
+ }
+ };
+
+ SpellScript* GetSpellScript() const override
+ {
+ return new spell_thorim_stormhammer_boomerang_SpellScript();
+ }
+};
+
+// 62057, 62058 - Runic Smash
+class spell_thorim_runic_smash : public SpellScriptLoader
+{
+ public:
+ spell_thorim_runic_smash() : SpellScriptLoader("spell_thorim_runic_smash") { }
+
+ class spell_thorim_runic_smash_SpellScript : public SpellScript
+ {
+ PrepareSpellScript(spell_thorim_runic_smash_SpellScript);
+
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ return ValidateSpellInfo({ SPELL_RUNIC_SMASH });
+ }
+
+ void HandleScript(SpellEffIndex effIndex)
+ {
+ PreventHitDefaultEffect(effIndex);
+
+ std::vector<Creature*> triggers;
+ GetCaster()->GetCreatureListWithEntryInGrid(triggers, GetSpellInfo()->Id == SPELL_RUNIC_SMASH_LEFT ? NPC_GOLEM_LEFT_HAND_BUNNY : NPC_GOLEM_RIGHT_HAND_BUNNY, 150.0f);
+ for (Creature* trigger : triggers)
+ {
+ float dist = GetCaster()->GetExactDist(trigger);
+ trigger->m_Events.AddEvent(new RunicSmashExplosionEvent(trigger), trigger->m_Events.CalculateTime(uint64(dist * 30.f)));
+ };
+ }
+
+ void Register() override
+ {
+ OnEffectHitTarget += SpellEffectFn(spell_thorim_runic_smash_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_TRIGGER_SPELL);
+ }
+ };
+
+ SpellScript* GetSpellScript() const override
+ {
+ return new spell_thorim_runic_smash_SpellScript();
+ }
+};
+
+class UpperOrbCheck
+{
+ public:
+ UpperOrbCheck() : _check(true) { }
+
+ bool operator() (Creature* target) const
+ {
+ return target->GetEntry() == NPC_THUNDER_ORB && _check(target);
+ }
+
+ private:
+ HeightPositionCheck const _check;
+};
+
+// 62184 - Activate Lightning Orb Periodic
+class spell_thorim_activate_lightning_orb_periodic : public SpellScriptLoader
+{
+ public:
+ spell_thorim_activate_lightning_orb_periodic() : SpellScriptLoader("spell_thorim_activate_lightning_orb_periodic") { }
+
+ class spell_thorim_activate_lightning_orb_periodic_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_thorim_activate_lightning_orb_periodic_AuraScript);
+
+ InstanceScript* instance = nullptr;
+
+ void PeriodicTick(AuraEffect const* /*aurEff*/)
+ {
+ PreventDefaultAction();
+
+ Unit* caster = GetCaster();
+ std::vector<Creature*> triggers;
+
+ UpperOrbCheck check;
+ Trinity::CreatureListSearcher<UpperOrbCheck> searcher(caster, triggers, check);
+ Cell::VisitGridObjects(caster, searcher, 100.f);
+
+ if (!triggers.empty())
+ {
+ Creature* target = Trinity::Containers::SelectRandomContainerElement(triggers);
+ if (Creature* thorim = instance->GetCreature(BOSS_THORIM))
+ thorim->AI()->SetGUID(target->GetGUID(), DATA_CHARGED_PILLAR);
+ }
+ }
+
+ bool Load() override
+ {
+ if (Unit* caster = GetCaster())
+ instance = caster->GetInstanceScript();
+
+ return instance != nullptr;
+ }
+
+ void Register() override
+ {
+ OnEffectPeriodic += AuraEffectPeriodicFn(spell_thorim_activate_lightning_orb_periodic_AuraScript::PeriodicTick, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_thorim_activate_lightning_orb_periodic_AuraScript();
+ }
+};
+
+// 62331, 62418 - Impale
+class spell_iron_ring_guard_impale : public SpellScriptLoader
+{
+ public:
+ spell_iron_ring_guard_impale() : SpellScriptLoader("spell_iron_ring_guard_impale") { }
+
+ class spell_iron_ring_guard_impale_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_iron_ring_guard_impale_AuraScript);
+
+ void PeriodicTick(AuraEffect const* /*aurEff*/)
+ {
+ if (GetTarget()->HealthAbovePct(GetSpellInfo()->GetEffect(EFFECT_1)->CalcValue()))
+ {
+ Remove(AURA_REMOVE_BY_ENEMY_SPELL);
+ PreventDefaultAction();
+ }
+ }
+
+ void Register() override
+ {
+ OnEffectPeriodic += AuraEffectPeriodicFn(spell_iron_ring_guard_impale_AuraScript::PeriodicTick, EFFECT_0, SPELL_AURA_PERIODIC_DAMAGE);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_iron_ring_guard_impale_AuraScript();
+ }
+};
+
+class condition_thorim_arena_leap : public ConditionScript
+{
+ public:
+ condition_thorim_arena_leap() : ConditionScript("condition_thorim_arena_leap"), _check(false) { }
+
+ bool OnConditionCheck(Condition const* condition, ConditionSourceInfo& sourceInfo) override
+ {
+ WorldObject* target = sourceInfo.mConditionTargets[condition->ConditionTarget];
+ InstanceScript* instance = target->GetInstanceScript();
+
+ if (!instance)
+ return false;
+
+ return _check(target);
+ }
+
+ private:
+ HeightPositionCheck _check;
+};
+
void AddSC_boss_thorim()
{
new boss_thorim();
+ new npc_thorim_pre_phase();
+ new npc_thorim_arena_phase();
+ new npc_runic_colossus();
+ new npc_ancient_rune_giant();
+ new npc_sif();
+ new spell_thorim_blizzard_effect();
+ new spell_thorim_frostbolt_volley();
+ new spell_thorim_charge_orb();
+ new spell_thorim_lightning_charge();
+ new spell_thorim_stormhammer();
+ new spell_thorim_stormhammer_sif();
+ new spell_thorim_stormhammer_boomerang();
+ new spell_thorim_arena_leap();
+ new spell_thorim_runic_smash();
+ new spell_thorim_activate_lightning_orb_periodic();
+ new spell_iron_ring_guard_impale();
+ new condition_thorim_arena_leap();
}
diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_yogg_saron.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_yogg_saron.cpp
index 2eb507db98c..be43dc8c6cb 100644
--- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_yogg_saron.cpp
+++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_yogg_saron.cpp
@@ -774,7 +774,7 @@ class boss_sara : public CreatureScript
{
me->RemoveAllAuras();
me->SetReactState(REACT_PASSIVE);
- me->SetFaction(35);
+ me->SetFaction(FACTION_FRIENDLY);
_events.Reset();
_events.SetPhase(PHASE_ONE);
}
@@ -817,7 +817,7 @@ class boss_sara : public CreatureScript
case EVENT_TRANSFORM_3:
Talk(SAY_SARA_TRANSFORM_4);
DoCast(me, SPELL_FULL_HEAL);
- me->SetFaction(16);
+ me->SetFaction(FACTION_MONSTER_2);
if (Creature* voice = _instance->GetCreature(DATA_VOICE_OF_YOGG_SARON))
voice->AI()->DoAction(ACTION_PHASE_TWO);
if (Creature* mimiron = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_MIMIRON_YS)))
diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/instance_ulduar.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/instance_ulduar.cpp
index d34a7ac516c..a90efe7bfd8 100644
--- a/src/server/scripts/Northrend/Ulduar/Ulduar/instance_ulduar.cpp
+++ b/src/server/scripts/Northrend/Ulduar/Ulduar/instance_ulduar.cpp
@@ -38,9 +38,9 @@ static BossBoundaryData const boundaries =
{ BOSS_XT002, new RectangleBoundary(755.0f, 940.0f, -125.0f, 95.0f) },
{ BOSS_ASSEMBLY_OF_IRON, new CircleBoundary(Position(1587.2f, 121.0f), 90.0) },
{ BOSS_ALGALON, new CircleBoundary(Position(1632.668f, -307.7656f), 45.0) },
- { BOSS_ALGALON, new ZRangeBoundary(410.0f, 440.0f) },
+ { BOSS_ALGALON, new ZRangeBoundary(410.0f, 470.0f) },
{ BOSS_HODIR, new EllipseBoundary(Position(2001.5f, -240.0f), 50.0, 75.0) },
- { BOSS_THORIM, new CircleBoundary(Position(2134.73f, -263.2f), 50.0) },
+ // Thorim sets boundaries dynamically
{ BOSS_FREYA, new RectangleBoundary(2094.6f, 2520.0f, -250.0f, 200.0f) },
{ BOSS_MIMIRON, new CircleBoundary(Position(2744.0f, 2569.0f), 70.0) },
{ BOSS_VEZAX, new RectangleBoundary(1740.0f, 1930.0f, 31.0f, 228.0f) },
@@ -59,6 +59,11 @@ static DoorData const doorData[] =
{ GO_MIMIRON_DOOR_1, BOSS_MIMIRON, DOOR_TYPE_ROOM },
{ GO_MIMIRON_DOOR_2, BOSS_MIMIRON, DOOR_TYPE_ROOM },
{ GO_MIMIRON_DOOR_3, BOSS_MIMIRON, DOOR_TYPE_ROOM },
+ { GO_THORIM_ENCOUNTER_DOOR, BOSS_THORIM, DOOR_TYPE_ROOM },
+ { GO_ANCIENT_GATE_OF_THE_KEEPERS, BOSS_HODIR, DOOR_TYPE_PASSAGE },
+ { GO_ANCIENT_GATE_OF_THE_KEEPERS, BOSS_MIMIRON, DOOR_TYPE_PASSAGE },
+ { GO_ANCIENT_GATE_OF_THE_KEEPERS, BOSS_THORIM, DOOR_TYPE_PASSAGE },
+ { GO_ANCIENT_GATE_OF_THE_KEEPERS, BOSS_FREYA, DOOR_TYPE_PASSAGE },
{ GO_VEZAX_DOOR, BOSS_VEZAX, DOOR_TYPE_PASSAGE },
{ GO_YOGG_SARON_DOOR, BOSS_YOGG_SARON, DOOR_TYPE_ROOM },
{ GO_DOODAD_UL_SIGILDOOR_03, BOSS_ALGALON, DOOR_TYPE_ROOM },
@@ -95,6 +100,10 @@ ObjectData const creatureData[] =
{ NPC_EXPEDITION_COMMANDER, DATA_EXPEDITION_COMMANDER },
{ NPC_RAZORSCALE_CONTROLLER, DATA_RAZORSCALE_CONTROL },
+ { NPC_SIF, DATA_SIF },
+ { NPC_RUNIC_COLOSSUS, DATA_RUNIC_COLOSSUS },
+ { NPC_RUNE_GIANT, DATA_RUNE_GIANT },
+ { NPC_THORIM_CONTROLLER, DATA_THORIM_CONTROLLER },
{ NPC_COMPUTER, DATA_COMPUTER },
{ NPC_WORLD_TRIGGER_MIMIRON, DATA_MIMIRON_WORLD_TRIGGER },
{ NPC_VOICE_OF_YOGG_SARON, DATA_VOICE_OF_YOGG_SARON },
@@ -118,6 +127,9 @@ ObjectData const objectData[] =
{ GO_RAZOR_HARPOON_2, GO_RAZOR_HARPOON_2 },
{ GO_RAZOR_HARPOON_3, GO_RAZOR_HARPOON_3 },
{ GO_RAZOR_HARPOON_4, GO_RAZOR_HARPOON_4 },
+ { GO_THORIM_LEVER, DATA_THORIM_LEVER },
+ { GO_THORIM_STONE_DOOR, DATA_STONE_DOOR },
+ { GO_THORIM_RUNIC_DOOR, DATA_RUNIC_DOOR },
{ 0, 0 }
};
@@ -173,7 +185,9 @@ class instance_ulduar : public InstanceMapScript
ObjectGuid LeviathanGateGUID;
ObjectGuid KologarnChestGUID;
ObjectGuid KologarnBridgeGUID;
- ObjectGuid ThorimChestGUID;
+ ObjectGuid ThorimDarkIronPortcullisGUID;
+ ObjectGuid CacheOfStormsGUID;
+ ObjectGuid CacheOfStormsHardmodeGUID;
ObjectGuid HodirRareCacheGUID;
ObjectGuid HodirChestGUID;
ObjectGuid MimironTramGUID;
@@ -330,6 +344,16 @@ class instance_ulduar : public InstanceMapScript
creature->UpdateEntry(NPC_BATTLE_PRIEST_GINA);
break;
+ // Thorim
+ case NPC_MERCENARY_CAPTAIN_H:
+ if (TeamInInstance == HORDE)
+ creature->UpdateEntry(NPC_MERCENARY_CAPTAIN_A);
+ break;
+ case NPC_MERCENARY_SOLDIER_H:
+ if (TeamInInstance == HORDE)
+ creature->UpdateEntry(NPC_MERCENARY_SOLDIER_A);
+ break;
+
// Freya
case NPC_IRONBRANCH:
ElderGUIDs[0] = creature->GetGUID();
@@ -447,9 +471,16 @@ class instance_ulduar : public InstanceMapScript
if (GetBossState(BOSS_KOLOGARN) == DONE)
HandleGameObject(ObjectGuid::Empty, false, gameObject);
break;
- case GO_THORIM_CHEST_HERO:
- case GO_THORIM_CHEST:
- ThorimChestGUID = gameObject->GetGUID();
+ case GO_THORIM_DARK_IRON_PORTCULLIS:
+ ThorimDarkIronPortcullisGUID = gameObject->GetGUID();
+ break;
+ case GO_CACHE_OF_STORMS_10:
+ case GO_CACHE_OF_STORMS_25:
+ CacheOfStormsGUID = gameObject->GetGUID();
+ break;
+ case GO_CACHE_OF_STORMS_HARDMODE_10:
+ case GO_CACHE_OF_STORMS_HARDMODE_25:
+ CacheOfStormsHardmodeGUID = gameObject->GetGUID();
break;
case GO_HODIR_RARE_CACHE_OF_WINTER_HERO:
case GO_HODIR_RARE_CACHE_OF_WINTER:
@@ -656,11 +687,25 @@ class instance_ulduar : public InstanceMapScript
case BOSS_THORIM:
if (state == DONE)
{
- if (GameObject* gameObject = instance->GetGameObject(ThorimChestGUID))
- gameObject->SetRespawnTime(gameObject->GetRespawnDelay());
+ if (Creature* thorim = GetCreature(BOSS_THORIM))
+ {
+ if (GameObject* cache = instance->GetGameObject(thorim->AI()->GetData(DATA_THORIM_HARDMODE) ? CacheOfStormsHardmodeGUID : CacheOfStormsGUID))
+ {
+ cache->SetLootRecipient(thorim->GetLootRecipient());
+ cache->SetRespawnTime(cache->GetRespawnDelay());
+ cache->RemoveFlag(GO_FLAG_LOCKED);
+ cache->RemoveFlag(GO_FLAG_NOT_SELECTABLE);
+ cache->RemoveFlag(GO_FLAG_NODESPAWN);
+ }
+ }
instance->SummonCreature(NPC_THORIM_OBSERVATION_RING, ObservationRingKeepersPos[2]);
}
+ else
+ {
+ DoCloseDoorOrButton(GetGuidData(DATA_THORIM_LEVER));
+ DoCloseDoorOrButton(ThorimDarkIronPortcullisGUID);
+ }
break;
case BOSS_ALGALON:
if (state == DONE)
diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/ulduar.h b/src/server/scripts/Northrend/Ulduar/Ulduar/ulduar.h
index a26b699b396..885686e6fc6 100644
--- a/src/server/scripts/Northrend/Ulduar/Ulduar/ulduar.h
+++ b/src/server/scripts/Northrend/Ulduar/Ulduar/ulduar.h
@@ -157,6 +157,31 @@ enum UlduarNPCs
// Freya Achievement Trigger
NPC_FREYA_ACHIEVE_TRIGGER = 33406,
+ // Thorim
+ NPC_THORIM_INVISIBLE_STALKER = 32780,
+ NPC_JORMUNGAR_BEHEMOTH = 32882,
+ NPC_MERCENARY_CAPTAIN_A = 32908,
+ NPC_MERCENARY_CAPTAIN_H = 32907,
+ NPC_MERCENARY_SOLDIER_A = 32885,
+ NPC_MERCENARY_SOLDIER_H = 32883,
+ NPC_DARK_RUNE_ACOLYTE_PRE = 32886,
+ NPC_RUNIC_COLOSSUS = 32872,
+ NPC_RUNE_GIANT = 32873,
+ NPC_IRON_RING_GUARD = 32874,
+ NPC_IRON_HONOR_GUARD = 32875,
+ NPC_DARK_RUNE_CHAMPION = 32876,
+ NPC_DARK_RUNE_WARBRINGER = 32877,
+ NPC_DARK_RUNE_EVOKER = 32878,
+ NPC_DARK_RUNE_COMMONER = 32904,
+ NPC_DARK_RUNE_ACOLYTE = 33110,
+ NPC_THORIM_EVENT_BUNNY = 32892,
+ NPC_LIGHTNING_ORB = 33138,
+ NPC_GOLEM_RIGHT_HAND_BUNNY = 33140,
+ NPC_GOLEM_LEFT_HAND_BUNNY = 33141,
+ NPC_SIF = 33196,
+ NPC_THUNDER_ORB = 33378,
+ NPC_THORIM_CONTROLLER = 32879,
+
// Yogg-Saron
NPC_SARA = 33134,
NPC_GUARDIAN_OF_YOGG_SARON = 33136,
@@ -231,6 +256,8 @@ enum UlduarGameObjects
GO_KOLOGARN_BRIDGE = 194232,
GO_KOLOGARN_DOOR = 194553,
+ GO_ANCIENT_GATE_OF_THE_KEEPERS = 194255,
+
// Hodir
GO_HODIR_ENTRANCE = 194442,
GO_HODIR_DOOR = 194634,
@@ -241,8 +268,15 @@ enum UlduarGameObjects
GO_HODIR_CHEST = 194307,
// Thorim
- GO_THORIM_CHEST_HERO = 194315,
- GO_THORIM_CHEST = 194314,
+ GO_CACHE_OF_STORMS_10 = 194312,
+ GO_CACHE_OF_STORMS_HARDMODE_10 = 194313,
+ GO_CACHE_OF_STORMS_25 = 194315,
+ GO_CACHE_OF_STORMS_HARDMODE_25 = 194314,
+ GO_THORIM_RUNIC_DOOR = 194557,
+ GO_THORIM_STONE_DOOR = 194558,
+ GO_THORIM_ENCOUNTER_DOOR = 194559,
+ GO_THORIM_LEVER = 194264,
+ GO_THORIM_DARK_IRON_PORTCULLIS = 194560,
// Mimiron
GO_MIMIRON_TRAM = 194675,
@@ -407,6 +441,16 @@ enum UlduarData
DATA_ALGALON_TRAPDOOR,
DATA_BRANN_BRONZEBEARD_ALG,
+ // Thorim
+ DATA_SIF,
+ DATA_THORIM_LEVER,
+ DATA_RUNIC_COLOSSUS,
+ DATA_RUNE_GIANT,
+ DATA_RUNIC_DOOR,
+ DATA_STONE_DOOR,
+ DATA_THORIM_HARDMODE,
+ DATA_THORIM_CONTROLLER,
+
// Misc
DATA_BRANN_BRONZEBEARD_INTRO,
DATA_LORE_KEEPER_OF_NORGANNON,
@@ -423,10 +467,15 @@ enum UlduarWorldStates
enum UlduarAchievementData
{
// FL Achievement boolean
- DATA_UNBROKEN = 29052906, // 2905, 2906 are achievement IDs,
+ DATA_UNBROKEN = 29052906, // 2905, 2906 are achievement IDs,
MAX_HERALD_ARMOR_ITEMLEVEL = 226,
- MAX_HERALD_WEAPON_ITEMLEVEL = 232,
- SPELL_LUMBERJACKED_CREDIT = 65296
+ MAX_HERALD_WEAPON_ITEMLEVEL = 232
+};
+
+enum UlduarSharedSpells
+{
+ SPELL_LUMBERJACKED_CREDIT = 65296,
+ SPELL_TELEPORT_KEEPER_VISUAL = 62940 // used by keepers
};
enum UlduarEvents
@@ -445,6 +494,23 @@ enum YoggSaronIllusions
STORMWIND_ILLUSION = 2,
};
+class KeeperDespawnEvent : public BasicEvent
+{
+public:
+ KeeperDespawnEvent(Creature* owner, uint32 despawnTimerOffset = 500) : _owner(owner), _despawnTimer(despawnTimerOffset) { }
+
+ bool Execute(uint64 /*eventTime*/, uint32 /*updateTime*/) override
+ {
+ _owner->CastSpell(_owner, SPELL_TELEPORT_KEEPER_VISUAL);
+ _owner->DespawnOrUnsummon(1000 + _despawnTimer);
+ return true;
+ }
+
+private:
+ Creature* _owner;
+ uint32 _despawnTimer;
+};
+
template<typename AI, typename T>
inline AI* GetUlduarAI(T* obj)
{
diff --git a/src/server/scripts/Northrend/VaultOfArchavon/boss_toravon.cpp b/src/server/scripts/Northrend/VaultOfArchavon/boss_toravon.cpp
index 5b9ab19fb86..ae9d06e9e5d 100644
--- a/src/server/scripts/Northrend/VaultOfArchavon/boss_toravon.cpp
+++ b/src/server/scripts/Northrend/VaultOfArchavon/boss_toravon.cpp
@@ -277,7 +277,7 @@ class npc_frozen_orb_stalker : public CreatureScript
{
Position pos;
me->GetNearPoint(toravon, pos.m_positionX, pos.m_positionY, pos.m_positionZ, 0.0f, 10.0f, 0.0f);
- me->SetPosition(pos);
+ me->UpdatePosition(pos);
DoCast(me, SPELL_FROZEN_ORB_SUMMON);
}
}
diff --git a/src/server/scripts/Northrend/VioletHold/boss_ichoron.cpp b/src/server/scripts/Northrend/VioletHold/boss_ichoron.cpp
index 042b8dad906..8d7231d2ea3 100644
--- a/src/server/scripts/Northrend/VioletHold/boss_ichoron.cpp
+++ b/src/server/scripts/Northrend/VioletHold/boss_ichoron.cpp
@@ -243,7 +243,7 @@ class npc_ichor_globule : public CreatureScript
struct npc_ichor_globuleAI : public ScriptedAI
{
- npc_ichor_globuleAI(Creature* creature) : ScriptedAI(creature)
+ npc_ichor_globuleAI(Creature* creature) : ScriptedAI(creature), _splashTriggered(false)
{
_instance = creature->GetInstanceScript();
creature->SetReactState(REACT_PASSIVE);
@@ -275,14 +275,21 @@ class npc_ichor_globule : public CreatureScript
// this feature should be still implemented
void DamageTaken(Unit* /*attacker*/, uint32& damage) override
{
+ if (_splashTriggered)
+ return;
+
if (damage >= me->GetHealth())
+ {
+ _splashTriggered = true;
DoCastAOE(SPELL_SPLASH);
+ }
}
void UpdateAI(uint32 /*diff*/) override { }
private:
InstanceScript* _instance;
+ bool _splashTriggered;
};
CreatureAI* GetAI(Creature* creature) const override
diff --git a/src/server/scripts/Northrend/northrend_script_loader.cpp b/src/server/scripts/Northrend/northrend_script_loader.cpp
index 934d29e61b6..57bd641591c 100644
--- a/src/server/scripts/Northrend/northrend_script_loader.cpp
+++ b/src/server/scripts/Northrend/northrend_script_loader.cpp
@@ -110,6 +110,7 @@ void AddSC_boss_general_vezax();
void AddSC_boss_mimiron();
void AddSC_boss_hodir();
void AddSC_boss_freya();
+void AddSC_boss_thorim();
void AddSC_boss_yogg_saron();
void AddSC_boss_algalon_the_observer();
void AddSC_instance_ulduar();
@@ -291,6 +292,7 @@ void AddNorthrendScripts()
AddSC_boss_mimiron();
AddSC_boss_hodir();
AddSC_boss_freya();
+ AddSC_boss_thorim();
AddSC_boss_yogg_saron();
AddSC_boss_algalon_the_observer();
AddSC_instance_ulduar();
diff --git a/src/server/scripts/Northrend/zone_borean_tundra.cpp b/src/server/scripts/Northrend/zone_borean_tundra.cpp
index b14038431ad..b487d7fc6e1 100644
--- a/src/server/scripts/Northrend/zone_borean_tundra.cpp
+++ b/src/server/scripts/Northrend/zone_borean_tundra.cpp
@@ -119,7 +119,7 @@ public:
DoCast(me, SPELL_EXPLODE_CART, true);
DoCast(me, SPELL_SUMMON_CART, true);
if (GameObject* cart = me->FindNearestGameObject(GO_EXPLOSIVES_CART, 3.0f))
- cart->SetFaction(14);
+ cart->SetFaction(FACTION_MONSTER);
phaseTimer = 3000;
phase = 2;
break;
@@ -557,9 +557,6 @@ enum Lurgglbr
GO_CAGE = 187369,
- FACTION_ESCORTEE_A = 774,
- FACTION_ESCORTEE_H = 775,
-
SAY_START_1 = 0,
SAY_START_2 = 1,
SAY_END_1 = 2,
@@ -681,11 +678,11 @@ public:
switch (player->GetTeam())
{
case ALLIANCE:
- me->SetFaction(FACTION_ESCORTEE_A);
+ me->SetFaction(FACTION_ESCORTEE_A_PASSIVE);
break;
default:
case HORDE:
- me->SetFaction(FACTION_ESCORTEE_H);
+ me->SetFaction(FACTION_ESCORTEE_H_PASSIVE);
break;
}
}
@@ -1690,10 +1687,10 @@ public:
switch (player->GetTeam())
{
case ALLIANCE:
- me->SetFaction(FACTION_ESCORTEE_A);
+ me->SetFaction(FACTION_ESCORTEE_A_PASSIVE);
break;
case HORDE:
- me->SetFaction(FACTION_ESCORTEE_H);
+ me->SetFaction(FACTION_ESCORTEE_H_PASSIVE);
break;
}
me->SetStandState(UNIT_STAND_STATE_STAND);
diff --git a/src/server/scripts/Northrend/zone_dragonblight.cpp b/src/server/scripts/Northrend/zone_dragonblight.cpp
index 5c7df86b6a4..9c3f455bc41 100644
--- a/src/server/scripts/Northrend/zone_dragonblight.cpp
+++ b/src/server/scripts/Northrend/zone_dragonblight.cpp
@@ -379,9 +379,7 @@ enum StrengthenAncientsMisc
SPELL_CREATE_ITEM_BARK = 47550,
SPELL_CONFUSED = 47044,
- NPC_LOTHALOR = 26321,
-
- FACTION_WALKER_ENEMY = 14,
+ NPC_LOTHALOR = 26321
};
class spell_q12096_q12092_dummy : public SpellScriptLoader // Strengthen the Ancients: On Interact Dummy to Woodlands Walker
@@ -414,7 +412,7 @@ public:
else if (roll == 0) // enemy version
{
tree->AI()->Talk(SAY_WALKER_ENEMY, player);
- tree->SetFaction(FACTION_WALKER_ENEMY);
+ tree->SetFaction(FACTION_MONSTER);
tree->Attack(player, true);
}
}
diff --git a/src/server/scripts/Northrend/zone_grizzly_hills.cpp b/src/server/scripts/Northrend/zone_grizzly_hills.cpp
index d5c06855cff..bfb90373474 100644
--- a/src/server/scripts/Northrend/zone_grizzly_hills.cpp
+++ b/src/server/scripts/Northrend/zone_grizzly_hills.cpp
@@ -103,7 +103,7 @@ public:
Talk(SAY_WORGRAGGRO3);
if (Creature* RWORG = me->SummonCreature(NPC_RAVENOUS_WORG, me->GetPositionX()+10, me->GetPositionY()+8, me->GetPositionZ()+2, 3.229f, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, 120000))
{
- RWORG->SetFaction(35);
+ RWORG->SetFaction(FACTION_FRIENDLY);
_RavenousworgGUID = RWORG->GetGUID();
}
break;
@@ -136,7 +136,7 @@ public:
{
RWORG->Kill(Mrfloppy);
Mrfloppy->ExitVehicle();
- RWORG->SetFaction(14);
+ RWORG->SetFaction(FACTION_MONSTER);
RWORG->GetMotionMaster()->MovePoint(0, RWORG->GetPositionX()+10, RWORG->GetPositionY()+80, RWORG->GetPositionZ());
Talk(SAY_VICTORY2);
}
diff --git a/src/server/scripts/Northrend/zone_howling_fjord.cpp b/src/server/scripts/Northrend/zone_howling_fjord.cpp
index cab2d03b29c..1989b424679 100644
--- a/src/server/scripts/Northrend/zone_howling_fjord.cpp
+++ b/src/server/scripts/Northrend/zone_howling_fjord.cpp
@@ -43,7 +43,6 @@ EndContentData */
enum Entries
{
NPC_APOTHECARY_HANES = 23784,
- FACTION_ESCORTEE_H = 775,
QUEST_TRAIL_OF_FIRE = 11241,
SPELL_HEALING_POTION = 17534,
@@ -155,7 +154,7 @@ public:
break;
case EVENT_START_ESCORT:
events.Reset();
- me->SetFaction(FACTION_ESCORTEE_H);
+ me->SetFaction(FACTION_ESCORTEE_H_PASSIVE);
me->SetReactState(REACT_AGGRESSIVE);
ENSURE_AI(npc_escortAI, (me->AI()))->Start(true, true, _player);
break;
diff --git a/src/server/scripts/Northrend/zone_icecrown.cpp b/src/server/scripts/Northrend/zone_icecrown.cpp
index 8adbd37d884..bf4caf3128f 100644
--- a/src/server/scripts/Northrend/zone_icecrown.cpp
+++ b/src/server/scripts/Northrend/zone_icecrown.cpp
@@ -47,7 +47,7 @@ public:
{
Initialize();
creature->GetMotionMaster()->MovePoint(0, 8599.258f, 963.951f, 547.553f);
- creature->SetFaction(35); //wrong faction in db?
+ creature->SetFaction(FACTION_FRIENDLY); //wrong faction in db?
}
void Initialize()
@@ -69,7 +69,7 @@ public:
if (uiType != POINT_MOTION_TYPE)
return;
- me->SetFaction(14);
+ me->SetFaction(FACTION_MONSTER);
}
void DamageTaken(Unit* pDoneBy, uint32& uiDamage) override
@@ -78,7 +78,7 @@ public:
{
uiDamage = 0;
pDoneBy->CastSpell(pDoneBy, SPELL_KILL_CREDIT, true);
- me->SetFaction(35);
+ me->SetFaction(FACTION_FRIENDLY);
me->DespawnOrUnsummon(5000);
me->SetHomePosition(me->GetPositionX(), me->GetPositionY(), me->GetPositionZ(), me->GetOrientation());
EnterEvadeMode();
diff --git a/src/server/scripts/Northrend/zone_sholazar_basin.cpp b/src/server/scripts/Northrend/zone_sholazar_basin.cpp
index 01285e18a61..5ace31b5cdd 100644
--- a/src/server/scripts/Northrend/zone_sholazar_basin.cpp
+++ b/src/server/scripts/Northrend/zone_sholazar_basin.cpp
@@ -340,7 +340,7 @@ public:
if (quest->GetQuestId() == QUEST_DISASTER)
{
me->GetMotionMaster()->MoveJumpTo(0, 0.4f, 0.4f);
- me->SetFaction(113);
+ me->SetFaction(FACTION_ESCORTEE_N_NEUTRAL_PASSIVE);
Start(false, false, player->GetGUID());
Talk(SAY_WP_1);
diff --git a/src/server/scripts/Northrend/zone_storm_peaks.cpp b/src/server/scripts/Northrend/zone_storm_peaks.cpp
index 8fbf23d4a44..5a0e6c5aa99 100644
--- a/src/server/scripts/Northrend/zone_storm_peaks.cpp
+++ b/src/server/scripts/Northrend/zone_storm_peaks.cpp
@@ -93,7 +93,7 @@ public:
if (menuId == GOSSIP_ID && gossipListId == GOSSIP_OPTION_ID)
{
CloseGossipMenuFor(player);
- me->SetFaction(113);
+ me->SetFaction(FACTION_ESCORTEE_N_NEUTRAL_PASSIVE);
Start(true, true, player->GetGUID());
}
return false;
diff --git a/src/server/scripts/Northrend/zone_zuldrak.cpp b/src/server/scripts/Northrend/zone_zuldrak.cpp
index 48dc7a1d7e4..4e1079eccc7 100644
--- a/src/server/scripts/Northrend/zone_zuldrak.cpp
+++ b/src/server/scripts/Northrend/zone_zuldrak.cpp
@@ -139,7 +139,7 @@ public:
void Reset() override
{
- me->SetFaction(35);
+ me->SetFaction(FACTION_FRIENDLY);
DoCast(me, SPELL_KNEEL, true); // Little Hack for kneel - Thanks Illy :P
}