aboutsummaryrefslogtreecommitdiff
path: root/src/server/scripts
diff options
context:
space:
mode:
Diffstat (limited to 'src/server/scripts')
-rw-r--r--src/server/scripts/Commands/cs_wp.cpp6
-rw-r--r--src/server/scripts/EasternKingdoms/Karazhan/boss_midnight.cpp4
-rw-r--r--src/server/scripts/EasternKingdoms/Karazhan/boss_prince_malchezaar.cpp2
-rw-r--r--src/server/scripts/EasternKingdoms/MagistersTerrace/boss_felblood_kaelthas.cpp6
-rw-r--r--src/server/scripts/EasternKingdoms/MagistersTerrace/boss_selin_fireheart.cpp4
-rw-r--r--src/server/scripts/EasternKingdoms/ScarletEnclave/chapter5.cpp4
-rw-r--r--src/server/scripts/EasternKingdoms/ScarletMonastery/boss_headless_horseman.cpp4
-rw-r--r--src/server/scripts/EasternKingdoms/ScarletMonastery/instance_scarlet_monastery.cpp2
-rw-r--r--src/server/scripts/EasternKingdoms/Stratholme/stratholme.cpp4
-rw-r--r--src/server/scripts/EasternKingdoms/SunwellPlateau/boss_eredar_twins.cpp2
-rw-r--r--src/server/scripts/EasternKingdoms/SunwellPlateau/boss_kiljaeden.cpp4
-rw-r--r--src/server/scripts/EasternKingdoms/zone_western_plaguelands.cpp140
-rw-r--r--src/server/scripts/Kalimdor/CavernsOfTime/BattleForMountHyjal/boss_anetheron.cpp2
-rw-r--r--src/server/scripts/Kalimdor/CavernsOfTime/BattleForMountHyjal/boss_azgalor.cpp4
-rw-r--r--src/server/scripts/Kalimdor/CavernsOfTime/CullingOfStratholme/boss_mal_ganis.cpp2
-rw-r--r--src/server/scripts/Kalimdor/CavernsOfTime/CullingOfStratholme/culling_of_stratholme.cpp4
-rw-r--r--src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_cthun.cpp18
-rw-r--r--src/server/scripts/Kalimdor/zone_dustwallow_marsh.cpp2
-rw-r--r--src/server/scripts/Kalimdor/zone_moonglade.cpp59
-rw-r--r--src/server/scripts/Northrend/AzjolNerub/Ahnkahet/boss_jedoga_shadowseeker.cpp2
-rw-r--r--src/server/scripts/Northrend/ChamberOfAspects/ObsidianSanctum/obsidian_sanctum.cpp6
-rw-r--r--src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/boss_halion.cpp6
-rw-r--r--src/server/scripts/Northrend/IcecrownCitadel/boss_lady_deathwhisper.cpp4
-rw-r--r--src/server/scripts/Northrend/Naxxramas/boss_anubrekhan.cpp2
-rw-r--r--src/server/scripts/Northrend/Naxxramas/boss_maexxna.cpp150
-rw-r--r--src/server/scripts/Northrend/Naxxramas/boss_noth.cpp2
-rw-r--r--src/server/scripts/Northrend/Naxxramas/boss_razuvious.cpp196
-rw-r--r--src/server/scripts/Northrend/Naxxramas/boss_thaddius.cpp1372
-rw-r--r--src/server/scripts/Northrend/Naxxramas/instance_naxxramas.cpp47
-rw-r--r--src/server/scripts/Northrend/Naxxramas/naxxramas.h11
-rw-r--r--src/server/scripts/Northrend/Nexus/EyeOfEternity/boss_malygos.cpp5
-rw-r--r--src/server/scripts/Northrend/Ulduar/Ulduar/boss_mimiron.cpp2
-rw-r--r--src/server/scripts/Northrend/Ulduar/Ulduar/boss_yogg_saron.cpp4
-rw-r--r--src/server/scripts/Northrend/zone_borean_tundra.cpp2
-rw-r--r--src/server/scripts/Northrend/zone_sholazar_basin.cpp2
-rw-r--r--src/server/scripts/Outland/Auchindoun/ShadowLabyrinth/boss_grandmaster_vorpil.cpp2
-rw-r--r--src/server/scripts/Outland/CoilfangReservoir/SerpentShrine/boss_lady_vashj.cpp2
-rw-r--r--src/server/scripts/Outland/TempestKeep/Eye/boss_kaelthas.cpp2
-rw-r--r--src/server/scripts/Pet/pet_mage.cpp185
-rw-r--r--src/server/scripts/Spells/spell_dk.cpp10
-rw-r--r--src/server/scripts/Spells/spell_holiday.cpp81
-rw-r--r--src/server/scripts/Spells/spell_hunter.cpp2
-rw-r--r--src/server/scripts/Spells/spell_item.cpp2
-rw-r--r--src/server/scripts/World/duel_reset.cpp79
44 files changed, 1741 insertions, 710 deletions
diff --git a/src/server/scripts/Commands/cs_wp.cpp b/src/server/scripts/Commands/cs_wp.cpp
index b35e71dbd50..30ee8254f72 100644
--- a/src/server/scripts/Commands/cs_wp.cpp
+++ b/src/server/scripts/Commands/cs_wp.cpp
@@ -374,6 +374,12 @@ public:
if (show == "del")
{
+ if (!arg_id)
+ {
+ handler->SendSysMessage("|cffff33ffERROR: Waypoint script guid not present.|r");
+ return true;
+ }
+
id = atoi(arg_id);
stmt = WorldDatabase.GetPreparedStatement(WORLD_SEL_WAYPOINT_SCRIPT_ID_BY_GUID);
diff --git a/src/server/scripts/EasternKingdoms/Karazhan/boss_midnight.cpp b/src/server/scripts/EasternKingdoms/Karazhan/boss_midnight.cpp
index 0b5c3302890..96c7c5d8102 100644
--- a/src/server/scripts/EasternKingdoms/Karazhan/boss_midnight.cpp
+++ b/src/server/scripts/EasternKingdoms/Karazhan/boss_midnight.cpp
@@ -108,7 +108,7 @@ public:
{
Talk(SAY_DEATH);
if (Unit* midnight = ObjectAccessor::GetUnit(*me, Midnight))
- midnight->Kill(midnight);
+ midnight->KillSelf();
}
void UpdateAI(uint32 diff) override;
@@ -264,7 +264,7 @@ void boss_attumen::boss_attumenAI::UpdateAI(uint32 diff)
}
Midnight.Clear();
me->SetVisible(false);
- me->Kill(me);
+ me->KillSelf();
} else ResetTimer -= diff;
}
diff --git a/src/server/scripts/EasternKingdoms/Karazhan/boss_prince_malchezaar.cpp b/src/server/scripts/EasternKingdoms/Karazhan/boss_prince_malchezaar.cpp
index 0abba3dfff4..d11c4a6e584 100644
--- a/src/server/scripts/EasternKingdoms/Karazhan/boss_prince_malchezaar.cpp
+++ b/src/server/scripts/EasternKingdoms/Karazhan/boss_prince_malchezaar.cpp
@@ -295,7 +295,7 @@ public:
{
Unit* axe = ObjectAccessor::GetUnit(*me, axes[i]);
if (axe && axe->IsAlive())
- axe->Kill(axe);
+ axe->KillSelf();
axes[i].Clear();
}
}
diff --git a/src/server/scripts/EasternKingdoms/MagistersTerrace/boss_felblood_kaelthas.cpp b/src/server/scripts/EasternKingdoms/MagistersTerrace/boss_felblood_kaelthas.cpp
index a95ac9aaa20..e4cc7c0e84a 100644
--- a/src/server/scripts/EasternKingdoms/MagistersTerrace/boss_felblood_kaelthas.cpp
+++ b/src/server/scripts/EasternKingdoms/MagistersTerrace/boss_felblood_kaelthas.cpp
@@ -473,7 +473,7 @@ public:
if (FlameStrikeTimer <= diff)
{
DoCast(me, SPELL_FLAMESTRIKE1_NORMAL, true);
- me->Kill(me);
+ me->KillSelf();
} else FlameStrikeTimer -= diff;
}
};
@@ -636,7 +636,7 @@ public:
if (HatchTimer <= diff)
{
me->SummonCreature(CREATURE_PHOENIX, 0.0f, 0.0f, 0.0f, 0.0f, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 60000);
- me->Kill(me);
+ me->KillSelf();
} else HatchTimer -= diff;
}
};
@@ -675,7 +675,7 @@ public:
void UpdateAI(uint32 diff) override
{
if (DespawnTimer <= diff)
- me->Kill(me);
+ me->KillSelf();
else
DespawnTimer -= diff;
diff --git a/src/server/scripts/EasternKingdoms/MagistersTerrace/boss_selin_fireheart.cpp b/src/server/scripts/EasternKingdoms/MagistersTerrace/boss_selin_fireheart.cpp
index f57de5316ab..480fd8848f5 100644
--- a/src/server/scripts/EasternKingdoms/MagistersTerrace/boss_selin_fireheart.cpp
+++ b/src/server/scripts/EasternKingdoms/MagistersTerrace/boss_selin_fireheart.cpp
@@ -139,7 +139,7 @@ class boss_selin_fireheart : public CreatureScript
for (Creature* crystal : Crystals)
{
if (crystal && crystal->IsAlive())
- crystal->Kill(crystal);
+ crystal->KillSelf();
}
}
@@ -218,7 +218,7 @@ class boss_selin_fireheart : public CreatureScript
Creature* CrystalChosen = ObjectAccessor::GetCreature(*me, CrystalGUID);
if (CrystalChosen && CrystalChosen->IsAlive())
- CrystalChosen->Kill(CrystalChosen);
+ CrystalChosen->KillSelf();
CrystalGUID.Clear();
diff --git a/src/server/scripts/EasternKingdoms/ScarletEnclave/chapter5.cpp b/src/server/scripts/EasternKingdoms/ScarletEnclave/chapter5.cpp
index 2714d65774f..ce8b094bb83 100644
--- a/src/server/scripts/EasternKingdoms/ScarletEnclave/chapter5.cpp
+++ b/src/server/scripts/EasternKingdoms/ScarletEnclave/chapter5.cpp
@@ -1218,7 +1218,7 @@ public:
if (Creature* temp = ObjectAccessor::GetCreature(*me, uiLichKingGUID)) // Lich king disappears here
{
temp->AI()->Talk(EMOTE_LIGHT_OF_DAWN17);
- temp->Kill(temp);
+ temp->KillSelf();
}
JumpToNextStep(10000);
break;
@@ -1633,7 +1633,7 @@ public:
if (temp->IsAlive())
{
temp->SetVisible(false);
- temp->Kill(temp);
+ temp->KillSelf();
}
}
};
diff --git a/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_headless_horseman.cpp b/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_headless_horseman.cpp
index a78ad740c97..bac4e450a03 100644
--- a/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_headless_horseman.cpp
+++ b/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_headless_horseman.cpp
@@ -359,8 +359,8 @@ public:
{
die = false;
if (Unit* body = ObjectAccessor::GetUnit(*me, bodyGUID))
- body->Kill(body);
- me->Kill(me);
+ body->KillSelf();
+ me->KillSelf();
}
else wait -= diff;
}
diff --git a/src/server/scripts/EasternKingdoms/ScarletMonastery/instance_scarlet_monastery.cpp b/src/server/scripts/EasternKingdoms/ScarletMonastery/instance_scarlet_monastery.cpp
index ed9f7ccb6dd..c41b1d87d61 100644
--- a/src/server/scripts/EasternKingdoms/ScarletMonastery/instance_scarlet_monastery.cpp
+++ b/src/server/scripts/EasternKingdoms/ScarletMonastery/instance_scarlet_monastery.cpp
@@ -121,7 +121,7 @@ class instance_scarlet_monastery : public InstanceMapScript
{
Creature* add = instance->GetCreature(guid);
if (add && add->IsAlive())
- add->Kill(add);
+ add->KillSelf();
}
HorsemanAdds.clear();
HandleGameObject(PumpkinShrineGUID, false);
diff --git a/src/server/scripts/EasternKingdoms/Stratholme/stratholme.cpp b/src/server/scripts/EasternKingdoms/Stratholme/stratholme.cpp
index ba99df8cdd5..60dd27eed90 100644
--- a/src/server/scripts/EasternKingdoms/Stratholme/stratholme.cpp
+++ b/src/server/scripts/EasternKingdoms/Stratholme/stratholme.cpp
@@ -170,7 +170,7 @@ public:
{
if (Player* player = temp->ToPlayer())
player->KilledMonsterCredit(NPC_RESTLESS, me->GetGUID());
- me->Kill(me);
+ me->KillSelf();
}
}
else
@@ -248,7 +248,7 @@ public:
if (Tagged)
{
if (Die_Timer <= diff)
- me->Kill(me);
+ me->KillSelf();
else Die_Timer -= diff;
}
diff --git a/src/server/scripts/EasternKingdoms/SunwellPlateau/boss_eredar_twins.cpp b/src/server/scripts/EasternKingdoms/SunwellPlateau/boss_eredar_twins.cpp
index 31ca716e0fb..77e0e680f4a 100644
--- a/src/server/scripts/EasternKingdoms/SunwellPlateau/boss_eredar_twins.cpp
+++ b/src/server/scripts/EasternKingdoms/SunwellPlateau/boss_eredar_twins.cpp
@@ -698,7 +698,7 @@ public:
if (KillTimer <= diff)
{
- me->Kill(me);
+ me->KillSelf();
KillTimer = 9999999;
} else KillTimer -= diff;
diff --git a/src/server/scripts/EasternKingdoms/SunwellPlateau/boss_kiljaeden.cpp b/src/server/scripts/EasternKingdoms/SunwellPlateau/boss_kiljaeden.cpp
index 4d544ccdeab..e3deac506b0 100644
--- a/src/server/scripts/EasternKingdoms/SunwellPlateau/boss_kiljaeden.cpp
+++ b/src/server/scripts/EasternKingdoms/SunwellPlateau/boss_kiljaeden.cpp
@@ -1112,7 +1112,7 @@ public:
else if (me->IsWithinDistInMap(me->GetVictim(), 3)) // Explode if it's close enough to it's target
{
DoCastVictim(SPELL_FELFIRE_FISSION);
- me->Kill(me);
+ me->KillSelf();
}
}
};
@@ -1172,7 +1172,7 @@ public:
uiTimer = 5000;
break;
case 3:
- me->Kill(me);
+ me->KillSelf();
me->RemoveCorpse();
break;
}
diff --git a/src/server/scripts/EasternKingdoms/zone_western_plaguelands.cpp b/src/server/scripts/EasternKingdoms/zone_western_plaguelands.cpp
index 9cecbc31665..9af23f17dca 100644
--- a/src/server/scripts/EasternKingdoms/zone_western_plaguelands.cpp
+++ b/src/server/scripts/EasternKingdoms/zone_western_plaguelands.cpp
@@ -277,145 +277,6 @@ public:
};
/*######
-## npc_anchorite_truuen
-######*/
-
-enum Truuen
-{
- NPC_GHOST_UTHER = 17233,
- NPC_THEL_DANIS = 1854,
- NPC_GHOUL = 1791, //ambush
-
- QUEST_TOMB_LIGHTBRINGER = 9446,
-
- SAY_WP_0 = 0, //Beware! We are attacked!
- SAY_WP_1 = 1, //It must be the purity of the Mark of the Lightbringer that is drawing forth the Scourge to attack us. We must proceed with caution lest we be overwhelmed!
- SAY_WP_2 = 2, //This land truly needs to be cleansed by the Light! Let us continue on to the tomb. It isn't far now...
- SAY_WP_3 = 0, //Be welcome, friends!
- SAY_WP_4 = 0, //Thank you for coming here in remembrance of me. Your efforts in recovering that symbol, while unnecessary, are certainly touching to an old man's heart.
- SAY_WP_5 = 1, //Please, rise my friend. Keep the Blessing as a symbol of the strength of the Light and how heroes long gone might once again rise in each of us to inspire.
- SAY_WP_6 = 2 //Thank you my friend for making this possible. This is a day that I shall never forget! I think I will stay a while. Please return to High Priestess MacDonnell at the camp. I know that she'll be keenly interested to know of what has transpired here.
-};
-
-class npc_anchorite_truuen : public CreatureScript
-{
-public:
- npc_anchorite_truuen() : CreatureScript("npc_anchorite_truuen") { }
-
- bool OnQuestAccept(Player* player, Creature* creature, Quest const* quest) override
- {
- if (quest->GetQuestId() == QUEST_TOMB_LIGHTBRINGER)
- {
- npc_escortAI* pEscortAI = ENSURE_AI(npc_anchorite_truuen::npc_anchorite_truuenAI, creature->AI());
- pEscortAI->Start(true, true, player->GetGUID());
- }
- return false;
- }
-
- CreatureAI* GetAI(Creature* creature) const override
- {
- return new npc_anchorite_truuenAI(creature);
- }
-
- struct npc_anchorite_truuenAI : public npc_escortAI
- {
- npc_anchorite_truuenAI(Creature* creature) : npc_escortAI(creature)
- {
- Initialize();
- }
-
- void Initialize()
- {
- m_uiChatTimer = 7000;
- }
-
- uint32 m_uiChatTimer;
-
- ObjectGuid UghostGUID;
-
- void Reset() override
- {
- Initialize();
- }
-
- void JustSummoned(Creature* summoned) override
- {
- if (summoned->GetEntry() == NPC_GHOUL)
- summoned->AI()->AttackStart(me);
- }
-
- void WaypointReached(uint32 waypointId) override
- {
- Player* player = GetPlayerForEscort();
-
- switch (waypointId)
- {
- case 8:
- Talk(SAY_WP_0);
- me->SummonCreature(NPC_GHOUL, me->GetPositionX()+7.0f, me->GetPositionY()+7.0f, me->GetPositionZ(), 0.0f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 90000);
- me->SummonCreature(NPC_GHOUL, me->GetPositionX()+5.0f, me->GetPositionY()+5.0f, me->GetPositionZ(), 0.0f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 90000);
- break;
- case 9:
- Talk(SAY_WP_1);
- break;
- case 14:
- me->SummonCreature(NPC_GHOUL, me->GetPositionX()+7.0f, me->GetPositionY()+7.0f, me->GetPositionZ(), 0.0f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 90000);
- me->SummonCreature(NPC_GHOUL, me->GetPositionX()+5.0f, me->GetPositionY()+5.0f, me->GetPositionZ(), 0.0f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 90000);
- me->SummonCreature(NPC_GHOUL, me->GetPositionX()+10.0f, me->GetPositionY()+10.0f, me->GetPositionZ(), 0.0f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 90000);
- me->SummonCreature(NPC_GHOUL, me->GetPositionX()+8.0f, me->GetPositionY()+8.0f, me->GetPositionZ(), 0.0f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 90000);
- break;
- case 15:
- Talk(SAY_WP_2);
- break;
- case 21:
- if (Creature* Theldanis = GetClosestCreatureWithEntry(me, NPC_THEL_DANIS, 150))
- Theldanis->AI()->Talk(SAY_WP_3);
- break;
- case 23:
- if (Creature* Ughost = me->SummonCreature(NPC_GHOST_UTHER, 971.86f, -1825.42f, 81.99f, 0.0f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 30000))
- {
- UghostGUID = Ughost->GetGUID();
- Ughost->SetDisableGravity(true);
- Ughost->AI()->Talk(SAY_WP_4, me);
- }
- m_uiChatTimer = 4000;
- break;
- case 24:
- if (Creature* Ughost = ObjectAccessor::GetCreature(*me, UghostGUID))
- Ughost->AI()->Talk(SAY_WP_5, me);
- m_uiChatTimer = 4000;
- break;
- case 25:
- if (Creature* Ughost = ObjectAccessor::GetCreature(*me, UghostGUID))
- Ughost->AI()->Talk(SAY_WP_6, me);
- m_uiChatTimer = 4000;
- break;
- case 26:
- if (player)
- player->GroupEventHappens(QUEST_TOMB_LIGHTBRINGER, me);
- break;
- }
- }
-
- void EnterCombat(Unit* /*who*/) override { }
-
- void JustDied(Unit* /*killer*/) override
- {
- if (Player* player = GetPlayerForEscort())
- player->FailQuest(QUEST_TOMB_LIGHTBRINGER);
- }
-
- void UpdateAI(uint32 uiDiff) override
- {
- npc_escortAI::UpdateAI(uiDiff);
- DoMeleeAttackIfReady();
- if (HasEscortState(STATE_ESCORT_ESCORTING))
- m_uiChatTimer = 6000;
- }
- };
-};
-
-/*######
##
######*/
@@ -425,5 +286,4 @@ void AddSC_western_plaguelands()
new npc_myranda_the_hag();
new npc_the_scourge_cauldron();
new npc_andorhal_tower();
- new npc_anchorite_truuen();
}
diff --git a/src/server/scripts/Kalimdor/CavernsOfTime/BattleForMountHyjal/boss_anetheron.cpp b/src/server/scripts/Kalimdor/CavernsOfTime/BattleForMountHyjal/boss_anetheron.cpp
index 254e3a41d6b..d0a9b233454 100644
--- a/src/server/scripts/Kalimdor/CavernsOfTime/BattleForMountHyjal/boss_anetheron.cpp
+++ b/src/server/scripts/Kalimdor/CavernsOfTime/BattleForMountHyjal/boss_anetheron.cpp
@@ -235,7 +235,7 @@ public:
if (AnetheronGUID)
{
Creature* boss = ObjectAccessor::GetCreature(*me, AnetheronGUID);
- if (!boss || (boss && boss->isDead()))
+ if (!boss || boss->isDead())
{
me->setDeathState(JUST_DIED);
me->RemoveCorpse();
diff --git a/src/server/scripts/Kalimdor/CavernsOfTime/BattleForMountHyjal/boss_azgalor.cpp b/src/server/scripts/Kalimdor/CavernsOfTime/BattleForMountHyjal/boss_azgalor.cpp
index 08942e3393f..8bfdee067b2 100644
--- a/src/server/scripts/Kalimdor/CavernsOfTime/BattleForMountHyjal/boss_azgalor.cpp
+++ b/src/server/scripts/Kalimdor/CavernsOfTime/BattleForMountHyjal/boss_azgalor.cpp
@@ -200,7 +200,6 @@ public:
CrippleTimer = 50000;
WarstompTimer = 10000;
CheckTimer = 5000;
- instance = creature->GetInstanceScript();
AzgalorGUID = instance->GetGuidData(DATA_AZGALOR);
}
@@ -208,7 +207,6 @@ public:
uint32 WarstompTimer;
uint32 CheckTimer;
ObjectGuid AzgalorGUID;
- InstanceScript* instance;
void Reset() override
{
@@ -248,7 +246,7 @@ public:
if (AzgalorGUID)
{
Creature* boss = ObjectAccessor::GetCreature(*me, AzgalorGUID);
- if (!boss || (boss && boss->isDead()))
+ if (!boss || boss->isDead())
{
me->setDeathState(JUST_DIED);
me->RemoveCorpse();
diff --git a/src/server/scripts/Kalimdor/CavernsOfTime/CullingOfStratholme/boss_mal_ganis.cpp b/src/server/scripts/Kalimdor/CavernsOfTime/CullingOfStratholme/boss_mal_ganis.cpp
index 70ecaad3d8d..c39fbc90795 100644
--- a/src/server/scripts/Kalimdor/CavernsOfTime/CullingOfStratholme/boss_mal_ganis.cpp
+++ b/src/server/scripts/Kalimdor/CavernsOfTime/CullingOfStratholme/boss_mal_ganis.cpp
@@ -218,7 +218,7 @@ public:
break;
case 5:
me->SetVisible(false);
- me->Kill(me);
+ me->KillSelf();
break;
}
diff --git a/src/server/scripts/Kalimdor/CavernsOfTime/CullingOfStratholme/culling_of_stratholme.cpp b/src/server/scripts/Kalimdor/CavernsOfTime/CullingOfStratholme/culling_of_stratholme.cpp
index b5d2931377f..a73a6b8d998 100644
--- a/src/server/scripts/Kalimdor/CavernsOfTime/CullingOfStratholme/culling_of_stratholme.cpp
+++ b/src/server/scripts/Kalimdor/CavernsOfTime/CullingOfStratholme/culling_of_stratholme.cpp
@@ -817,7 +817,7 @@ public:
cityman1->AI()->Talk(SAY_PHASE204);
cityman1->SetTarget(me->GetGUID());
if (Creature* cityman0 = ObjectAccessor::GetCreature(*me, citymenGUID[0]))
- cityman0->Kill(cityman0);
+ cityman0->KillSelf();
me->SetTarget(citymenGUID[1]);
}
JumpToNextStep(0);
@@ -829,7 +829,7 @@ public:
break;
case 33:
if (Creature* cityman1 = ObjectAccessor::GetCreature(*me, citymenGUID[1]))
- cityman1->Kill(cityman1);
+ cityman1->KillSelf();
JumpToNextStep(1000);
break;
case 34:
diff --git a/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_cthun.cpp b/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_cthun.cpp
index 8e84f1b4265..6016893a785 100644
--- a/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_cthun.cpp
+++ b/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_cthun.cpp
@@ -917,7 +917,7 @@ public:
void JustDied(Unit* /*killer*/) override
{
if (Unit* p = ObjectAccessor::GetUnit(*me, Portal))
- p->Kill(p);
+ p->KillSelf();
}
void Reset() override
@@ -943,7 +943,7 @@ public:
//KillSelfTimer
if (KillSelfTimer <= diff)
{
- me->Kill(me);
+ me->KillSelf();
return;
} else KillSelfTimer -= diff;
@@ -997,7 +997,7 @@ public:
void JustDied(Unit* /*killer*/) override
{
if (Unit* p = ObjectAccessor::GetUnit(*me, Portal))
- p->Kill(p);
+ p->KillSelf();
}
void Reset() override
@@ -1025,7 +1025,7 @@ public:
if (EvadeTimer <= diff)
{
if (Unit* p = ObjectAccessor::GetUnit(*me, Portal))
- p->Kill(p);
+ p->KillSelf();
//Dissapear and reappear at new position
me->SetVisible(false);
@@ -1033,7 +1033,7 @@ public:
Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0);
if (!target)
{
- me->Kill(me);
+ me->KillSelf();
return;
}
@@ -1113,7 +1113,7 @@ public:
void JustDied(Unit* /*killer*/) override
{
if (Unit* p = ObjectAccessor::GetUnit(*me, Portal))
- p->Kill(p);
+ p->KillSelf();
}
void Reset() override
@@ -1142,7 +1142,7 @@ public:
if (EvadeTimer <= diff)
{
if (Unit* p = ObjectAccessor::GetUnit(*me, Portal))
- p->Kill(p);
+ p->KillSelf();
//Dissapear and reappear at new position
me->SetVisible(false);
@@ -1150,7 +1150,7 @@ public:
Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0);
if (!target)
{
- me->Kill(me);
+ me->KillSelf();
return;
}
@@ -1231,7 +1231,7 @@ public:
void JustDied(Unit* /*killer*/) override
{
if (Unit* p = ObjectAccessor::GetUnit(*me, Portal))
- p->Kill(p);
+ p->KillSelf();
}
void Reset() override
diff --git a/src/server/scripts/Kalimdor/zone_dustwallow_marsh.cpp b/src/server/scripts/Kalimdor/zone_dustwallow_marsh.cpp
index b0800918765..fba0956ccfc 100644
--- a/src/server/scripts/Kalimdor/zone_dustwallow_marsh.cpp
+++ b/src/server/scripts/Kalimdor/zone_dustwallow_marsh.cpp
@@ -352,7 +352,7 @@ class spell_ooze_zap_channel_end : public SpellScriptLoader
PreventHitDefaultEffect(effIndex);
if (Player* player = GetCaster()->ToPlayer())
player->CastSpell(player, SPELL_OOZE_CHANNEL_CREDIT, true);
- GetHitUnit()->Kill(GetHitUnit());
+ GetHitUnit()->KillSelf();
}
void Register() override
diff --git a/src/server/scripts/Kalimdor/zone_moonglade.cpp b/src/server/scripts/Kalimdor/zone_moonglade.cpp
index 163620230ef..c7decd3e286 100644
--- a/src/server/scripts/Kalimdor/zone_moonglade.cpp
+++ b/src/server/scripts/Kalimdor/zone_moonglade.cpp
@@ -108,64 +108,6 @@ public:
};
/*######
-## npc_great_bear_spirit
-######*/
-
-#define GOSSIP_BEAR1 "What do you represent, spirit?"
-#define GOSSIP_BEAR2 "I seek to understand the importance of strength of the body."
-#define GOSSIP_BEAR3 "I seek to understand the importance of strength of the heart."
-#define GOSSIP_BEAR4 "I have heard your words, Great Bear Spirit, and I understand. I now seek your blessings to fully learn the way of the Claw."
-
-class npc_great_bear_spirit : public CreatureScript
-{
-public:
- npc_great_bear_spirit() : CreatureScript("npc_great_bear_spirit") { }
-
- bool OnGossipSelect(Player* player, Creature* creature, uint32 /*sender*/, uint32 action) override
- {
- player->PlayerTalkClass->ClearMenus();
- switch (action)
- {
- case GOSSIP_ACTION_INFO_DEF:
- player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_BEAR2, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1);
- player->SEND_GOSSIP_MENU(4721, creature->GetGUID());
- break;
- case GOSSIP_ACTION_INFO_DEF + 1:
- player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_BEAR3, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2);
- player->SEND_GOSSIP_MENU(4733, creature->GetGUID());
- break;
- case GOSSIP_ACTION_INFO_DEF + 2:
- player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_BEAR4, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 3);
- player->SEND_GOSSIP_MENU(4734, creature->GetGUID());
- break;
- case GOSSIP_ACTION_INFO_DEF + 3:
- player->SEND_GOSSIP_MENU(4735, creature->GetGUID());
- if (player->GetQuestStatus(5929) == QUEST_STATUS_INCOMPLETE)
- player->AreaExploredOrEventHappens(5929);
- if (player->GetQuestStatus(5930) == QUEST_STATUS_INCOMPLETE)
- player->AreaExploredOrEventHappens(5930);
- break;
- }
- return true;
- }
-
- bool OnGossipHello(Player* player, Creature* creature) override
- {
- //ally or horde quest
- if (player->GetQuestStatus(5929) == QUEST_STATUS_INCOMPLETE || player->GetQuestStatus(5930) == QUEST_STATUS_INCOMPLETE)
- {
- player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_BEAR1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF);
- player->SEND_GOSSIP_MENU(4719, creature->GetGUID());
- }
- else
- player->SEND_GOSSIP_MENU(4718, creature->GetGUID());
-
- return true;
- }
-
-};
-
-/*######
## npc_silva_filnaveth
######*/
@@ -712,7 +654,6 @@ public:
void AddSC_moonglade()
{
new npc_bunthen_plainswind();
- new npc_great_bear_spirit();
new npc_silva_filnaveth();
new npc_clintar_spirit();
new npc_omen();
diff --git a/src/server/scripts/Northrend/AzjolNerub/Ahnkahet/boss_jedoga_shadowseeker.cpp b/src/server/scripts/Northrend/AzjolNerub/Ahnkahet/boss_jedoga_shadowseeker.cpp
index 5890b9cbec7..240e8a7b957 100644
--- a/src/server/scripts/Northrend/AzjolNerub/Ahnkahet/boss_jedoga_shadowseeker.cpp
+++ b/src/server/scripts/Northrend/AzjolNerub/Ahnkahet/boss_jedoga_shadowseeker.cpp
@@ -433,7 +433,7 @@ public:
{
ENSURE_AI(boss_jedoga_shadowseeker::boss_jedoga_shadowseekerAI, boss->AI())->bOpFerok = true;
ENSURE_AI(boss_jedoga_shadowseeker::boss_jedoga_shadowseekerAI, boss->AI())->bOpFerokFail = false;
- me->Kill(me);
+ me->KillSelf();
}
}
break;
diff --git a/src/server/scripts/Northrend/ChamberOfAspects/ObsidianSanctum/obsidian_sanctum.cpp b/src/server/scripts/Northrend/ChamberOfAspects/ObsidianSanctum/obsidian_sanctum.cpp
index eac84d1f6c9..3b12104a90b 100644
--- a/src/server/scripts/Northrend/ChamberOfAspects/ObsidianSanctum/obsidian_sanctum.cpp
+++ b/src/server/scripts/Northrend/ChamberOfAspects/ObsidianSanctum/obsidian_sanctum.cpp
@@ -338,14 +338,14 @@ struct dummy_dragonAI : public ScriptedAI
if (instance->GetBossState(DATA_SARTHARION) != IN_PROGRESS)
instance->SetBossState(DATA_SHADRON, DONE);
if (Creature* acolyte = me->FindNearestCreature(NPC_ACOLYTE_OF_SHADRON, 100.0f))
- acolyte->Kill(acolyte);
+ acolyte->KillSelf();
break;
case NPC_VESPERON:
spellId = SPELL_POWER_OF_VESPERON;
if (instance->GetBossState(DATA_SARTHARION) != IN_PROGRESS)
instance->SetBossState(DATA_VESPERON, DONE);
if (Creature* acolyte = me->FindNearestCreature(NPC_ACOLYTE_OF_VESPERON, 100.0f))
- acolyte->Kill(acolyte);
+ acolyte->KillSelf();
break;
}
@@ -948,7 +948,7 @@ public:
//DoCastVictim(57620, true);
//DoCastVictim(57874, true);
me->RemoveAllAuras();
- me->Kill(me);
+ me->KillSelf();
}
}
diff --git a/src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/boss_halion.cpp b/src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/boss_halion.cpp
index 0b8fa7459a8..6bc49de5319 100644
--- a/src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/boss_halion.cpp
+++ b/src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/boss_halion.cpp
@@ -360,11 +360,11 @@ class boss_halion : public CreatureScript
if (Creature* twilightHalion = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_TWILIGHT_HALION)))
if (twilightHalion->IsAlive())
- twilightHalion->Kill(twilightHalion);
+ twilightHalion->KillSelf();
if (Creature* controller = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_HALION_CONTROLLER)))
if (controller->IsAlive())
- controller->Kill(controller);
+ controller->KillSelf();
}
Position const* GetMeteorStrikePosition() const { return &_meteorStrikePos; }
@@ -523,7 +523,7 @@ class boss_twilight_halion : public CreatureScript
if (Creature* controller = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_HALION_CONTROLLER)))
if (controller->IsAlive())
- controller->Kill(controller);
+ controller->KillSelf();
instance->SendEncounterUnit(ENCOUNTER_FRAME_DISENGAGE, me);
}
diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_lady_deathwhisper.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_lady_deathwhisper.cpp
index b2aa6dadd84..78a279b94fd 100644
--- a/src/server/scripts/Northrend/IcecrownCitadel/boss_lady_deathwhisper.cpp
+++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_lady_deathwhisper.cpp
@@ -831,7 +831,7 @@ class npc_vengeful_shade : public CreatureScript
case SPELL_VENGEFUL_BLAST_25N:
case SPELL_VENGEFUL_BLAST_10H:
case SPELL_VENGEFUL_BLAST_25H:
- me->Kill(me);
+ me->KillSelf();
break;
default:
break;
@@ -1019,7 +1019,7 @@ class spell_cultist_dark_martyrdom : public SpellScriptLoader
if (Unit* owner = GetCaster()->ToTempSummon()->GetSummoner())
owner->GetAI()->SetGUID(GetCaster()->GetGUID(), GUID_CULTIST);
- GetCaster()->Kill(GetCaster());
+ GetCaster()->KillSelf();
GetCaster()->SetDisplayId(uint32(GetCaster()->GetEntry() == NPC_CULT_FANATIC ? 38009 : 38010));
}
diff --git a/src/server/scripts/Northrend/Naxxramas/boss_anubrekhan.cpp b/src/server/scripts/Northrend/Naxxramas/boss_anubrekhan.cpp
index 47569a6b85f..11fe5f41455 100644
--- a/src/server/scripts/Northrend/Naxxramas/boss_anubrekhan.cpp
+++ b/src/server/scripts/Northrend/Naxxramas/boss_anubrekhan.cpp
@@ -197,7 +197,7 @@ public:
if (!guardCorpses.empty())
{
if (ObjectGuid target = Trinity::Containers::SelectRandomContainerElement(guardCorpses))
- if(Creature* creatureTarget = ObjectAccessor::GetCreature(*me, target))
+ if (Creature* creatureTarget = ObjectAccessor::GetCreature(*me, target))
{
creatureTarget->CastSpell(creatureTarget, SPELL_SUMMON_CORPSE_SCARABS_MOB, true, nullptr, nullptr, me->GetGUID());
creatureTarget->AI()->Talk(EMOTE_SCARAB);
diff --git a/src/server/scripts/Northrend/Naxxramas/boss_maexxna.cpp b/src/server/scripts/Northrend/Naxxramas/boss_maexxna.cpp
index e52731d003e..0d938122f28 100644
--- a/src/server/scripts/Northrend/Naxxramas/boss_maexxna.cpp
+++ b/src/server/scripts/Northrend/Naxxramas/boss_maexxna.cpp
@@ -18,6 +18,7 @@
#include "ScriptMgr.h"
#include "ScriptedCreature.h"
#include "PassiveAI.h"
+#include "SpellScript.h"
#include "naxxramas.h"
enum Spells
@@ -28,6 +29,14 @@ enum Spells
SPELL_NECROTIC_POISON = 28776,
SPELL_FRENZY = 54123
};
+#define SPELL_FRENZY_HELPER RAID_MODE(54123,54124)
+
+enum Emotes
+{
+ EMOTE_SPIDERS = 0,
+ EMOTE_WEB_WRAP = 1,
+ EMOTE_WEB_SPRAY = 2
+};
enum Creatures
{
@@ -35,12 +44,16 @@ enum Creatures
NPC_SPIDERLING = 17055,
};
-#define MAX_POS_WRAP 3
-const Position PosWrap[MAX_POS_WRAP] =
+#define MAX_WRAP_POSITION 7
+const Position WrapPositions[MAX_WRAP_POSITION] =
{
- {3546.796f, -3869.082f, 296.450f, 0.0f},
- {3531.271f, -3847.424f, 299.450f, 0.0f},
- {3497.067f, -3843.384f, 302.384f, 0.0f},
+ {3453.818f, -3854.651f, 308.7581f, 4.362833f},
+ {3535.042f, -3842.383f, 300.795f, 3.179324f},
+ {3538.399f, -3846.088f, 299.964f, 4.310297f},
+ {3548.464f, -3854.676f, 298.6075f, 4.546609f},
+ {3557.663f, -3870.123f, 297.5027f, 3.756433f},
+ {3560.546f, -3879.353f, 297.4843f, 2.508937f},
+ {3562.535f, -3892.507f, 298.532f, 6.022466f},
};
enum Events
@@ -51,7 +64,24 @@ enum Events
EVENT_POISON,
EVENT_WRAP,
EVENT_SUMMON,
- EVENT_FRENZY,
+};
+
+const float WEB_WRAP_MOVE_SPEED = 20.0f;
+
+struct WebTargetSelector : public std::unary_function<Unit*, bool>
+{
+ WebTargetSelector(Unit* maexxna) : _maexxna(maexxna) {}
+ bool operator()(Unit const* target) const
+ {
+ if (_maexxna->GetVictim() == target) // never target tank
+ return false;
+ if (target->HasAura(SPELL_WEB_WRAP)) // never target targets that are already webbed
+ return false;
+ return true;
+ }
+
+ private:
+ const Unit* _maexxna;
};
class boss_maexxna : public CreatureScript
@@ -66,27 +96,22 @@ public:
struct boss_maexxnaAI : public BossAI
{
- boss_maexxnaAI(Creature* creature) : BossAI(creature, BOSS_MAEXXNA)
- {
- Initialize();
- }
+ boss_maexxnaAI(Creature* creature) : BossAI(creature, BOSS_MAEXXNA) { }
- void Initialize()
+ void EnterCombat(Unit* /*who*/) override
{
- enraged = false;
+ _EnterCombat();
+ events.ScheduleEvent(EVENT_WRAP, 20 * IN_MILLISECONDS);
+ events.ScheduleEvent(EVENT_SPRAY, 40 * IN_MILLISECONDS);
+ events.ScheduleEvent(EVENT_SHOCK, urandms(5, 10));
+ events.ScheduleEvent(EVENT_POISON, urandms(10, 15));
+ events.ScheduleEvent(EVENT_SUMMON, 30 * IN_MILLISECONDS);
}
- bool enraged;
-
- void EnterCombat(Unit* /*who*/) override
+ void Reset() override
{
- _EnterCombat();
- Initialize();
- events.ScheduleEvent(EVENT_WRAP, 20000);
- events.ScheduleEvent(EVENT_SPRAY, 40000);
- events.ScheduleEvent(EVENT_SHOCK, urand(5000, 10000));
- events.ScheduleEvent(EVENT_POISON, urand(10000, 15000));
- events.ScheduleEvent(EVENT_SUMMON, 30000);
+ _Reset();
+ instance->DoRemoveAurasDueToSpellOnPlayers(SPELL_WEB_WRAP);
}
void UpdateAI(uint32 diff) override
@@ -94,10 +119,9 @@ public:
if (!UpdateVictim() || !CheckInRoom())
return;
- if (!enraged && HealthBelowPct(30))
+ if (HealthBelowPct(30) && !me->HasAura(SPELL_FRENZY_HELPER))
{
- enraged = true;
- events.ScheduleEvent(EVENT_FRENZY, 0); // will be cast immediately
+ DoCast(SPELL_FRENZY);
}
events.Update(diff);
@@ -107,41 +131,49 @@ public:
switch (eventId)
{
case EVENT_WRAP:
- /// @todo Add missing text
- for (uint8 i = 0; i < RAID_MODE(1, 2); ++i)
+ {
+ std::list<Unit*> targets;
+ SelectTargetList(targets, WebTargetSelector(me), RAID_MODE(1, 2), SELECT_TARGET_RANDOM);
+ if (!targets.empty())
{
- if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 1, 0, true, -SPELL_WEB_WRAP))
+ Talk(EMOTE_WEB_WRAP);
+ int8 wrapPos = -1;
+ for (Unit* target : targets)
{
+ if (wrapPos == -1) // allow all positions on the first target
+ wrapPos = urand(0, MAX_WRAP_POSITION - 1);
+ else // on subsequent iterations, only allow positions that are not equal to the previous one (this is sufficient since we should only have two targets at most, ever)
+ wrapPos = (wrapPos + urand(1, MAX_WRAP_POSITION - 1)) % MAX_WRAP_POSITION;
+
target->RemoveAura(sSpellMgr->GetSpellIdForDifficulty(SPELL_WEB_SPRAY, me));
- uint8 pos = rand32() % MAX_POS_WRAP;
- target->GetMotionMaster()->MoveJump(PosWrap[pos].GetPositionX(), PosWrap[pos].GetPositionY(), PosWrap[pos].GetPositionZ(), 20, 20);
- if (Creature* wrap = DoSummon(NPC_WEB_WRAP, PosWrap[pos], 0, TEMPSUMMON_CORPSE_DESPAWN))
- wrap->AI()->SetGUID(target->GetGUID());
+ if (Creature* wrap = DoSummon(NPC_WEB_WRAP, WrapPositions[wrapPos], 70 * IN_MILLISECONDS, TEMPSUMMON_TIMED_DESPAWN))
+ {
+ wrap->AI()->SetGUID(target->GetGUID()); // handles application of debuff
+ target->GetMotionMaster()->MoveJump(WrapPositions[wrapPos], WEB_WRAP_MOVE_SPEED, WEB_WRAP_MOVE_SPEED); // move after stun to avoid stun cancelling move
+ }
}
}
events.ScheduleEvent(EVENT_WRAP, 40000);
break;
+ }
case EVENT_SPRAY:
+ Talk(EMOTE_WEB_SPRAY);
DoCastAOE(SPELL_WEB_SPRAY);
events.ScheduleEvent(EVENT_SPRAY, 40000);
break;
case EVENT_SHOCK:
DoCastAOE(SPELL_POISON_SHOCK);
- events.ScheduleEvent(EVENT_SHOCK, urand(10000, 20000));
+ events.ScheduleEvent(EVENT_SHOCK, urandms(10, 20));
break;
case EVENT_POISON:
DoCastVictim(SPELL_NECROTIC_POISON);
- events.ScheduleEvent(EVENT_POISON, urand(10000, 20000));
- break;
- case EVENT_FRENZY:
- DoCast(me, SPELL_FRENZY, true);
- events.ScheduleEvent(EVENT_FRENZY, 600000);
+ events.ScheduleEvent(EVENT_POISON, urandms(10, 20));
break;
case EVENT_SUMMON:
- /// @todo Add missing text
+ Talk(EMOTE_SPIDERS);
uint8 amount = urand(8, 10);
for (uint8 i = 0; i < amount; ++i)
- DoSummon(NPC_SPIDERLING, me, 0, TEMPSUMMON_CORPSE_DESPAWN);
+ DoSummon(NPC_SPIDERLING, me, 4.0f, 5 * IN_MILLISECONDS, TEMPSUMMON_CORPSE_TIMED_DESPAWN);
events.ScheduleEvent(EVENT_SUMMON, 40000);
break;
}
@@ -165,23 +197,49 @@ public:
struct npc_webwrapAI : public NullCreatureAI
{
- npc_webwrapAI(Creature* creature) : NullCreatureAI(creature) { }
+ npc_webwrapAI(Creature* creature) : NullCreatureAI(creature), visibleTimer(0) { }
ObjectGuid victimGUID;
+ uint32 visibleTimer;
+
+ void InitializeAI() override
+ {
+ me->SetVisible(false);
+ }
void SetGUID(ObjectGuid guid, int32 /*param*/) override
{
+ if (!guid)
+ return;
victimGUID = guid;
- if (me->m_spells[0] && victimGUID)
- if (Unit* victim = ObjectAccessor::GetUnit(*me, victimGUID))
- victim->CastSpell(victim, me->m_spells[0], true, NULL, NULL, me->GetGUID());
+ if (Unit* victim = ObjectAccessor::GetUnit(*me, victimGUID))
+ {
+ visibleTimer = (me->GetDistance2d(victim)/WEB_WRAP_MOVE_SPEED + 0.5f) * IN_MILLISECONDS;
+ victim->CastSpell(victim, SPELL_WEB_WRAP, true, NULL, NULL, me->GetGUID());
+ }
+ }
+
+ void UpdateAI(uint32 diff) override
+ {
+ if (!visibleTimer)
+ return;
+
+ if (diff >= visibleTimer)
+ {
+ visibleTimer = 0;
+ me->SetVisible(true);
+ }
+ else
+ visibleTimer -= diff;
}
void JustDied(Unit* /*killer*/) override
{
- if (me->m_spells[0] && victimGUID)
+ if (victimGUID)
if (Unit* victim = ObjectAccessor::GetUnit(*me, victimGUID))
- victim->RemoveAurasDueToSpell(me->m_spells[0], me->GetGUID());
+ victim->RemoveAurasDueToSpell(SPELL_WEB_WRAP, me->GetGUID());
+
+ me->DespawnOrUnsummon(5 * IN_MILLISECONDS);
}
};
diff --git a/src/server/scripts/Northrend/Naxxramas/boss_noth.cpp b/src/server/scripts/Northrend/Naxxramas/boss_noth.cpp
index 106661b70bf..7b3a9f8ac74 100644
--- a/src/server/scripts/Northrend/Naxxramas/boss_noth.cpp
+++ b/src/server/scripts/Northrend/Naxxramas/boss_noth.cpp
@@ -155,7 +155,7 @@ public:
void KilledUnit(Unit* victim) override
{
- if(victim->GetTypeId() == TYPEID_PLAYER)
+ if (victim->GetTypeId() == TYPEID_PLAYER)
Talk(SAY_SLAY);
}
diff --git a/src/server/scripts/Northrend/Naxxramas/boss_razuvious.cpp b/src/server/scripts/Northrend/Naxxramas/boss_razuvious.cpp
index 1683667a02a..f94f7b227bf 100644
--- a/src/server/scripts/Northrend/Naxxramas/boss_razuvious.cpp
+++ b/src/server/scripts/Northrend/Naxxramas/boss_razuvious.cpp
@@ -17,43 +17,40 @@
#include "ScriptMgr.h"
#include "ScriptedCreature.h"
+#include "SpellInfo.h"
#include "naxxramas.h"
-//Razuvious - NO TEXT sound only
-//8852 aggro01 - Hah hah, I'm just getting warmed up!
-//8853 aggro02 Stand and fight!
-//8854 aggro03 Show me what you've got!
-//8861 slay1 - You should've stayed home!
-//8863 slay2-
-//8858 cmmnd3 - You disappoint me, students!
-//8855 cmmnd1 - Do as I taught you!
-//8856 cmmnd2 - Show them no mercy!
-//8859 cmmnd4 - The time for practice is over! Show me what you've learned!
-//8861 Sweep the leg! Do you have a problem with that?
-//8860 death - An honorable... death...
-//8947 - Aggro Mixed? - ?
-
-#define SOUND_AGGRO RAND(8852, 8853, 8854)
-#define SOUND_SLAY RAND(8861, 8863)
-#define SOUND_COMMND RAND(8855, 8856, 8858, 8859, 8861)
-#define SOUND_DEATH 8860
-#define SOUND_AGGROMIX 8847
+enum Yells
+{
+ SAY_AGGRO = 0,
+ SAY_SLAY = 1,
+ SAY_TAUNTED = 2,
+ SAY_DEATH = 3
+};
enum Spells
{
- SPELL_UNBALANCING_STRIKE = 26613,
- SPELL_DISRUPTING_SHOUT = 29107,
- SPELL_JAGGED_KNIFE = 55550,
- SPELL_HOPELESS = 29125
+ SPELL_UNBALANCING_STRIKE = 26613,
+ SPELL_DISRUPTING_SHOUT = 29107,
+ SPELL_JAGGED_KNIFE = 55550,
+ SPELL_HOPELESS = 29125,
+ SPELL_UNDERSTUDY_TAUNT = 29060,
+ SPELL_UNDERSTUDY_BLOOD_STRIKE = 61696,
+ SPELL_FORCE_OBEDIENCE = 55479
};
enum Events
{
- EVENT_NONE,
+ EVENT_ATTACK = 1,
EVENT_STRIKE,
EVENT_SHOUT,
- EVENT_KNIFE,
- EVENT_COMMAND,
+ EVENT_KNIFE
+};
+
+enum SummonGroups
+{
+ SUMMON_GROUP_10MAN = 1,
+ SUMMON_GROUP_25MAN = 2
};
class boss_razuvious : public CreatureScript
@@ -70,36 +67,60 @@ public:
{
boss_razuviousAI(Creature* creature) : BossAI(creature, BOSS_RAZUVIOUS) { }
- void KilledUnit(Unit* /*victim*/) override
+ void SummonAdds()
{
- if (!(rand32() % 3))
- DoPlaySoundToSet(me, SOUND_SLAY);
+ me->SummonCreatureGroup(SUMMON_GROUP_10MAN);
+ if (Is25ManRaid())
+ me->SummonCreatureGroup(SUMMON_GROUP_25MAN);
}
- void DamageTaken(Unit* pDone_by, uint32& uiDamage) override
+ void InitializeAI() override
{
- // Damage done by the controlled Death Knight understudies should also count toward damage done by players
- if (pDone_by->GetTypeId() == TYPEID_UNIT && (pDone_by->GetEntry() == 16803 || pDone_by->GetEntry() == 29941))
+ if (!me->isDead())
{
- me->LowerPlayerDamageReq(uiDamage);
+ Reset();
+ SummonAdds();
}
}
+ void JustReachedHome() override
+ {
+ _JustReachedHome();
+ SummonAdds();
+ me->GetMotionMaster()->Initialize();
+ }
+
+ void KilledUnit(Unit* victim) override
+ {
+ if (victim->GetTypeId() == TYPEID_PLAYER || (victim->GetTypeId() == TYPEID_UNIT && victim->GetEntry() == NPC_DK_UNDERSTUDY))
+ Talk(SAY_SLAY);
+ }
+
+ void SpellHit(Unit* caster, SpellInfo const* spell) override
+ {
+ if (spell->Id == SPELL_UNDERSTUDY_TAUNT)
+ Talk(SAY_TAUNTED, caster);
+ }
+
void JustDied(Unit* /*killer*/) override
{
- _JustDied();
- DoPlaySoundToSet(me, SOUND_DEATH);
- me->CastSpell(me, SPELL_HOPELESS, true); /// @todo this may affect other creatures
+ Talk(SAY_DEATH);
+ DoCastAOE(SPELL_HOPELESS, true);
+
+ events.Reset();
+ instance->SetBossState(BOSS_RAZUVIOUS, DONE);
}
void EnterCombat(Unit* /*who*/) override
{
_EnterCombat();
- DoPlaySoundToSet(me, SOUND_AGGRO);
- events.ScheduleEvent(EVENT_STRIKE, 30000);
- events.ScheduleEvent(EVENT_SHOUT, 25000);
- events.ScheduleEvent(EVENT_COMMAND, 40000);
- events.ScheduleEvent(EVENT_KNIFE, 10000);
+ me->StopMoving();
+ summons.DoZoneInCombat();
+ Talk(SAY_AGGRO);
+ events.ScheduleEvent(EVENT_ATTACK, 7 * IN_MILLISECONDS);
+ events.ScheduleEvent(EVENT_STRIKE, 21 * IN_MILLISECONDS);
+ events.ScheduleEvent(EVENT_SHOUT, 16 * IN_MILLISECONDS);
+ events.ScheduleEvent(EVENT_KNIFE, 10 * IN_MILLISECONDS);
}
void UpdateAI(uint32 diff) override
@@ -113,33 +134,112 @@ public:
{
switch (eventId)
{
+ case EVENT_ATTACK:
+ SetCombatMovement(true);
+ if (Unit* victim = me->GetVictim())
+ me->GetMotionMaster()->MoveChase(victim);
+ break;
case EVENT_STRIKE:
DoCastVictim(SPELL_UNBALANCING_STRIKE);
- events.ScheduleEvent(EVENT_STRIKE, 30000);
+ events.ScheduleEvent(EVENT_STRIKE, 6 * IN_MILLISECONDS);
return;
case EVENT_SHOUT:
DoCastAOE(SPELL_DISRUPTING_SHOUT);
- events.ScheduleEvent(EVENT_SHOUT, 25000);
+ events.ScheduleEvent(EVENT_SHOUT, 16 * IN_MILLISECONDS);
return;
case EVENT_KNIFE:
if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 45.0f))
DoCast(target, SPELL_JAGGED_KNIFE);
- events.ScheduleEvent(EVENT_KNIFE, 10000);
- return;
- case EVENT_COMMAND:
- DoPlaySoundToSet(me, SOUND_COMMND);
- events.ScheduleEvent(EVENT_COMMAND, 40000);
+ events.ScheduleEvent(EVENT_KNIFE, urandms(10,15));
return;
}
}
DoMeleeAttackIfReady();
}
+
+ void Reset() override
+ {
+ SetCombatMovement(false);
+ _Reset();
+ }
};
};
+class npc_dk_understudy : public CreatureScript
+{
+ public:
+ npc_dk_understudy() : CreatureScript("npc_dk_understudy") { }
+
+ struct npc_dk_understudyAI : public ScriptedAI
+ {
+ npc_dk_understudyAI(Creature* creature) : ScriptedAI(creature), _instance(creature->GetInstanceScript()), bloodStrikeTimer(0) { }
+
+ void EnterCombat(Unit* /*who*/) override
+ {
+ me->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_ONESHOT_NONE);
+ if (Creature* razuvious = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_RAZUVIOUS)))
+ razuvious->AI()->DoZoneInCombat(nullptr, 250.0f);
+ }
+
+ void JustReachedHome() override
+ {
+ if (_instance->GetBossState(BOSS_RAZUVIOUS) == DONE)
+ me->DespawnOrUnsummon();
+ else
+ ScriptedAI::JustReachedHome();
+ }
+
+ void UpdateAI(uint32 diff) override
+ {
+ if (!me->isPossessedByPlayer() && !UpdateVictim())
+ return;
+
+ if (!me->isPossessedByPlayer())
+ {
+ if (diff < bloodStrikeTimer)
+ bloodStrikeTimer -= diff;
+ else
+ DoCastVictim(SPELL_UNDERSTUDY_BLOOD_STRIKE);
+ }
+
+ DoMeleeAttackIfReady();
+ }
+
+ void OnCharmed(bool apply) override
+ {
+ ScriptedAI::OnCharmed(apply);
+ if (apply)
+ {
+ if (!me->IsInCombat())
+ EnterCombat(nullptr);
+ me->StopMoving();
+ me->SetReactState(REACT_PASSIVE);
+ _charmer = me->GetCharmerGUID();
+ }
+ else
+ {
+ me->SetReactState(REACT_AGGRESSIVE);
+ if (Unit* charmer = ObjectAccessor::GetUnit(*me, _charmer))
+ me->AddThreat(charmer, 100000.0f);
+ DoZoneInCombat(nullptr, 250.0f);
+ }
+ }
+ private:
+ InstanceScript* const _instance;
+ ObjectGuid _charmer;
+ uint32 bloodStrikeTimer;
+ };
+
+ CreatureAI* GetAI(Creature* creature) const override
+ {
+ return GetInstanceAI<npc_dk_understudyAI>(creature);
+ }
+};
+
void AddSC_boss_razuvious()
{
new boss_razuvious();
+ new npc_dk_understudy();
}
diff --git a/src/server/scripts/Northrend/Naxxramas/boss_thaddius.cpp b/src/server/scripts/Northrend/Naxxramas/boss_thaddius.cpp
index d74fd5a03f8..5d3b038d41d 100644
--- a/src/server/scripts/Northrend/Naxxramas/boss_thaddius.cpp
+++ b/src/server/scripts/Northrend/Naxxramas/boss_thaddius.cpp
@@ -19,48 +19,104 @@
#include "ScriptedCreature.h"
#include "SpellScript.h"
#include "Player.h"
+#include "ObjectGuid.h"
#include "naxxramas.h"
-//Stalagg
-enum StalaggYells
+
+enum Phases
+{
+ PHASE_NOT_ENGAGED = 1,
+ PHASE_PETS,
+ PHASE_TRANSITION,
+ PHASE_THADDIUS,
+ PHASE_RESETTING
+};
+
+enum AIActions
{
- SAY_STAL_AGGRO = 0,
- SAY_STAL_SLAY = 1,
- SAY_STAL_DEATH = 2
+ ACTION_RESET_ENCOUNTER_TIMER = -1, // sent from instance AI
+ ACTION_BEGIN_RESET_ENCOUNTER = 0, // sent from thaddius to pets to trigger despawn and encounter reset
+ ACTION_RESET_ENCOUNTER, // sent from thaddius to pets to trigger respawn and full reset
+ ACTION_FEUGEN_DIED, // sent from respective pet to thaddius to indicate death
+ ACTION_STALAGG_DIED, // ^
+ ACTION_FEUGEN_RESET, // pet to thaddius
+ ACTION_STALAGG_RESET, // ^
+ ACTION_FEUGEN_AGGRO, // pet to thaddius on combat start
+ ACTION_STALAGG_AGGRO, // ^
+ ACTION_FEUGEN_REVIVING_FX, // thaddius to pet when pet reports its death
+ ACTION_STALAGG_REVIVING_FX, // ^
+ ACTION_FEUGEN_REVIVED, // thaddius to pet when pet should revive
+ ACTION_STALAGG_REVIVED, // ^
+ ACTION_TRANSITION, // thaddius to pets when transition starts (coil overload anim)
+ ACTION_TRANSITION_2, // thaddius to pets to make the coils shock him
+ ACTION_TRANSITION_3, // thaddius to pets to disable coil GO after spawn
+
+ ACTION_POLARITY_CROSSED // triggers achievement failure, sent from spellscript
};
-enum StalagSpells
+enum Events
{
- SPELL_POWERSURGE = 28134,
- SPELL_MAGNETIC_PULL = 28338,
- SPELL_STALAGG_TESLA = 28097
+ EVENT_SHIFT = 1, // polarity shift
+ EVENT_SHIFT_TALK, // polarity shift yell (hack? couldn't find any event for cast finish)
+ EVENT_CHAIN, // chain lightning
+ EVENT_BERSERK, // enrage timer
+ EVENT_REVIVE_FEUGEN, // timer until feugen is revived (if stalagg still lives)
+ EVENT_REVIVE_STALAGG, // timer until stalagg is revived (if feugen still lives)
+ EVENT_TRANSITION_1, // timer until overload emote
+ EVENT_TRANSITION_2, // timer until thaddius gets zapped by the coils
+ EVENT_TRANSITION_3, // timer until thaddius engages
+ EVENT_ENABLE_BALL_LIGHTNING // grace period after thaddius aggro after which he starts being a baller (e.g. tossing ball lightning at out of range targets)
};
-//Feugen
-enum FeugenYells
+enum Misc
{
- SAY_FEUG_AGGRO = 0,
- SAY_FEUG_SLAY = 1,
- SAY_FEUG_DEATH = 2
+ MAX_POLARITY_10M = 5,
+ MAX_POLARITY_25M = 13,
+
+ DATA_POLARITY_CROSSED = 1,
+};
+
+// Feugen & Stalagg
+enum PetYells
+{
+ SAY_STALAGG_AGGRO = 0,
+ SAY_STALAGG_SLAY = 1,
+ SAY_STALAGG_DEATH = 2,
+
+ SAY_FEUGEN_AGGRO = 0,
+ SAY_FEUGEN_SLAY = 1,
+ SAY_FEUGEN_DEATH = 2,
+
+ EMOTE_FEIGN_DEATH = 3,
+ EMOTE_FEIGN_REVIVE = 4,
+
+ EMOTE_TESLA_LINK_BREAKS = 0,
+ EMOTE_TESLA_OVERLOAD = 1
};
-enum FeugenSpells
+enum PetSpells
{
- SPELL_STATICFIELD = 28135,
- SPELL_FEUGEN_TESLA = 28109
+ SPELL_STALAGG_POWERSURGE = 28134,
+ //SPELL_STALAGG_TESLA = 28097,
+ SPELL_STALAGG_TESLA_PERIODIC = 28098,
+ SPELL_STALAGG_CHAIN_VISUAL = 28096,
+
+ SPELL_FEUGEN_STATICFIELD = 28135,
+ //SPELL_FEUGEN_TESLA = 28109,
+ SPELL_FEUGEN_TESLA_PERIODIC = 28110,
+ SPELL_FEUGEN_CHAIN_VISUAL = 28111,
+
+ SPELL_MAGNETIC_PULL = 54517,
+ SPELL_MAGNETIC_PULL_EFFECT = 28337,
+
+ SPELL_TESLA_SHOCK = 28099
};
-// Thaddius DoAction
-enum ThaddiusActions
+enum PetMisc
{
- ACTION_FEUGEN_RESET,
- ACTION_FEUGEN_DIED,
- ACTION_STALAGG_RESET,
- ACTION_STALAGG_DIED
+ OVERLOAD_DISTANCE = 28
};
-//generic
-#define C_TESLA_COIL 16218 //the coils (emotes "Tesla Coil overloads!")
//Thaddius
enum ThaddiusYells
@@ -70,34 +126,31 @@ enum ThaddiusYells
SAY_SLAY = 2,
SAY_ELECT = 3,
SAY_DEATH = 4,
- SAY_SCREAM = 5
+ SAY_SCREAM = 5,
+
+ EMOTE_POLARITY_SHIFTED = 6
};
enum ThaddiusSpells
{
- SPELL_POLARITY_SHIFT = 28089,
- SPELL_BALL_LIGHTNING = 28299,
- SPELL_CHAIN_LIGHTNING = 28167,
- SPELL_BERSERK = 27680,
- SPELL_POSITIVE_CHARGE = 28062,
- SPELL_POSITIVE_CHARGE_STACK = 29659,
- SPELL_NEGATIVE_CHARGE = 28085,
- SPELL_NEGATIVE_CHARGE_STACK = 29660,
- SPELL_POSITIVE_POLARITY = 28059,
- SPELL_NEGATIVE_POLARITY = 28084,
-};
+ SPELL_THADDIUS_INACTIVE_VISUAL = 28160,
+ SPELL_THADDIUS_SPARK_VISUAL = 28136,
+ SPELL_SHOCK_VISUAL = 28159,
-enum Events
-{
- EVENT_NONE,
- EVENT_SHIFT,
- EVENT_CHAIN,
- EVENT_BERSERK,
-};
+ SPELL_BALL_LIGHTNING = 28299,
+ SPELL_CHAIN_LIGHTNING = 28167,
+ SPELL_BERSERK = 27680,
-enum Achievement
-{
- DATA_POLARITY_SWITCH = 76047605,
+ // polarity handling
+ SPELL_POLARITY_SHIFT = 28089,
+
+ SPELL_POSITIVE_CHARGE_APPLY = 28059,
+ SPELL_POSITIVE_CHARGE_TICK = 28062,
+ SPELL_POSITIVE_CHARGE_AMP = 29659,
+
+ SPELL_NEGATIVE_CHARGE_APPLY = 28084,
+ SPELL_NEGATIVE_CHARGE_TICK = 28085,
+ SPELL_NEGATIVE_CHARGE_AMP = 29660,
};
class boss_thaddius : public CreatureScript
@@ -112,166 +165,276 @@ public:
struct boss_thaddiusAI : public BossAI
{
- boss_thaddiusAI(Creature* creature) : BossAI(creature, BOSS_THADDIUS)
- {
- // init is a bit tricky because thaddius shall track the life of both adds, but not if there was a wipe
- // and, in particular, if there was a crash after both adds were killed (should not respawn)
-
- // Moreover, the adds may not yet be spawn. So just track down the status if mob is spawn
- // and each mob will send its status at reset (meaning that it is alive)
- checkFeugenAlive = false;
- if (Creature* pFeugen = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_FEUGEN)))
- checkFeugenAlive = pFeugen->IsAlive();
+ public:
+ boss_thaddiusAI(Creature* creature) : BossAI(creature, BOSS_THADDIUS), stalaggAlive(true), feugenAlive(true), ballLightningEnabled(false), shockingEligibility(true)
+ {
+ if (instance->GetBossState(BOSS_THADDIUS) != DONE)
+ {
+ events.SetPhase(PHASE_NOT_ENGAGED);
+ SetCombatMovement(false);
- checkStalaggAlive = false;
- if (Creature* pStalagg = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_STALAGG)))
- checkStalaggAlive = pStalagg->IsAlive();
+ // initialize everything properly, and ensure that the coils are loaded by the time we initialize
+ BeginResetEncounter(true);
+ }
+ }
- if (!checkFeugenAlive && !checkStalaggAlive)
+ void KilledUnit(Unit* victim) override
{
- me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC | UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_STUNNED);
- me->SetReactState(REACT_AGGRESSIVE);
+ if (victim->GetTypeId() == TYPEID_PLAYER)
+ Talk(SAY_SLAY);
}
- else
+
+ void Reset() override
{
- me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC | UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_STUNNED);
- me->SetReactState(REACT_PASSIVE);
+ if (events.IsInPhase(PHASE_TRANSITION) || (events.IsInPhase(PHASE_THADDIUS) && me->IsAlive()))
+ BeginResetEncounter();
}
- polaritySwitch = false;
- uiAddsTimer = 0;
- }
-
- bool checkStalaggAlive;
- bool checkFeugenAlive;
- bool polaritySwitch;
- uint32 uiAddsTimer;
-
- void KilledUnit(Unit* /*victim*/) override
- {
- if (!(rand32() % 5))
- Talk(SAY_SLAY);
- }
-
- void JustDied(Unit* /*killer*/) override
- {
- _JustDied();
- Talk(SAY_DEATH);
- }
+ void JustDied(Unit* /*killer*/) override
+ {
+ _JustDied();
+ me->setActive(false);
+ if (Creature* stalagg = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_STALAGG)))
+ stalagg->setActive(false);
+ if (Creature* feugen = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_FEUGEN)))
+ feugen->setActive(false);
+ Talk(SAY_DEATH);
+ }
- void DoAction(int32 action) override
- {
- switch (action)
+ void DoAction(int32 action) override
{
- case ACTION_FEUGEN_RESET:
- checkFeugenAlive = true;
- break;
- case ACTION_FEUGEN_DIED:
- checkFeugenAlive = false;
- break;
- case ACTION_STALAGG_RESET:
- checkStalaggAlive = true;
- break;
- case ACTION_STALAGG_DIED:
- checkStalaggAlive = false;
- break;
+ switch (action)
+ {
+ case ACTION_RESET_ENCOUNTER_TIMER:
+ if (events.IsInPhase(PHASE_RESETTING))
+ ResetEncounter();
+ break;
+ case ACTION_FEUGEN_RESET:
+ case ACTION_STALAGG_RESET:
+ if (!events.IsInPhase(PHASE_NOT_ENGAGED) && !events.IsInPhase(PHASE_RESETTING))
+ BeginResetEncounter();
+ break;
+ case ACTION_FEUGEN_AGGRO:
+ case ACTION_STALAGG_AGGRO:
+ if (events.IsInPhase(PHASE_RESETTING))
+ return BeginResetEncounter();
+ if (!events.IsInPhase(PHASE_NOT_ENGAGED))
+ return;
+ events.SetPhase(PHASE_PETS);
+
+ shockingEligibility = true;
+
+ if (!instance->CheckRequiredBosses(BOSS_THADDIUS))
+ return BeginResetEncounter();
+ instance->SetBossState(BOSS_THADDIUS, IN_PROGRESS);
+
+ me->setActive(true);
+ if (Creature* stalagg = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_STALAGG)))
+ stalagg->setActive(true);
+ if (Creature* feugen = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_FEUGEN)))
+ feugen->setActive(true);
+ break;
+ case ACTION_FEUGEN_DIED:
+ if (Creature* feugen = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_FEUGEN)))
+ feugen->AI()->DoAction(ACTION_FEUGEN_REVIVING_FX);
+ feugenAlive = false;
+ if (stalaggAlive)
+ events.ScheduleEvent(EVENT_REVIVE_FEUGEN, 5 * IN_MILLISECONDS, 0, PHASE_PETS);
+ else
+ Transition();
+
+ break;
+ case ACTION_STALAGG_DIED:
+ if (Creature* stalagg = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_STALAGG)))
+ stalagg->AI()->DoAction(ACTION_STALAGG_REVIVING_FX);
+ stalaggAlive = false;
+ if (feugenAlive)
+ events.ScheduleEvent(EVENT_REVIVE_STALAGG, 5 * IN_MILLISECONDS, 0, PHASE_PETS);
+ else
+ Transition();
+
+ break;
+
+ case ACTION_POLARITY_CROSSED:
+ shockingEligibility = false;
+ break;
+ default:
+ break;
+ }
}
- if (!checkFeugenAlive && !checkStalaggAlive)
+ uint32 GetData(uint32 id) const override
{
- me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC | UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_STUNNED);
- // REACT_AGGRESSIVE only reset when he takes damage.
- DoZoneInCombat();
+ return (id == DATA_POLARITY_CROSSED && shockingEligibility) ? 1u : 0u;
}
- else
+
+ void Transition() // initiate transition between pet phase and thaddius phase
{
- me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC | UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_STUNNED);
- me->SetReactState(REACT_PASSIVE);
+ events.SetPhase(PHASE_TRANSITION);
+
+ me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
+
+ events.ScheduleEvent(EVENT_TRANSITION_1, 10 * IN_MILLISECONDS, 0, PHASE_TRANSITION);
+ events.ScheduleEvent(EVENT_TRANSITION_2, 12 * IN_MILLISECONDS, 0, PHASE_TRANSITION);
+ events.ScheduleEvent(EVENT_TRANSITION_3, 14 * IN_MILLISECONDS, 0, PHASE_TRANSITION);
}
- }
- void EnterCombat(Unit* /*who*/) override
- {
- _EnterCombat();
- Talk(SAY_AGGRO);
- events.ScheduleEvent(EVENT_SHIFT, 30000);
- events.ScheduleEvent(EVENT_CHAIN, urand(10000, 20000));
- events.ScheduleEvent(EVENT_BERSERK, 360000);
- }
+ void BeginResetEncounter(bool initial = false)
+ {
+ if (instance->GetBossState(BOSS_THADDIUS) == DONE)
+ return;
+ if (events.IsInPhase(PHASE_RESETTING))
+ return;
- void DamageTaken(Unit* /*pDoneBy*/, uint32 & /*uiDamage*/) override
- {
- me->SetReactState(REACT_AGGRESSIVE);
- }
+ if (initial) // signal shorter spawn timer to instance script
+ instance->SetBossState(BOSS_THADDIUS, SPECIAL);
+ instance->ProcessEvent(me, EVENT_THADDIUS_BEGIN_RESET);
+ instance->SetBossState(BOSS_THADDIUS, NOT_STARTED);
- void SetData(uint32 id, uint32 data) override
- {
- if (id == DATA_POLARITY_SWITCH)
- polaritySwitch = data ? true : false;
- }
+ // remove polarity shift debuffs on reset
+ instance->DoRemoveAurasDueToSpellOnPlayers(SPELL_POSITIVE_CHARGE_APPLY);
+ instance->DoRemoveAurasDueToSpellOnPlayers(SPELL_NEGATIVE_CHARGE_APPLY);
- uint32 GetData(uint32 id) const override
- {
- if (id != DATA_POLARITY_SWITCH)
- return 0;
+ me->DespawnOrUnsummon();
- return uint32(polaritySwitch);
- }
+ me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC | UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_STUNNED);
+ events.SetPhase(PHASE_RESETTING);
+ if (Creature* feugen = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_FEUGEN)))
+ feugen->AI()->DoAction(ACTION_BEGIN_RESET_ENCOUNTER);
+ if (Creature* stalagg = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_STALAGG)))
+ stalagg->AI()->DoAction(ACTION_BEGIN_RESET_ENCOUNTER);
- void UpdateAI(uint32 diff) override
- {
- if (checkFeugenAlive && checkStalaggAlive)
- uiAddsTimer = 0;
+ me->setActive(false);
+ }
- if (checkStalaggAlive != checkFeugenAlive)
+ void ResetEncounter()
{
- uiAddsTimer += diff;
- if (uiAddsTimer > 5000)
- {
- if (!checkStalaggAlive)
- {
- if (Creature* pStalagg = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_STALAGG)))
- pStalagg->Respawn();
- }
- else
- {
- if (Creature* pFeugen = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_FEUGEN)))
- pFeugen->Respawn();
- }
- }
- }
+ feugenAlive = true;
+ stalaggAlive = true;
- if (!UpdateVictim())
- return;
+ me->Respawn(true);
+ _Reset();
+ events.SetPhase(PHASE_NOT_ENGAGED);
- events.Update(diff);
+ me->CastSpell(me, SPELL_THADDIUS_INACTIVE_VISUAL, true);
- if (me->HasUnitState(UNIT_STATE_CASTING))
- return;
+ if (Creature* feugen = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_FEUGEN)))
+ feugen->AI()->DoAction(ACTION_RESET_ENCOUNTER);
+ if (Creature* stalagg = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_STALAGG)))
+ stalagg->AI()->DoAction(ACTION_RESET_ENCOUNTER);
+ }
- while (uint32 eventId = events.ExecuteEvent())
+ void UpdateAI(uint32 diff) override
{
- switch (eventId)
+ if (events.IsInPhase(PHASE_NOT_ENGAGED))
+ return;
+ if (events.IsInPhase(PHASE_THADDIUS) && !UpdateVictim())
+ return;
+
+ events.Update(diff);
+ while (uint32 eventId = events.ExecuteEvent())
{
- case EVENT_SHIFT:
- DoCastAOE(SPELL_POLARITY_SHIFT);
- events.ScheduleEvent(EVENT_SHIFT, 30000);
- return;
- case EVENT_CHAIN:
- DoCastVictim(SPELL_CHAIN_LIGHTNING);
- events.ScheduleEvent(EVENT_CHAIN, urand(10000, 20000));
- return;
- case EVENT_BERSERK:
- DoCast(me, SPELL_BERSERK);
- return;
+ switch (eventId)
+ {
+ case EVENT_REVIVE_FEUGEN:
+ feugenAlive = true;
+ if (Creature* feugen = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_FEUGEN)))
+ feugen->AI()->DoAction(ACTION_FEUGEN_REVIVED);
+ break;
+ case EVENT_REVIVE_STALAGG:
+ stalaggAlive = true;
+ if (Creature* stalagg = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_STALAGG)))
+ stalagg->AI()->DoAction(ACTION_STALAGG_REVIVED);
+ break;
+ case EVENT_TRANSITION_1: // tesla coils overload
+ if (Creature* feugen = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_FEUGEN)))
+ feugen->AI()->DoAction(ACTION_TRANSITION);
+ if (Creature* stalagg = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_STALAGG)))
+ stalagg->AI()->DoAction(ACTION_TRANSITION);
+ break;
+ case EVENT_TRANSITION_2: // tesla coils shock thaddius
+ me->CastSpell(me, SPELL_THADDIUS_SPARK_VISUAL, true);
+ if (Creature* feugen = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_FEUGEN)))
+ feugen->AI()->DoAction(ACTION_TRANSITION_2);
+ if (Creature* stalagg = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_STALAGG)))
+ stalagg->AI()->DoAction(ACTION_TRANSITION_2);
+ break;
+ case EVENT_TRANSITION_3: // thaddius becomes active
+ me->CastSpell(me, SPELL_THADDIUS_SPARK_VISUAL, true);
+ ballLightningEnabled = false;
+ me->RemoveAura(SPELL_THADDIUS_INACTIVE_VISUAL);
+ me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_STUNNED);
+ me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC);
+
+ DoZoneInCombat();
+ if (Unit* closest = SelectTarget(SELECT_TARGET_NEAREST, 0, 500.0f))
+ AttackStart(closest);
+ else // if there is no nearest target, then there is no target, meaning we should reset
+ return BeginResetEncounter();
+
+ if (Creature* feugen = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_FEUGEN)))
+ feugen->AI()->DoAction(ACTION_TRANSITION_3);
+ if (Creature* stalagg = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_STALAGG)))
+ stalagg->AI()->DoAction(ACTION_TRANSITION_3);
+
+ events.SetPhase(PHASE_THADDIUS);
+
+ Talk(SAY_AGGRO);
+
+ events.ScheduleEvent(EVENT_ENABLE_BALL_LIGHTNING, 5 * IN_MILLISECONDS, 0, PHASE_THADDIUS);
+ events.ScheduleEvent(EVENT_SHIFT, 10 * IN_MILLISECONDS, 0, PHASE_THADDIUS);
+ events.ScheduleEvent(EVENT_CHAIN, urand(10, 20) * IN_MILLISECONDS, 0, PHASE_THADDIUS);
+ events.ScheduleEvent(EVENT_BERSERK, 6 * MINUTE * IN_MILLISECONDS, 0, PHASE_THADDIUS);
+
+ break;
+ case EVENT_ENABLE_BALL_LIGHTNING:
+ ballLightningEnabled = true;
+ break;
+ case EVENT_SHIFT:
+ me->CastStop(); // shift overrides all other spells
+ DoCastAOE(SPELL_POLARITY_SHIFT);
+ events.ScheduleEvent(EVENT_SHIFT_TALK, 3 * IN_MILLISECONDS, PHASE_THADDIUS);
+ events.ScheduleEvent(EVENT_SHIFT, 30 * IN_MILLISECONDS, PHASE_THADDIUS);
+ break;
+ case EVENT_SHIFT_TALK:
+ Talk(SAY_ELECT);
+ Talk(EMOTE_POLARITY_SHIFTED);
+ break;
+ case EVENT_CHAIN:
+ if (me->FindCurrentSpellBySpellId(SPELL_POLARITY_SHIFT)) // delay until shift is over
+ events.ScheduleEvent(EVENT_CHAIN, 3 * IN_MILLISECONDS, 0, PHASE_THADDIUS);
+ else
+ {
+ me->CastStop();
+ DoCastVictim(SPELL_CHAIN_LIGHTNING);
+ events.ScheduleEvent(EVENT_CHAIN, urand(10, 20) * IN_MILLISECONDS, PHASE_THADDIUS);
+ }
+ break;
+ case EVENT_BERSERK:
+ me->CastStop();
+ DoCast(me, SPELL_BERSERK);
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (events.IsInPhase(PHASE_THADDIUS))
+ {
+ if (me->IsWithinMeleeRange(me->GetVictim()))
+ DoMeleeAttackIfReady();
+ else
+ if (ballLightningEnabled)
+ if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM))
+ DoCast(target, SPELL_BALL_LIGHTNING);
}
}
- if (events.GetTimer() > 15000 && !me->IsWithinMeleeRange(me->GetVictim()))
- DoCastVictim(SPELL_BALL_LIGHTNING);
- else
- DoMeleeAttackIfReady();
- }
+ private:
+ bool stalaggAlive;
+ bool feugenAlive;
+ bool ballLightningEnabled;
+ bool shockingEligibility;
};
};
@@ -288,88 +451,257 @@ public:
struct npc_stalaggAI : public ScriptedAI
{
- npc_stalaggAI(Creature* creature) : ScriptedAI(creature)
- {
- Initialize();
- instance = creature->GetInstanceScript();
- }
+ public:
+ npc_stalaggAI(Creature* creature) : ScriptedAI(creature), _myCoil(ObjectGuid::Empty), _myCoilGO(ObjectGuid::Empty), isOverloading(false), refreshBeam(false), isFeignDeath(false)
+ {
+ Initialize();
+ instance = creature->GetInstanceScript();
+ }
- void Initialize()
- {
- powerSurgeTimer = urand(20000, 25000);
- magneticPullTimer = 20000;
- }
+ void Initialize()
+ {
+ if (GameObject* coil = myCoilGO())
+ coil->SetGoState(GO_STATE_ACTIVE);
- InstanceScript* instance;
+ // if the encounter reset while feigning death
+ me->SetStandState(UNIT_STAND_STATE_STAND);
+ me->SetReactState(REACT_AGGRESSIVE);
+ me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
+ isOverloading = false;
+ isFeignDeath = false;
- uint32 powerSurgeTimer;
- uint32 magneticPullTimer;
+ // force tesla coil state refresh
+ refreshBeam = true;
- void Reset() override
- {
- if (Creature* pThaddius = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_THADDIUS)))
- if (pThaddius->AI())
- pThaddius->AI()->DoAction(ACTION_STALAGG_RESET);
- Initialize();
- }
+ powerSurgeTimer = 10 * IN_MILLISECONDS;
+ }
- void KilledUnit(Unit* /*victim*/) override
- {
- if (!(rand32() % 5))
- Talk(SAY_STAL_SLAY);
- }
+ void Reset() override
+ {
+ if (isFeignDeath || !me->IsAlive())
+ return;
+ if (Creature* thaddius = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_THADDIUS)))
+ thaddius->AI()->DoAction(ACTION_STALAGG_RESET);
+ }
- void EnterCombat(Unit* /*who*/) override
- {
- Talk(SAY_STAL_AGGRO);
- DoCast(SPELL_STALAGG_TESLA);
- }
+ void BeginResetEncounter()
+ {
+ if (GameObject* coil = myCoilGO())
+ coil->SetGoState(GO_STATE_READY);
+ me->DespawnOrUnsummon();
+ me->setActive(false);
+ }
- void JustDied(Unit* /*killer*/) override
- {
- Talk(SAY_STAL_DEATH);
- if (Creature* pThaddius = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_THADDIUS)))
- if (pThaddius->AI())
- pThaddius->AI()->DoAction(ACTION_STALAGG_DIED);
- }
+ void ResetEncounter()
+ {
+ me->Respawn(true);
+ Initialize();
+ }
- void UpdateAI(uint32 uiDiff) override
- {
- if (!UpdateVictim())
- return;
+ void DoAction(int32 action) override
+ {
+ switch (action)
+ {
+ case ACTION_BEGIN_RESET_ENCOUNTER:
+ BeginResetEncounter();
+ break;
+ case ACTION_RESET_ENCOUNTER:
+ ResetEncounter();
+ break;
+ case ACTION_STALAGG_REVIVING_FX:
+ break;
+ case ACTION_STALAGG_REVIVED:
+ if (!isFeignDeath)
+ break;
+
+ me->SetFullHealth();
+ me->SetStandState(UNIT_STAND_STATE_STAND);
+ me->SetReactState(REACT_AGGRESSIVE);
+ me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
+ Talk(EMOTE_FEIGN_REVIVE);
+ isFeignDeath = false;
+
+ refreshBeam = true; // force beam refresh
+
+ if (Creature* feugen = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_FEUGEN)))
+ if (feugen->GetVictim())
+ {
+ me->AddThreat(feugen->EnsureVictim(), 0.0f);
+ me->SetInCombatWith(feugen->EnsureVictim());
+ }
+ break;
+ case ACTION_TRANSITION:
+ me->KillSelf(); // true death
+ me->DespawnOrUnsummon();
+
+ if (Creature* coil = myCoil())
+ {
+ coil->CastStop();
+ coil->AI()->Talk(EMOTE_TESLA_OVERLOAD);
+ }
+ break;
+ case ACTION_TRANSITION_2:
+ if (Creature* coil = myCoil())
+ if (Creature* thaddius = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_THADDIUS)))
+ coil->CastSpell(thaddius, SPELL_SHOCK_VISUAL);
+ break;
+ case ACTION_TRANSITION_3:
+ if (GameObject* coil = myCoilGO())
+ coil->SetGoState(GO_STATE_READY);
+ break;
+ default:
+ break;
+ }
+ }
- if (magneticPullTimer <= uiDiff)
+ void KilledUnit(Unit* victim) override
{
- if (Creature* pFeugen = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_FEUGEN)))
+ if (victim->GetTypeId() == TYPEID_PLAYER)
+ Talk(SAY_STALAGG_SLAY);
+ }
+
+ void EnterCombat(Unit* who) override
+ {
+ Talk(SAY_STALAGG_AGGRO);
+
+ if (Creature* thaddius = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_THADDIUS)))
+ thaddius->AI()->DoAction(ACTION_STALAGG_AGGRO);
+
+ if (Creature* feugen = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_FEUGEN)))
+ if (!feugen->IsInCombat())
+ {
+ feugen->AddThreat(who, 0.0f);
+ feugen->SetInCombatWith(who);
+ }
+ }
+
+ void DamageTaken(Unit* /*who*/, uint32& damage) override
+ {
+ if (damage < me->GetHealth())
+ return;
+
+ if (isFeignDeath) // don't take damage while feigning death
{
- Unit* pStalaggVictim = me->GetVictim();
- Unit* pFeugenVictim = pFeugen->GetVictim();
+ damage = 0;
+ return;
+ }
+
+ isFeignDeath = true;
+ isOverloading = false;
+
+ Talk(EMOTE_FEIGN_DEATH);
+ if (Creature* thaddius = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_THADDIUS)))
+ thaddius->AI()->DoAction(ACTION_STALAGG_DIED);
+
+ me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
+ me->RemoveAllAuras();
+ me->SetReactState(REACT_PASSIVE);
+ me->AttackStop();
+ me->StopMoving();
+ me->SetStandState(UNIT_STAND_STATE_DEAD);
- if (pFeugenVictim && pStalaggVictim)
+ damage = 0;
+
+ // force beam refresh as we just removed auras
+ refreshBeam = true;
+ }
+
+ void SpellHit(Unit* caster, SpellInfo const* spell) override
+ {
+ if (!caster)
+ return;
+ if (spell->Id != SPELL_STALAGG_TESLA_PERIODIC)
+ return;
+ if (!isFeignDeath && me->IsInCombat() && !me->GetHomePosition().IsInDist(me, OVERLOAD_DISTANCE))
+ {
+ if (!isOverloading)
{
- // magnetic pull is not working. So just jump.
+ isOverloading = true;
+ caster->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC);
+ if (Creature* creatureCaster = caster->ToCreature())
+ creatureCaster->AI()->Talk(EMOTE_TESLA_LINK_BREAKS);
+ me->RemoveAura(SPELL_STALAGG_CHAIN_VISUAL);
+ }
+ if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM))
+ {
+ caster->CastStop(SPELL_TESLA_SHOCK);
+ caster->CastSpell(target, SPELL_TESLA_SHOCK,true);
+ }
+ }
+ else if (isOverloading || refreshBeam)
+ {
+ isOverloading = false;
+ refreshBeam = false;
+ caster->CastStop();
+ caster->CastSpell(me, SPELL_STALAGG_CHAIN_VISUAL, true);
+ caster->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC);
+ }
+ }
- // reset aggro to be sure that feugen will not follow the jump
- pFeugen->getThreatManager().modifyThreatPercent(pFeugenVictim, -100);
- pFeugenVictim->JumpTo(me, 0.3f);
+ void UpdateAI(uint32 uiDiff) override
+ {
+ if (!isFeignDeath)
+ if (!UpdateVictim())
+ return;
- me->getThreatManager().modifyThreatPercent(pStalaggVictim, -100);
- pStalaggVictim->JumpTo(pFeugen, 0.3f);
+ if (powerSurgeTimer <= uiDiff)
+ {
+ if (isFeignDeath) // delay until potential revive
+ powerSurgeTimer = 0u;
+ else
+ {
+ DoCast(me, SPELL_STALAGG_POWERSURGE);
+ powerSurgeTimer = urand(25, 30) * IN_MILLISECONDS;
}
}
+ else
+ powerSurgeTimer -= uiDiff;
- magneticPullTimer = 20000;
+ if (!isFeignDeath)
+ DoMeleeAttackIfReady();
}
- else magneticPullTimer -= uiDiff;
- if (powerSurgeTimer <= uiDiff)
+ private:
+ Creature* myCoil()
{
- DoCast(me, SPELL_POWERSURGE);
- powerSurgeTimer = urand(15000, 20000);
- } else powerSurgeTimer -= uiDiff;
+ Creature* coil = nullptr;
+ if (_myCoil)
+ coil = ObjectAccessor::GetCreature(*me, _myCoil);
+ if (!coil)
+ {
+ coil = me->FindNearestCreature(NPC_TESLA, 1000.0f, true);
+ if (coil)
+ {
+ _myCoil = coil->GetGUID();
+ coil->SetReactState(REACT_PASSIVE);
+ }
+ }
+ return coil;
+ }
- DoMeleeAttackIfReady();
- }
+ GameObject* myCoilGO()
+ {
+ GameObject* coil = nullptr;
+ if (_myCoilGO)
+ coil = ObjectAccessor::GetGameObject(*me, _myCoilGO);
+ if (!coil)
+ {
+ coil = me->FindNearestGameObject(GO_CONS_NOX_TESLA_STALAGG, 1000.0f);
+ if (coil)
+ _myCoilGO = coil->GetGUID();
+ }
+ return coil;
+ }
+
+ InstanceScript* instance;
+
+ uint32 powerSurgeTimer;
+
+ ObjectGuid _myCoil;
+ ObjectGuid _myCoilGO;
+ bool isOverloading;
+ bool refreshBeam;
+ bool isFeignDeath;
};
};
@@ -386,142 +718,381 @@ public:
struct npc_feugenAI : public ScriptedAI
{
- npc_feugenAI(Creature* creature) : ScriptedAI(creature)
- {
- Initialize();
- instance = creature->GetInstanceScript();
- }
-
- void Initialize()
- {
- staticFieldTimer = 5000;
- }
+ public:
+ npc_feugenAI(Creature* creature) : ScriptedAI(creature), _myCoil(ObjectGuid::Empty), _myCoilGO(ObjectGuid::Empty), isOverloading(false), refreshBeam(false), isFeignDeath(false)
+ {
+ Initialize();
+ instance = creature->GetInstanceScript();
+ }
- InstanceScript* instance;
+ void Initialize()
+ {
+ if (GameObject* coil = myCoilGO())
+ coil->SetGoState(GO_STATE_ACTIVE);
- uint32 staticFieldTimer;
+ // if the encounter reset while feigning death
+ me->SetStandState(UNIT_STAND_STATE_STAND);
+ me->SetReactState(REACT_AGGRESSIVE);
+ me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
+ isOverloading = false;
+ isFeignDeath = false;
- void Reset() override
- {
- if (Creature* pThaddius = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_THADDIUS)))
- if (pThaddius->AI())
- pThaddius->AI()->DoAction(ACTION_FEUGEN_RESET);
- Initialize();
- }
+ // force coil state to refresh
+ refreshBeam = true;
- void KilledUnit(Unit* /*victim*/) override
- {
- if (!(rand32() % 5))
- Talk(SAY_FEUG_SLAY);
- }
+ staticFieldTimer = 6 * IN_MILLISECONDS;
+ magneticPullTimer = 20 * IN_MILLISECONDS;
+ }
- void EnterCombat(Unit* /*who*/) override
- {
- Talk(SAY_FEUG_AGGRO);
- DoCast(SPELL_FEUGEN_TESLA);
- }
+ void Reset() override
+ {
+ if (isFeignDeath || !me->IsAlive())
+ return;
+ if (Creature* thaddius = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_THADDIUS)))
+ thaddius->AI()->DoAction(ACTION_FEUGEN_RESET);
+ }
- void JustDied(Unit* /*killer*/) override
- {
- Talk(SAY_FEUG_DEATH);
- if (Creature* pThaddius = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_THADDIUS)))
- if (pThaddius->AI())
- pThaddius->AI()->DoAction(ACTION_FEUGEN_DIED);
- }
+ void BeginResetEncounter()
+ {
+ if (GameObject* coil = myCoilGO())
+ coil->SetGoState(GO_STATE_READY);
+ me->DespawnOrUnsummon();
+ me->setActive(false);
+ }
- void UpdateAI(uint32 uiDiff) override
- {
- if (!UpdateVictim())
- return;
+ void ResetEncounter()
+ {
+ me->Respawn(true);
+ Initialize();
+ }
- if (staticFieldTimer <= uiDiff)
+ void DoAction(int32 action) override
{
- DoCast(me, SPELL_STATICFIELD);
- staticFieldTimer = 5000;
- } else staticFieldTimer -= uiDiff;
+ switch (action)
+ {
+ case ACTION_BEGIN_RESET_ENCOUNTER:
+ BeginResetEncounter();
+ break;
+ case ACTION_RESET_ENCOUNTER:
+ ResetEncounter();
+ break;
+ case ACTION_FEUGEN_REVIVING_FX:
+ break;
+ case ACTION_FEUGEN_REVIVED:
+ if (!isFeignDeath)
+ break;
+
+ me->SetFullHealth();
+ me->SetStandState(UNIT_STAND_STATE_STAND);
+ me->SetReactState(REACT_AGGRESSIVE);
+ me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
+ Talk(EMOTE_FEIGN_REVIVE);
+ isFeignDeath = false;
+
+ refreshBeam = true; // force beam refresh
+
+ if (Creature* stalagg = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_STALAGG)))
+ if (stalagg->GetVictim())
+ {
+ me->AddThreat(stalagg->EnsureVictim(), 0.0f);
+ me->SetInCombatWith(stalagg->EnsureVictim());
+ }
+ staticFieldTimer = 6 * IN_MILLISECONDS;
+ magneticPullTimer = 30 * IN_MILLISECONDS;
+ break;
+ case ACTION_TRANSITION:
+ me->KillSelf(); // true death this time around
+ me->DespawnOrUnsummon();
+
+ if (Creature* coil = myCoil())
+ {
+ coil->CastStop();
+ coil->AI()->Talk(EMOTE_TESLA_OVERLOAD);
+ }
+ break;
+ case ACTION_TRANSITION_2:
+ if (Creature* coil = myCoil())
+ if (Creature* thaddius = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_THADDIUS)))
+ coil->CastSpell(thaddius, SPELL_SHOCK_VISUAL);
+ break;
+ case ACTION_TRANSITION_3:
+ if (GameObject* coil = myCoilGO())
+ coil->SetGoState(GO_STATE_READY);
+ default:
+ break;
+ }
+ }
- DoMeleeAttackIfReady();
- }
- };
+ void KilledUnit(Unit* victim) override
+ {
+ if (victim->GetTypeId() == TYPEID_PLAYER)
+ Talk(SAY_FEUGEN_SLAY);
+ }
-};
+ void EnterCombat(Unit* who) override
+ {
+ Talk(SAY_FEUGEN_AGGRO);
-class spell_thaddius_pos_neg_charge : public SpellScriptLoader
-{
- public:
- spell_thaddius_pos_neg_charge() : SpellScriptLoader("spell_thaddius_pos_neg_charge") { }
+ if (Creature* thaddius = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_THADDIUS)))
+ thaddius->AI()->DoAction(ACTION_STALAGG_AGGRO);
- class spell_thaddius_pos_neg_charge_SpellScript : public SpellScript
- {
- PrepareSpellScript(spell_thaddius_pos_neg_charge_SpellScript);
+ if (Creature* stalagg = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_STALAGG)))
+ if (!stalagg->IsInCombat())
+ {
+ stalagg->AddThreat(who, 0.0f);
+ stalagg->SetInCombatWith(who);
+ }
+ }
- bool Validate(SpellInfo const* /*spell*/) override
+ void DamageTaken(Unit* /*who*/, uint32& damage) override
{
- if (!sSpellMgr->GetSpellInfo(SPELL_POSITIVE_CHARGE))
- return false;
- if (!sSpellMgr->GetSpellInfo(SPELL_POSITIVE_CHARGE_STACK))
- return false;
- if (!sSpellMgr->GetSpellInfo(SPELL_NEGATIVE_CHARGE))
- return false;
- if (!sSpellMgr->GetSpellInfo(SPELL_NEGATIVE_CHARGE_STACK))
- return false;
- return true;
+ if (damage < me->GetHealth())
+ return;
+
+ if (isFeignDeath) // don't take damage while feigning death
+ {
+ damage = 0;
+ return;
+ }
+
+ isFeignDeath = true;
+ isOverloading = false;
+
+ Talk(EMOTE_FEIGN_DEATH);
+ if (Creature* thaddius = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_THADDIUS)))
+ thaddius->AI()->DoAction(ACTION_FEUGEN_DIED);
+
+ me->RemoveAllAuras();
+ me->SetReactState(REACT_PASSIVE);
+ me->AttackStop();
+ me->StopMoving();
+ me->SetStandState(UNIT_STAND_STATE_DEAD);
+ me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
+
+ damage = 0;
+
+ // force beam refresh as we just removed auras
+ refreshBeam = true;
}
- bool Load() override
+ void SpellHit(Unit* caster, SpellInfo const* spell) override
{
- return GetCaster()->GetTypeId() == TYPEID_UNIT;
+ if (!caster)
+ return;
+ if (spell->Id != SPELL_FEUGEN_TESLA_PERIODIC)
+ return;
+ if (!isFeignDeath && me->IsInCombat() && !me->GetHomePosition().IsInDist(me, OVERLOAD_DISTANCE))
+ {
+ if (!isOverloading)
+ {
+ isOverloading = true;
+ caster->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC);
+ if (Creature* creatureCaster = caster->ToCreature())
+ creatureCaster->AI()->Talk(EMOTE_TESLA_LINK_BREAKS);
+ me->RemoveAura(SPELL_STALAGG_CHAIN_VISUAL);
+ }
+ if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0))
+ {
+ caster->CastStop(SPELL_TESLA_SHOCK);
+ caster->CastSpell(target, SPELL_TESLA_SHOCK,true);
+ }
+ }
+ else if (isOverloading || refreshBeam)
+ {
+ isOverloading = false;
+ refreshBeam = false;
+ caster->CastStop();
+ caster->CastSpell(me, SPELL_FEUGEN_CHAIN_VISUAL, true);
+ caster->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC);
+ }
}
- void HandleTargets(std::list<WorldObject*>& targets)
+ void UpdateAI(uint32 uiDiff) override
{
- uint8 count = 0;
- for (std::list<WorldObject*>::iterator ihit = targets.begin(); ihit != targets.end(); ++ihit)
- if ((*ihit)->GetGUID() != GetCaster()->GetGUID())
- if (Player* target = (*ihit)->ToPlayer())
- if (target->HasAura(GetTriggeringSpell()->Id))
- ++count;
+ if (isFeignDeath)
+ return;
+ if (!UpdateVictim())
+ return;
- if (count)
+ if (magneticPullTimer <= uiDiff)
+ {
+ DoCast(me, SPELL_MAGNETIC_PULL);
+ magneticPullTimer = 20 * IN_MILLISECONDS;
+ }
+ else magneticPullTimer -= uiDiff;
+
+ if (staticFieldTimer <= uiDiff)
{
- uint32 spellId = 0;
+ DoCast(me, SPELL_FEUGEN_STATICFIELD);
+ staticFieldTimer = 6 * IN_MILLISECONDS;
+ }
+ else staticFieldTimer -= uiDiff;
- if (GetSpellInfo()->Id == SPELL_POSITIVE_CHARGE)
- spellId = SPELL_POSITIVE_CHARGE_STACK;
- else // if (GetSpellInfo()->Id == SPELL_NEGATIVE_CHARGE)
- spellId = SPELL_NEGATIVE_CHARGE_STACK;
+ DoMeleeAttackIfReady();
+ }
- GetCaster()->SetAuraStack(spellId, GetCaster(), count);
+ private:
+ Creature* myCoil()
+ {
+ Creature* coil = nullptr;
+ if (_myCoil)
+ coil = ObjectAccessor::GetCreature(*me, _myCoil);
+ if (!coil)
+ {
+ coil = me->FindNearestCreature(NPC_TESLA, 1000.0f, true);
+ if (coil)
+ {
+ _myCoil = coil->GetGUID();
+ coil->SetReactState(REACT_PASSIVE);
+ }
}
+ return coil;
+ }
+
+ GameObject* myCoilGO()
+ {
+ GameObject* coil = nullptr;
+ if (_myCoilGO)
+ coil = ObjectAccessor::GetGameObject(*me, _myCoilGO);
+ if (!coil)
+ {
+ coil = me->FindNearestGameObject(GO_CONS_NOX_TESLA_FEUGEN, 1000.0f);
+ if (coil)
+ _myCoilGO = coil->GetGUID();
+ }
+ return coil;
+ }
+ InstanceScript* instance;
+
+ uint32 magneticPullTimer;
+ uint32 staticFieldTimer;
+
+ ObjectGuid _myCoil;
+ ObjectGuid _myCoilGO;
+
+ bool isOverloading;
+ bool refreshBeam;
+ bool isFeignDeath;
+ };
+};
+
+class npc_tesla : public CreatureScript
+{
+public:
+ npc_tesla() : CreatureScript("npc_tesla") { }
+
+ CreatureAI* GetAI(Creature* creature) const override
+ {
+ return GetInstanceAI<npc_teslaAI>(creature);
+ }
+
+ struct npc_teslaAI : public ScriptedAI
+ {
+ npc_teslaAI(Creature* creature) : ScriptedAI(creature) { }
+
+ void EnterEvadeMode() override { } // never stop casting due to evade
+ void UpdateAI(uint32 /*diff*/) override { } // never do anything unless told
+ void EnterCombat(Unit* /*who*/) override { }
+ void DamageTaken(Unit* /*who*/, uint32& damage) override { damage = 0; } // no, you can't kill it
+ };
+};
+
+class spell_thaddius_polarity_charge : public SpellScriptLoader
+{
+ public:
+ spell_thaddius_polarity_charge() : SpellScriptLoader("spell_thaddius_polarity_charge") { }
+
+ class spell_thaddius_polarity_charge_SpellScript : public SpellScript
+ {
+ PrepareSpellScript(spell_thaddius_polarity_charge_SpellScript);
+
+ bool Validate(SpellInfo const* /*spell*/) override
+ {
+ return (
+ sSpellMgr->GetSpellInfo(SPELL_POLARITY_SHIFT) &&
+ sSpellMgr->GetSpellInfo(SPELL_POSITIVE_CHARGE_APPLY) &&
+ sSpellMgr->GetSpellInfo(SPELL_POSITIVE_CHARGE_TICK) &&
+ sSpellMgr->GetSpellInfo(SPELL_POSITIVE_CHARGE_AMP) &&
+ sSpellMgr->GetSpellInfo(SPELL_NEGATIVE_CHARGE_APPLY) &&
+ sSpellMgr->GetSpellInfo(SPELL_NEGATIVE_CHARGE_TICK) &&
+ sSpellMgr->GetSpellInfo(SPELL_NEGATIVE_CHARGE_AMP)
+ );
}
- void HandleDamage(SpellEffIndex /*effIndex*/)
+ void HandleTargets(std::list<WorldObject*>& targetList)
{
if (!GetTriggeringSpell())
return;
- Unit* target = GetHitUnit();
- Unit* caster = GetCaster();
+ uint32 triggeringId = GetTriggeringSpell()->Id;
+ uint32 ampId;
+ switch (triggeringId)
+ {
+ case SPELL_POSITIVE_CHARGE_APPLY:
+ ampId = SPELL_POSITIVE_CHARGE_AMP;
+ break;
+ case SPELL_NEGATIVE_CHARGE_APPLY:
+ ampId = SPELL_NEGATIVE_CHARGE_AMP;
+ break;
+ default:
+ return;
+ }
- if (target->HasAura(GetTriggeringSpell()->Id))
- SetHitDamage(0);
- else
+ uint8 maxStacks = 0;
+ if (GetCaster())
+ switch (GetCaster()->GetMap()->GetDifficulty())
+ {
+ case RAID_DIFFICULTY_10MAN_NORMAL:
+ maxStacks = MAX_POLARITY_10M;
+ break;
+ case RAID_DIFFICULTY_25MAN_NORMAL:
+ maxStacks = MAX_POLARITY_25M;
+ break;
+ default:
+ break;
+ }
+
+ uint8 stacksCount = 1; // do we get a stack for our own debuff?
+ std::list<WorldObject*>::iterator it = targetList.begin();
+ while(it != targetList.end())
+ {
+ if ((*it)->GetTypeId() != TYPEID_PLAYER)
+ {
+ it = targetList.erase(it);
+ continue;
+ }
+ if ((*it)->ToPlayer()->HasAura(triggeringId))
+ {
+ it = targetList.erase(it);
+ if (stacksCount < maxStacks)
+ stacksCount++;
+ continue;
+ }
+
+ // this guy will get hit - achievement failure trigger
+ if (Creature* thaddius = (*it)->FindNearestCreature(NPC_THADDIUS,200.0f))
+ thaddius->AI()->DoAction(ACTION_POLARITY_CROSSED);
+
+ ++it;
+ }
+
+ if (GetCaster() && GetCaster()->ToPlayer())
{
- if (target->GetTypeId() == TYPEID_PLAYER && caster->IsAIEnabled)
- caster->ToCreature()->AI()->SetData(DATA_POLARITY_SWITCH, 1);
+ if (!GetCaster()->ToPlayer()->HasAura(ampId))
+ GetCaster()->ToPlayer()->AddAura(ampId, GetCaster());
+ GetCaster()->ToPlayer()->SetAuraStack(ampId, GetCaster(), stacksCount);
}
}
void Register() override
{
- OnEffectHitTarget += SpellEffectFn(spell_thaddius_pos_neg_charge_SpellScript::HandleDamage, EFFECT_0, SPELL_EFFECT_SCHOOL_DAMAGE);
- OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_thaddius_pos_neg_charge_SpellScript::HandleTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ALLY);
+ OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_thaddius_polarity_charge_SpellScript::HandleTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ALLY);
}
};
SpellScript* GetSpellScript() const override
{
- return new spell_thaddius_pos_neg_charge_SpellScript();
+ return new spell_thaddius_polarity_charge_SpellScript;
}
};
@@ -536,16 +1107,33 @@ class spell_thaddius_polarity_shift : public SpellScriptLoader
bool Validate(SpellInfo const* /*spell*/) override
{
- if (!sSpellMgr->GetSpellInfo(SPELL_POSITIVE_POLARITY) || !sSpellMgr->GetSpellInfo(SPELL_NEGATIVE_POLARITY))
- return false;
- return true;
+ return (
+ sSpellMgr->GetSpellInfo(SPELL_POLARITY_SHIFT) &&
+ sSpellMgr->GetSpellInfo(SPELL_POSITIVE_CHARGE_APPLY) &&
+ sSpellMgr->GetSpellInfo(SPELL_POSITIVE_CHARGE_TICK) &&
+ sSpellMgr->GetSpellInfo(SPELL_POSITIVE_CHARGE_AMP) &&
+ sSpellMgr->GetSpellInfo(SPELL_NEGATIVE_CHARGE_APPLY) &&
+ sSpellMgr->GetSpellInfo(SPELL_NEGATIVE_CHARGE_TICK) &&
+ sSpellMgr->GetSpellInfo(SPELL_NEGATIVE_CHARGE_AMP)
+ );
}
- void HandleDummy(SpellEffIndex /* effIndex */)
+ void HandleDummy(SpellEffIndex /*effIndex*/)
{
- Unit* caster = GetCaster();
if (Unit* target = GetHitUnit())
- target->CastSpell(target, roll_chance_i(50) ? SPELL_POSITIVE_POLARITY : SPELL_NEGATIVE_POLARITY, true, NULL, NULL, caster->GetGUID());
+ if (target->GetTypeId() == TYPEID_PLAYER)
+ {
+ if (roll_chance_i(50))
+ { // positive
+ target->CastSpell(target, SPELL_POSITIVE_CHARGE_APPLY, true);
+ target->RemoveAura(SPELL_POSITIVE_CHARGE_AMP);
+ }
+ else
+ { // negative
+ target->CastSpell(target, SPELL_NEGATIVE_CHARGE_APPLY, true);
+ target->RemoveAura(SPELL_NEGATIVE_CHARGE_AMP);
+ }
+ }
}
void Register() override
@@ -560,23 +1148,131 @@ class spell_thaddius_polarity_shift : public SpellScriptLoader
}
};
-class achievement_polarity_switch : public AchievementCriteriaScript
+class spell_thaddius_magnetic_pull : public SpellScriptLoader
{
public:
- achievement_polarity_switch() : AchievementCriteriaScript("achievement_polarity_switch") { }
+ spell_thaddius_magnetic_pull() : SpellScriptLoader("spell_thaddius_magnetic_pull") { };
+
+ class spell_thaddius_magnetic_pull_SpellScript : public SpellScript
+ {
+ PrepareSpellScript(spell_thaddius_magnetic_pull_SpellScript);
+
+ bool Validate(SpellInfo const* /*spell*/) override
+ {
+ return sSpellMgr->GetSpellInfo(SPELL_MAGNETIC_PULL) ? true : false;
+ }
+
+ void HandleCast() // only feugen ever casts this according to wowhead data
+ {
+ Unit* feugen = GetCaster();
+ if (!feugen || feugen->GetEntry() != NPC_FEUGEN)
+ return;
+
+ Unit* stalagg = ObjectAccessor::GetCreature(*feugen, feugen->GetInstanceScript()->GetGuidData(DATA_STALAGG));
+ if (!stalagg)
+ return;
+
+ Unit* feugenTank = feugen->GetVictim();
+ Unit* stalaggTank = stalagg->GetVictim();
+
+ if (!feugenTank || !stalaggTank)
+ return;
+
+ ThreatManager& feugenThreat = feugen->getThreatManager();
+ ThreatManager& stalaggThreat = stalagg->getThreatManager();
+
+ if (feugenTank == stalaggTank) // special behavior if the tanks are the same (taken from retail)
+ {
+ float feugenTankThreat = feugenThreat.getThreat(feugenTank);
+ float stalaggTankThreat = stalaggThreat.getThreat(stalaggTank);
+
+ feugenThreat.addThreat(feugenTank, stalaggTankThreat - feugenTankThreat);
+ stalaggThreat.addThreat(stalaggTank, feugenTankThreat - stalaggTankThreat);
+
+ feugen->CastSpell(stalaggTank, SPELL_MAGNETIC_PULL_EFFECT, true);
+ }
+ else // normal case, two tanks
+ {
+ float feugenTankThreat = feugenThreat.getThreat(feugenTank);
+ float feugenOtherThreat = feugenThreat.getThreat(stalaggTank);
+ float stalaggTankThreat = stalaggThreat.getThreat(stalaggTank);
+ float stalaggOtherThreat = stalaggThreat.getThreat(feugenTank);
+
+ // set the two entries in feugen's threat table to be equal to the ones in stalagg's
+ feugenThreat.addThreat(stalaggTank, stalaggTankThreat - feugenOtherThreat);
+ feugenThreat.addThreat(feugenTank, stalaggOtherThreat - feugenTankThreat);
+
+ // set the two entries in stalagg's threat table to be equal to the ones in feugen's
+ stalaggThreat.addThreat(feugenTank, feugenTankThreat - stalaggOtherThreat);
+ stalaggThreat.addThreat(stalaggTank, feugenOtherThreat - stalaggTankThreat);
+
+ // pull the two tanks across
+ feugenTank->CastSpell(stalaggTank, SPELL_MAGNETIC_PULL_EFFECT, true);
+ stalaggTank->CastSpell(feugenTank, SPELL_MAGNETIC_PULL_EFFECT, true);
+
+ // and make both attack their respective new tanks
+ if (feugen->GetAI())
+ feugen->GetAI()->AttackStart(stalaggTank);
+ if (stalagg->GetAI())
+ stalagg->GetAI()->AttackStart(feugenTank);
+ }
+ }
+
+ void Register() override
+ {
+ OnCast += SpellCastFn(spell_thaddius_magnetic_pull_SpellScript::HandleCast);
+ }
+ };
+
+ SpellScript* GetSpellScript() const override
+ {
+ return new spell_thaddius_magnetic_pull_SpellScript();
+ }
+};
+
+class at_thaddius_entrance : public AreaTriggerScript
+{
+ public:
+ at_thaddius_entrance() : AreaTriggerScript("at_thaddius_entrance") { }
+
+ bool OnTrigger(Player* player, AreaTriggerEntry const* /*areaTrigger*/) override
+ {
+ InstanceScript* instance = player->GetInstanceScript();
+ if (!instance || instance->GetData(DATA_HAD_THADDIUS_GREET) || instance->GetBossState(BOSS_THADDIUS) == DONE)
+ return true;
+
+ if (Creature* thaddius = ObjectAccessor::GetCreature(*player, instance->GetGuidData(DATA_THADDIUS)))
+ thaddius->AI()->Talk(SAY_GREET);
+ instance->SetData(DATA_HAD_THADDIUS_GREET, 1u);
+
+ return true;
+ }
+};
+
+class achievement_thaddius_shocking : public AchievementCriteriaScript
+{
+ public:
+ achievement_thaddius_shocking() : AchievementCriteriaScript("achievement_thaddius_shocking") { }
bool OnCheck(Player* /*source*/, Unit* target) override
{
- return target && target->GetAI()->GetData(DATA_POLARITY_SWITCH);
+ return target && target->GetAI() && target->GetAI()->GetData(DATA_POLARITY_CROSSED);
}
};
+
void AddSC_boss_thaddius()
{
new boss_thaddius();
new npc_stalagg();
new npc_feugen();
- new spell_thaddius_pos_neg_charge();
+ new npc_tesla();
+
+ new spell_thaddius_polarity_charge();
new spell_thaddius_polarity_shift();
- new achievement_polarity_switch();
+ new spell_thaddius_magnetic_pull();
+
+ new at_thaddius_entrance();
+
+ new achievement_thaddius_shocking();
}
diff --git a/src/server/scripts/Northrend/Naxxramas/instance_naxxramas.cpp b/src/server/scripts/Northrend/Naxxramas/instance_naxxramas.cpp
index 9b10fab2d62..0e572835a51 100644
--- a/src/server/scripts/Northrend/Naxxramas/instance_naxxramas.cpp
+++ b/src/server/scripts/Northrend/Naxxramas/instance_naxxramas.cpp
@@ -60,7 +60,6 @@ DoorData const doorData[] =
MinionData const minionData[] =
{
- { NPC_DK_UNDERSTUDY, BOSS_RAZUVIOUS },
{ NPC_SIR, BOSS_HORSEMEN },
{ NPC_THANE, BOSS_HORSEMEN },
{ NPC_LADY, BOSS_HORSEMEN },
@@ -127,6 +126,7 @@ class instance_naxxramas : public InstanceMapScript
AbominationCount = 0;
hadAnubRekhanGreet = false;
hadFaerlinaGreet = false;
+ hadThaddiusGreet = false;
CurrentWingTaunt = SAY_KELTHUZAD_FIRST_WING_TAUNT;
playerDied = 0;
@@ -142,6 +142,9 @@ class instance_naxxramas : public InstanceMapScript
case NPC_FAERLINA:
FaerlinaGUID = creature->GetGUID();
break;
+ case NPC_RAZUVIOUS:
+ RazuviousGUID = creature->GetGUID();
+ break;
case NPC_THANE:
ThaneGUID = creature->GetGUID();
break;
@@ -154,12 +157,12 @@ class instance_naxxramas : public InstanceMapScript
case NPC_SIR:
SirGUID = creature->GetGUID();
break;
- case NPC_THADDIUS:
- ThaddiusGUID = creature->GetGUID();
- break;
case NPC_HEIGAN:
HeiganGUID = creature->GetGUID();
break;
+ case NPC_THADDIUS:
+ ThaddiusGUID = creature->GetGUID();
+ break;
case NPC_FEUGEN:
FeugenGUID = creature->GetGUID();
break;
@@ -187,6 +190,19 @@ class instance_naxxramas : public InstanceMapScript
AddMinion(creature, false);
}
+ void ProcessEvent(WorldObject* /*source*/, uint32 eventId) override
+ {
+ switch (eventId)
+ {
+ case EVENT_THADDIUS_BEGIN_RESET:
+ if (GetBossState(BOSS_THADDIUS) == SPECIAL) // this is the initial spawn, we want a shorter spawn time
+ events.ScheduleEvent(EVENT_THADDIUS_RESET, 5 * IN_MILLISECONDS);
+ else
+ events.ScheduleEvent(EVENT_THADDIUS_RESET, 30 * IN_MILLISECONDS);
+ break;
+ }
+ }
+
void OnGameObjectCreate(GameObject* go) override
{
if (go->GetGOInfo()->displayId == 6785 || go->GetGOInfo()->displayId == 1287)
@@ -329,6 +345,9 @@ class instance_naxxramas : public InstanceMapScript
case DATA_HAD_FAERLINA_GREET:
hadFaerlinaGreet = (value == 1u);
break;
+ case DATA_HAD_THADDIUS_GREET:
+ hadThaddiusGreet = (value == 1u);
+ break;
default:
break;
}
@@ -341,9 +360,11 @@ class instance_naxxramas : public InstanceMapScript
case DATA_ABOMINATION_KILLED:
return AbominationCount;
case DATA_HAD_ANUBREKHAN_GREET:
- return (uint32)hadAnubRekhanGreet;
+ return hadAnubRekhanGreet ? 1u : 0u;
case DATA_HAD_FAERLINA_GREET:
- return (uint32)hadFaerlinaGreet;
+ return hadFaerlinaGreet ? 1u : 0u;
+ case DATA_HAD_THADDIUS_GREET:
+ return hadThaddiusGreet ? 1u : 0u;
default:
break;
}
@@ -359,6 +380,8 @@ class instance_naxxramas : public InstanceMapScript
return AnubRekhanGUID;
case DATA_FAERLINA:
return FaerlinaGUID;
+ case DATA_RAZUVIOUS:
+ return RazuviousGUID;
case DATA_THANE:
return ThaneGUID;
case DATA_LADY:
@@ -367,14 +390,14 @@ class instance_naxxramas : public InstanceMapScript
return BaronGUID;
case DATA_SIR:
return SirGUID;
- case DATA_THADDIUS:
- return ThaddiusGUID;
case DATA_HEIGAN:
return HeiganGUID;
case DATA_FEUGEN:
return FeugenGUID;
case DATA_STALAGG:
return StalaggGUID;
+ case DATA_THADDIUS:
+ return ThaddiusGUID;
case DATA_KELTHUZAD:
return KelthuzadGUID;
case DATA_KELTHUZAD_PORTAL01:
@@ -543,6 +566,11 @@ class instance_naxxramas : public InstanceMapScript
kelthuzad->AI()->Talk(SAY_DIALOGUE_SAPPHIRON_KELTHUZAD4);
HandleGameObject(KelthuzadDoorGUID, true);
break;
+ case EVENT_THADDIUS_RESET:
+ if (GetBossState(BOSS_THADDIUS) != DONE)
+ if (Creature* thaddius = instance->GetCreature(ThaddiusGUID))
+ thaddius->AI()->DoAction(-1);
+ break;
default:
break;
}
@@ -628,6 +656,8 @@ class instance_naxxramas : public InstanceMapScript
ObjectGuid HeiganGUID;
/* The Military Quarter */
+ // Instructor Razuvious
+ ObjectGuid RazuviousGUID;
// Gothik the Harvester
ObjectGuid GothikGateGUID;
// The Four Horsemen
@@ -657,6 +687,7 @@ class instance_naxxramas : public InstanceMapScript
uint8 AbominationCount;
bool hadAnubRekhanGreet;
bool hadFaerlinaGreet;
+ bool hadThaddiusGreet;
uint8 CurrentWingTaunt;
/* The Immortal / The Undying */
diff --git a/src/server/scripts/Northrend/Naxxramas/naxxramas.h b/src/server/scripts/Northrend/Naxxramas/naxxramas.h
index 6289b707411..e4d15cf84ba 100644
--- a/src/server/scripts/Northrend/Naxxramas/naxxramas.h
+++ b/src/server/scripts/Northrend/Naxxramas/naxxramas.h
@@ -47,8 +47,8 @@ enum Data
DATA_GOTHIK_GATE,
DATA_SAPPHIRON_BIRTH,
DATA_HAD_ANUBREKHAN_GREET,
-
DATA_HAD_FAERLINA_GREET,
+ DATA_HAD_THADDIUS_GREET,
DATA_HORSEMEN0,
DATA_HORSEMEN1,
@@ -66,6 +66,7 @@ enum Data64
{
DATA_ANUBREKHAN,
DATA_FAERLINA,
+ DATA_RAZUVIOUS,
DATA_THANE,
DATA_LADY,
DATA_BARON,
@@ -87,14 +88,16 @@ enum CreaturesIds
{
NPC_ANUBREKHAN = 15956,
NPC_FAERLINA = 15953,
+ NPC_RAZUVIOUS = 16061,
NPC_THANE = 16064,
NPC_LADY = 16065,
NPC_BARON = 30549,
NPC_SIR = 16063,
- NPC_THADDIUS = 15928,
NPC_HEIGAN = 15936,
+ NPC_THADDIUS = 15928,
NPC_FEUGEN = 15930,
NPC_STALAGG = 15929,
+ NPC_TESLA = 16218,
NPC_SAPPHIRON = 15989,
NPC_KEL_THUZAD = 15990,
NPC_CRYPT_GUARD = 16573,
@@ -174,6 +177,10 @@ enum InstanceEvents
EVENT_DIALOGUE_GOTHIK_KORTHAZZ2,
EVENT_DIALOGUE_GOTHIK_RIVENDARE2,
+ // Thaddius AI requesting timed encounter (re-)spawn
+ EVENT_THADDIUS_BEGIN_RESET,
+ EVENT_THADDIUS_RESET,
+
// Dialogue that happens after each wing.
EVENT_KELTHUZAD_WING_TAUNT,
diff --git a/src/server/scripts/Northrend/Nexus/EyeOfEternity/boss_malygos.cpp b/src/server/scripts/Northrend/Nexus/EyeOfEternity/boss_malygos.cpp
index cc9af9413e5..33ffea4993b 100644
--- a/src/server/scripts/Northrend/Nexus/EyeOfEternity/boss_malygos.cpp
+++ b/src/server/scripts/Northrend/Nexus/EyeOfEternity/boss_malygos.cpp
@@ -1244,8 +1244,9 @@ public:
++_wpCount;
}
else if (Vehicle* hoverDisk = me->GetVehicleKit())
- if (Unit* lordPassenger = hoverDisk->GetPassenger(0))
- lordPassenger->ToCreature()->AI()->DoAction(ACTION_SET_DISK_VICTIM_CHASE);
+ if (Unit* passenger = hoverDisk->GetPassenger(0))
+ if (Creature* lordPassenger = passenger->ToCreature())
+ lordPassenger->AI()->DoAction(ACTION_SET_DISK_VICTIM_CHASE);
}
private:
diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_mimiron.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_mimiron.cpp
index bd4fee60c42..5c852cd7f26 100644
--- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_mimiron.cpp
+++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_mimiron.cpp
@@ -701,7 +701,7 @@ class boss_leviathan_mk_ii : public CreatureScript
{
me->CastStop();
if (Unit* turret = me->GetVehicleKit()->GetPassenger(3))
- turret->Kill(turret);
+ turret->KillSelf();
me->SetSpeed(MOVE_RUN, 1.5f, true);
me->GetMotionMaster()->MovePoint(WP_MKII_P1_IDLE, VehicleRelocation[WP_MKII_P1_IDLE]);
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 6f07a88536d..8545d5b21eb 100644
--- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_yogg_saron.cpp
+++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_yogg_saron.cpp
@@ -2423,7 +2423,7 @@ class spell_yogg_saron_squeeze : public SpellScriptLoader // 64125
{
if (Unit* vehicle = GetTarget()->GetVehicleBase())
if (vehicle->IsAlive())
- vehicle->Kill(vehicle); // should tentacle die or just release its target?
+ vehicle->KillSelf(); // should tentacle die or just release its target?
}
void Register() override
@@ -2905,7 +2905,7 @@ class spell_yogg_saron_insane : public SpellScriptLoader // 63120
void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
{
if (GetTarget()->IsAlive())
- GetTarget()->Kill(GetTarget());
+ GetTarget()->KillSelf();
}
void Register() override
diff --git a/src/server/scripts/Northrend/zone_borean_tundra.cpp b/src/server/scripts/Northrend/zone_borean_tundra.cpp
index 4cdfa653224..6ef9abe2267 100644
--- a/src/server/scripts/Northrend/zone_borean_tundra.cpp
+++ b/src/server/scripts/Northrend/zone_borean_tundra.cpp
@@ -1326,7 +1326,7 @@ public:
arlos->AI()->Talk(SAY_ARLOS_1);
arlos->AI()->Talk(SAY_ARLOS_2);
leryssa->AI()->Talk(SAY_LERYSSA_1);
- arlos->Kill(arlos, false);
+ arlos->KillSelf(false);
leryssa->RemoveAura(SPELL_STUN);
leryssa->ClearUnitState(UNIT_STATE_STUNNED);
leryssa->SetWalk(false);
diff --git a/src/server/scripts/Northrend/zone_sholazar_basin.cpp b/src/server/scripts/Northrend/zone_sholazar_basin.cpp
index 6e4a8df6f25..5d47e7fa4ec 100644
--- a/src/server/scripts/Northrend/zone_sholazar_basin.cpp
+++ b/src/server/scripts/Northrend/zone_sholazar_basin.cpp
@@ -778,7 +778,7 @@ public:
wilhelm->AI()->Talk(SAY_WILHELM_MISS);
drostan->AI()->Talk(SAY_DROSTAN_REPLY_MISS);
- bird->Kill(bird);
+ bird->KillSelf();
crunchy->GetMotionMaster()->MovePoint(0, bird->GetPositionX(), bird->GetPositionY(),
bird->GetMap()->GetWaterOrGroundLevel(bird->GetPositionX(), bird->GetPositionY(), bird->GetPositionZ()));
/// @todo Make crunchy perform emote eat when he reaches the bird
diff --git a/src/server/scripts/Outland/Auchindoun/ShadowLabyrinth/boss_grandmaster_vorpil.cpp b/src/server/scripts/Outland/Auchindoun/ShadowLabyrinth/boss_grandmaster_vorpil.cpp
index b16a9630335..04d3a20d945 100644
--- a/src/server/scripts/Outland/Auchindoun/ShadowLabyrinth/boss_grandmaster_vorpil.cpp
+++ b/src/server/scripts/Outland/Auchindoun/ShadowLabyrinth/boss_grandmaster_vorpil.cpp
@@ -257,7 +257,7 @@ class npc_voidtraveler : public CreatureScript
{
DoCastAOE(SPELL_EMPOWERING_SHADOWS, true);
DoCast(me, SPELL_SHADOW_NOVA, true);
- me->Kill(me);
+ me->KillSelf();
return;
}
me->GetMotionMaster()->MoveFollow(Vorpil, 0, 0);
diff --git a/src/server/scripts/Outland/CoilfangReservoir/SerpentShrine/boss_lady_vashj.cpp b/src/server/scripts/Outland/CoilfangReservoir/SerpentShrine/boss_lady_vashj.cpp
index 787b191e23d..0292ed65697 100644
--- a/src/server/scripts/Outland/CoilfangReservoir/SerpentShrine/boss_lady_vashj.cpp
+++ b/src/server/scripts/Outland/CoilfangReservoir/SerpentShrine/boss_lady_vashj.cpp
@@ -633,7 +633,7 @@ public:
}
if (Creature* vashj = ObjectAccessor::GetCreature(*me, VashjGUID))
if (!vashj->IsInCombat() || ENSURE_AI(boss_lady_vashj::boss_lady_vashjAI, vashj->AI())->Phase != 2 || vashj->isDead())
- me->Kill(me);
+ me->KillSelf();
Move = 1000;
} else Move -= diff;
}
diff --git a/src/server/scripts/Outland/TempestKeep/Eye/boss_kaelthas.cpp b/src/server/scripts/Outland/TempestKeep/Eye/boss_kaelthas.cpp
index 872269fd19f..2d99fd9bacf 100644
--- a/src/server/scripts/Outland/TempestKeep/Eye/boss_kaelthas.cpp
+++ b/src/server/scripts/Outland/TempestKeep/Eye/boss_kaelthas.cpp
@@ -1286,7 +1286,7 @@ class npc_kael_flamestrike : public CreatureScript
DoCast(me, SPELL_FLAME_STRIKE_DMG);
}
else
- me->Kill(me);
+ me->KillSelf();
KillSelf = true;
Timer = 1000;
diff --git a/src/server/scripts/Pet/pet_mage.cpp b/src/server/scripts/Pet/pet_mage.cpp
index 0d6353cfb86..14d2687c298 100644
--- a/src/server/scripts/Pet/pet_mage.cpp
+++ b/src/server/scripts/Pet/pet_mage.cpp
@@ -24,11 +24,25 @@
#include "ScriptedCreature.h"
#include "CombatAI.h"
#include "Pet.h"
+#include "PetAI.h"
+#include "Cell.h"
+#include "CellImpl.h"
+#include "GridNotifiers.h"
+#include "GridNotifiersImpl.h"
enum MageSpells
{
SPELL_MAGE_CLONE_ME = 45204,
- SPELL_MAGE_MASTERS_THREAT_LIST = 58838
+ SPELL_MAGE_MASTERS_THREAT_LIST = 58838,
+ SPELL_MAGE_FROST_BOLT = 59638,
+ SPELL_MAGE_FIRE_BLAST = 59637
+};
+
+enum MirrorImageTimers
+{
+ TIMER_MIRROR_IMAGE_INIT = 0,
+ TIMER_MIRROR_IMAGE_FROST_BOLT = 4000,
+ TIMER_MIRROR_IMAGE_FIRE_BLAST = 6000
};
class npc_pet_mage_mirror_image : public CreatureScript
@@ -40,20 +54,184 @@ class npc_pet_mage_mirror_image : public CreatureScript
{
npc_pet_mage_mirror_imageAI(Creature* creature) : CasterAI(creature) { }
+ void Init()
+ {
+ Unit* owner = me->GetCharmerOrOwner();
+
+ std::list<Unit*> targets;
+ Trinity::AnyUnfriendlyUnitInObjectRangeCheck u_check(me, me, 30.0f);
+ Trinity::UnitListSearcher<Trinity::AnyUnfriendlyUnitInObjectRangeCheck> searcher(me, targets, u_check);
+ me->VisitNearbyObject(40.0f, searcher);
+
+ Unit* highestThreatUnit = nullptr;
+ float highestThreat = 0.0f;
+ Unit* nearestPlayer = nullptr;
+ for (std::list<Unit*>::const_iterator iter = targets.begin(); iter != targets.end(); ++iter)
+ {
+ // Consider only units without CC
+ if (!(*iter)->HasBreakableByDamageCrowdControlAura((*iter)))
+ {
+ // Take first found unit
+ if (!highestThreatUnit && (*iter)->GetTypeId() != TYPEID_PLAYER)
+ {
+ highestThreatUnit = (*iter);
+ continue;
+ }
+ if (!nearestPlayer && ((*iter)->GetTypeId() == TYPEID_PLAYER))
+ {
+ nearestPlayer = (*iter);
+ continue;
+ }
+ // else compare best fit unit with current unit
+ ThreatContainer::StorageType triggers = (*iter)->getThreatManager().getThreatList();
+ for (ThreatContainer::StorageType::const_iterator trig_citr = triggers.begin(); trig_citr != triggers.end(); ++trig_citr)
+ {
+ // Try to find threat referenced to owner
+ if ((*trig_citr)->getTarget() == owner)
+ {
+ // Check if best fit hostile unit hs lower threat than this current unit
+ if (highestThreat < (*trig_citr)->getThreat())
+ {
+ // If so, update best fit unit
+ highestThreat = (*trig_citr)->getThreat();
+ highestThreatUnit = (*iter);
+ break;
+ }
+ }
+ }
+ // In case no unit with threat was found so far, always check for nearest unit (only for players)
+ if ((*iter)->GetTypeId() == TYPEID_PLAYER)
+ {
+ // If this player is closer than the previous one, update it
+ if (me->GetDistance((*iter)->GetPosition()) < me->GetDistance(nearestPlayer->GetPosition()))
+ nearestPlayer = (*iter);
+ }
+ }
+ }
+ // Prioritize units with threat referenced to owner
+ if (highestThreat > 0.0f && highestThreatUnit)
+ me->Attack(highestThreatUnit, false);
+ // If there is no such target, try to attack nearest hostile unit if such exists
+ else if (nearestPlayer)
+ me->Attack(nearestPlayer, false);
+ }
+
+ bool IsInThreatList(Unit* target)
+ {
+ Unit* owner = me->GetCharmerOrOwner();
+
+ std::list<Unit*> targets;
+ Trinity::AnyUnfriendlyUnitInObjectRangeCheck u_check(me, me, 30.0f);
+ Trinity::UnitListSearcher<Trinity::AnyUnfriendlyUnitInObjectRangeCheck> searcher(me, targets, u_check);
+ me->VisitNearbyObject(40.0f, searcher);
+
+ for (std::list<Unit*>::const_iterator iter = targets.begin(); iter != targets.end(); ++iter)
+ {
+ if ((*iter) == target)
+ {
+ // Consider only units without CC
+ if (!(*iter)->HasBreakableByDamageCrowdControlAura((*iter)))
+ {
+ ThreatContainer::StorageType triggers = (*iter)->getThreatManager().getThreatList();
+ for (ThreatContainer::StorageType::const_iterator trig_citr = triggers.begin(); trig_citr != triggers.end(); ++trig_citr)
+ {
+ // Try to find threat referenced to owner
+ if ((*trig_citr)->getTarget() == owner)
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+ }
+
void InitializeAI() override
{
CasterAI::InitializeAI();
Unit* owner = me->GetOwner();
if (!owner)
return;
- // Inherit Master's Threat List (not yet implemented)
- owner->CastSpell((Unit*)NULL, SPELL_MAGE_MASTERS_THREAT_LIST, true);
+
// here mirror image casts on summoner spell (not present in client dbc) 49866
// here should be auras (not present in client dbc): 35657, 35658, 35659, 35660 selfcast by mirror images (stats related?)
// Clone Me!
owner->CastSpell(me, SPELL_MAGE_CLONE_ME, false);
}
+ void EnterCombat(Unit* who) override
+ {
+ if (me->GetVictim() && !me->GetVictim()->HasBreakableByDamageCrowdControlAura(me))
+ {
+ me->CastSpell(who, SPELL_MAGE_FIRE_BLAST, false);
+ events.ScheduleEvent(SPELL_MAGE_FROST_BOLT, TIMER_MIRROR_IMAGE_INIT);
+ events.ScheduleEvent(SPELL_MAGE_FIRE_BLAST, TIMER_MIRROR_IMAGE_FIRE_BLAST);
+ }
+ else
+ EnterEvadeMode();
+ }
+
+ void Reset() override
+ {
+ events.Reset();
+ }
+
+ void UpdateAI(uint32 diff) override
+ {
+ Unit* owner = me->GetCharmerOrOwner();
+ Unit* target = owner->getAttackerForHelper();
+
+ events.Update(diff);
+
+ // prevent CC interrupts by images
+ if (me->GetVictim() && me->EnsureVictim()->HasBreakableByDamageCrowdControlAura(me))
+ {
+ me->InterruptNonMeleeSpells(false);
+ return;
+ }
+
+ if (me->HasUnitState(UNIT_STATE_CASTING))
+ return;
+
+ if (!owner)
+ return;
+
+ // assign target if image doesnt have any or the target is not actual
+ if (!target || me->GetVictim() != target)
+ {
+ Unit* ownerTarget = nullptr;
+ if (Player* owner = me->GetCharmerOrOwner()->ToPlayer())
+ ownerTarget = owner->GetSelectedUnit();
+
+ // recognize which victim will be choosen
+ if (ownerTarget && ownerTarget->GetTypeId() == TYPEID_PLAYER)
+ {
+ if (!ownerTarget->HasBreakableByDamageCrowdControlAura(ownerTarget))
+ me->Attack(ownerTarget, false);
+ }
+ else if (ownerTarget && (ownerTarget->GetTypeId() != TYPEID_PLAYER) && IsInThreatList(ownerTarget))
+ {
+ if (!ownerTarget->HasBreakableByDamageCrowdControlAura(ownerTarget))
+ me->Attack(ownerTarget, false);
+ }
+ else
+ Init();
+ }
+
+ if (uint32 spellId = events.ExecuteEvent())
+ {
+ if (spellId == SPELL_MAGE_FROST_BOLT)
+ {
+ events.ScheduleEvent(SPELL_MAGE_FROST_BOLT, TIMER_MIRROR_IMAGE_FROST_BOLT);
+ DoCastVictim(spellId);
+ }
+ else if (spellId == SPELL_MAGE_FIRE_BLAST)
+ {
+ DoCastVictim(spellId);
+ events.ScheduleEvent(SPELL_MAGE_FIRE_BLAST, TIMER_MIRROR_IMAGE_FIRE_BLAST);
+ }
+ }
+ }
+
// Do not reload Creature templates on evade mode enter - prevent visual lost
void EnterEvadeMode() override
{
@@ -68,6 +246,7 @@ class npc_pet_mage_mirror_image : public CreatureScript
me->GetMotionMaster()->Clear(false);
me->GetMotionMaster()->MoveFollow(owner, PET_FOLLOW_DIST, me->GetFollowAngle(), MOTION_SLOT_ACTIVE);
}
+ Init();
}
};
diff --git a/src/server/scripts/Spells/spell_dk.cpp b/src/server/scripts/Spells/spell_dk.cpp
index cd0052c24bc..88271dc7139 100644
--- a/src/server/scripts/Spells/spell_dk.cpp
+++ b/src/server/scripts/Spells/spell_dk.cpp
@@ -1343,6 +1343,15 @@ class spell_dk_raise_dead : public SpellScriptLoader
GetCaster()->CastSpell(targets, spellInfo, NULL, TRIGGERED_FULL_MASK);
}
+ void OverrideCooldown()
+ {
+ // Because the ghoul is summoned by one of triggered spells SendCooldownEvent is not sent for this spell
+ // but the client has locked it by itself so we need some link between this spell and the real spell summoning.
+ // Luckily such link already exists - spell category
+ // This starts infinite category cooldown which can later be used by SendCooldownEvent to send packet for this spell
+ GetCaster()->GetSpellHistory()->StartCooldown(GetSpellInfo(), 0, nullptr, true);
+ }
+
void Register() override
{
OnCheckCast += SpellCheckCastFn(spell_dk_raise_dead_SpellScript::CheckCast);
@@ -1351,6 +1360,7 @@ class spell_dk_raise_dead : public SpellScriptLoader
OnCast += SpellCastFn(spell_dk_raise_dead_SpellScript::ConsumeReagents);
OnEffectHitTarget += SpellEffectFn(spell_dk_raise_dead_SpellScript::HandleRaiseDead, EFFECT_1, SPELL_EFFECT_SCRIPT_EFFECT);
OnEffectHitTarget += SpellEffectFn(spell_dk_raise_dead_SpellScript::HandleRaiseDead, EFFECT_2, SPELL_EFFECT_DUMMY);
+ AfterCast += SpellCastFn(spell_dk_raise_dead_SpellScript::OverrideCooldown);
}
private:
diff --git a/src/server/scripts/Spells/spell_holiday.cpp b/src/server/scripts/Spells/spell_holiday.cpp
index a1b218010aa..e29f87a5ff9 100644
--- a/src/server/scripts/Spells/spell_holiday.cpp
+++ b/src/server/scripts/Spells/spell_holiday.cpp
@@ -277,6 +277,86 @@ class spell_hallow_end_tricky_treat : public SpellScriptLoader
}
};
+// Hallowed wands
+enum HallowendData
+{
+ //wand spells
+ SPELL_HALLOWED_WAND_PIRATE = 24717,
+ SPELL_HALLOWED_WAND_NINJA = 24718,
+ SPELL_HALLOWED_WAND_LEPER_GNOME = 24719,
+ SPELL_HALLOWED_WAND_RANDOM = 24720,
+ SPELL_HALLOWED_WAND_SKELETON = 24724,
+ SPELL_HALLOWED_WAND_WISP = 24733,
+ SPELL_HALLOWED_WAND_GHOST = 24737,
+ SPELL_HALLOWED_WAND_BAT = 24741
+};
+
+class spell_hallow_end_wand : public SpellScriptLoader
+{
+public:
+ spell_hallow_end_wand() : SpellScriptLoader("spell_hallow_end_wand") {}
+
+ class spell_hallow_end_wand_SpellScript : public SpellScript
+ {
+ PrepareSpellScript(spell_hallow_end_wand_SpellScript);
+
+ bool Validate(SpellInfo const* /*spellEntry*/) override
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_PIRATE_COSTUME_MALE) ||
+ !sSpellMgr->GetSpellInfo(SPELL_PIRATE_COSTUME_FEMALE) ||
+ !sSpellMgr->GetSpellInfo(SPELL_NINJA_COSTUME_MALE) ||
+ !sSpellMgr->GetSpellInfo(SPELL_NINJA_COSTUME_FEMALE) ||
+ !sSpellMgr->GetSpellInfo(SPELL_LEPER_GNOME_COSTUME_MALE) ||
+ !sSpellMgr->GetSpellInfo(SPELL_LEPER_GNOME_COSTUME_FEMALE) ||
+ !sSpellMgr->GetSpellInfo(SPELL_GHOST_COSTUME_MALE) ||
+ !sSpellMgr->GetSpellInfo(SPELL_GHOST_COSTUME_FEMALE))
+ return false;
+ return true;
+ }
+
+ void HandleScriptEffect()
+ {
+ Unit* caster = GetCaster();
+ Unit* target = GetHitUnit();
+
+ uint32 spellId = 0;
+ uint8 gender = target->getGender();
+
+ switch (GetSpellInfo()->Id)
+ {
+ case SPELL_HALLOWED_WAND_LEPER_GNOME:
+ spellId = gender ? SPELL_LEPER_GNOME_COSTUME_FEMALE : SPELL_LEPER_GNOME_COSTUME_MALE;
+ break;
+ case SPELL_HALLOWED_WAND_PIRATE:
+ spellId = gender ? SPELL_PIRATE_COSTUME_FEMALE : SPELL_PIRATE_COSTUME_MALE;
+ break;
+ case SPELL_HALLOWED_WAND_GHOST:
+ spellId = gender ? SPELL_GHOST_COSTUME_FEMALE : SPELL_GHOST_COSTUME_MALE;
+ break;
+ case SPELL_HALLOWED_WAND_NINJA:
+ spellId = gender ? SPELL_NINJA_COSTUME_FEMALE : SPELL_NINJA_COSTUME_MALE;
+ break;
+ case SPELL_HALLOWED_WAND_RANDOM:
+ spellId = RAND(SPELL_HALLOWED_WAND_PIRATE, SPELL_HALLOWED_WAND_NINJA, SPELL_HALLOWED_WAND_LEPER_GNOME, SPELL_HALLOWED_WAND_SKELETON, SPELL_HALLOWED_WAND_WISP, SPELL_HALLOWED_WAND_GHOST, SPELL_HALLOWED_WAND_BAT);
+ break;
+ default:
+ return;
+ }
+ caster->CastSpell(target, spellId, true);
+ }
+
+ void Register() override
+ {
+ AfterHit += SpellHitFn(spell_hallow_end_wand_SpellScript::HandleScriptEffect);
+ }
+ };
+
+ SpellScript* GetSpellScript() const override
+ {
+ return new spell_hallow_end_wand_SpellScript();
+ }
+};
+
enum PilgrimsBountyBuffFood
{
// Pilgrims Bounty Buff Food
@@ -886,6 +966,7 @@ void AddSC_holiday_spell_scripts()
new spell_hallow_end_trick();
new spell_hallow_end_trick_or_treat();
new spell_hallow_end_tricky_treat();
+ new spell_hallow_end_wand();
// Pilgrims Bounty
new spell_pilgrims_bounty_buff_food("spell_gen_slow_roasted_turkey", SPELL_WELL_FED_AP_TRIGGER);
new spell_pilgrims_bounty_buff_food("spell_gen_cranberry_chutney", SPELL_WELL_FED_ZM_TRIGGER);
diff --git a/src/server/scripts/Spells/spell_hunter.cpp b/src/server/scripts/Spells/spell_hunter.cpp
index f2871871c30..0ca4112b288 100644
--- a/src/server/scripts/Spells/spell_hunter.cpp
+++ b/src/server/scripts/Spells/spell_hunter.cpp
@@ -480,7 +480,7 @@ class spell_hun_misdirection : public SpellScriptLoader
void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
{
- if (GetTargetApplication()->GetRemoveMode() != AURA_REMOVE_BY_DEFAULT)
+ if (GetTargetApplication()->GetRemoveMode() != AURA_REMOVE_BY_DEFAULT || !GetTarget()->HasAura(SPELL_HUNTER_MISDIRECTION_PROC))
GetTarget()->ResetRedirectThreat();
}
diff --git a/src/server/scripts/Spells/spell_item.cpp b/src/server/scripts/Spells/spell_item.cpp
index 717382a0e36..f0b6c0945c2 100644
--- a/src/server/scripts/Spells/spell_item.cpp
+++ b/src/server/scripts/Spells/spell_item.cpp
@@ -2509,7 +2509,7 @@ class spell_item_chicken_cover : public SpellScriptLoader
if (!target->HasAura(SPELL_CHICKEN_NET) && (caster->GetQuestStatus(QUEST_CHICKEN_PARTY) == QUEST_STATUS_INCOMPLETE || caster->GetQuestStatus(QUEST_FLOWN_THE_COOP) == QUEST_STATUS_INCOMPLETE))
{
caster->CastSpell(caster, SPELL_CAPTURE_CHICKEN_ESCAPE, true);
- target->Kill(target);
+ target->KillSelf();
}
}
}
diff --git a/src/server/scripts/World/duel_reset.cpp b/src/server/scripts/World/duel_reset.cpp
index f08469d5bd5..9e720455692 100644
--- a/src/server/scripts/World/duel_reset.cpp
+++ b/src/server/scripts/World/duel_reset.cpp
@@ -17,6 +17,8 @@
#include "ScriptMgr.h"
#include "Player.h"
+#include "Pet.h"
+#include "SpellInfo.h"
class DuelResetScript : public PlayerScript
{
@@ -26,28 +28,89 @@ class DuelResetScript : public PlayerScript
// Called when a duel starts (after 3s countdown)
void OnDuelStart(Player* player1, Player* player2) override
{
+ // Cooldowns reset
if (sWorld->getBoolConfig(CONFIG_RESET_DUEL_COOLDOWNS))
{
player1->GetSpellHistory()->SaveCooldownStateBeforeDuel();
player2->GetSpellHistory()->SaveCooldownStateBeforeDuel();
- player1->RemoveArenaSpellCooldowns(true);
- player2->RemoveArenaSpellCooldowns(true);
+
+ ResetSpellCooldowns(player1);
+ ResetSpellCooldowns(player2);
+ }
+
+ // Health and mana reset
+ if (sWorld->getBoolConfig(CONFIG_RESET_DUEL_HEALTH_MANA))
+ {
+ player1->SaveHealthBeforeDuel();
+ player1->SetHealth(player1->GetMaxHealth());
+
+ player2->SaveHealthBeforeDuel();
+ player2->SetHealth(player2->GetMaxHealth());
+
+ // check if player1 class uses mana
+ if (player1->getPowerType() == POWER_MANA || player1->getClass() == CLASS_DRUID)
+ {
+ player1->SaveManaBeforeDuel();
+ player1->SetPower(POWER_MANA, player1->GetMaxPower(POWER_MANA));
+ }
+
+ // check if player2 class uses mana
+ if (player2->getPowerType() == POWER_MANA || player2->getClass() == CLASS_DRUID)
+ {
+ player2->SaveManaBeforeDuel();
+ player2->SetPower(POWER_MANA, player2->GetMaxPower(POWER_MANA));
+ }
}
}
// Called when a duel ends
- void OnDuelEnd(Player* winner, Player* loser, DuelCompleteType /*type*/) override
+ void OnDuelEnd(Player* winner, Player* loser, DuelCompleteType type) override
{
- if (sWorld->getBoolConfig(CONFIG_RESET_DUEL_COOLDOWNS))
+ // do not reset anything if DUEL_INTERRUPTED or DUEL_FLED
+ if (type == DUEL_WON)
{
- winner->RemoveArenaSpellCooldowns(true);
- loser->RemoveArenaSpellCooldowns(true);
+ // Cooldown restore
+ if (sWorld->getBoolConfig(CONFIG_RESET_DUEL_COOLDOWNS))
+ {
+
+ ResetSpellCooldowns(winner);
+ ResetSpellCooldowns(loser);
- winner->GetSpellHistory()->RestoreCooldownStateAfterDuel();
- loser->GetSpellHistory()->RestoreCooldownStateAfterDuel();
+ winner->GetSpellHistory()->RestoreCooldownStateAfterDuel();
+ loser->GetSpellHistory()->RestoreCooldownStateAfterDuel();
+ }
+
+ // Health and mana restore
+ if (sWorld->getBoolConfig(CONFIG_RESET_DUEL_HEALTH_MANA))
+ {
+ winner->RestoreHealthAfterDuel();
+ loser->RestoreHealthAfterDuel();
+
+ // check if player1 class uses mana
+ if (winner->getPowerType() == POWER_MANA || winner->getClass() == CLASS_DRUID)
+ winner->RestoreManaAfterDuel();
+
+ // check if player2 class uses mana
+ if (loser->getPowerType() == POWER_MANA || loser->getClass() == CLASS_DRUID)
+ loser->RestoreManaAfterDuel();
+ }
}
}
+
+ static void ResetSpellCooldowns(Player* player)
+ {
+ // remove cooldowns on spells that have < 10 min CD and has no onHold
+ player->GetSpellHistory()->ResetCooldowns([](SpellHistory::CooldownStorageType::iterator itr) -> bool
+ {
+ SpellInfo const* spellInfo = sSpellMgr->EnsureSpellInfo(itr->first);
+ return spellInfo->RecoveryTime < 10 * MINUTE * IN_MILLISECONDS && spellInfo->CategoryRecoveryTime < 10 * MINUTE * IN_MILLISECONDS && !itr->second.OnHold;
+ }, true);
+
+ // pet cooldowns
+ if (Pet* pet = player->GetPet())
+ pet->GetSpellHistory()->ResetAllCooldowns();
+ }
};
void AddSC_duel_reset()