From ff7658ed40e552fc635e2f61555eb108b8bf8fe5 Mon Sep 17 00:00:00 2001
From: Pondaveia <43385840+Pondaveia@users.noreply.github.com>
Date: Thu, 23 May 2019 14:28:59 +0100
Subject: [PATCH] fix(Core/Raid): Reworked Archimonde fight (#1691)
* Reworked Archimonde
* missing spell scripts on db
* Travis?
* Thanks Nefertum
* Update rev_1554524766481187700.sql
* compact sql
* Update data/sql/updates/pending_db_world/rev_1554524766481187700.sql
Co-Authored-By: Pondaveia <43385840+Pondaveia@users.noreply.github.com>
* Update rev_1554524766481187700.sql
* Update boss_archimonde.cpp
* Resets
* Update boss_archimonde.cpp
* Update boss_archimonde.cpp
* Finger of death check improvement
Deku suggested adding this check instead:
- me->IsWithinMeleeRange(unit)
* fix: remove unneeded if statement
* Possible targets list bug
Added a list for both Finger of death and Spell protections specifically. Also cleared the lists when needed to avoid possible bugs.
* comment typo
* Last touches
* Copy paste fail?
Removed waypoint reached function. No idea how it got there!
* Update boss_archimonde.cpp
* The meele check was too small
This check allows the tank to move the boss without getting snipped by finger of death
* Update boss_archimonde.cpp
* Initializing summonlist on constructor
* Update hyjal.h
* Update hyjal.h
* Changed Archimonde AI
Hyjal_trash AI to BossAI
* Removing hyjal_trashAI function
* Somehow the commit above didn't remove
* unused variable
* bool initialization on the constructor
bool Enraged;
bool BelowTenPercent;
bool HasProtected;
bool IsChanneling;
* HOLY SHIT TRAVIS
---
.../rev_1554524766481187700.sql | 8 +
src/server/game/Spells/SpellMgr.cpp | 12 +-
.../BattleForMountHyjal/boss_archimonde.cpp | 572 +++++++++++-------
.../CavernsOfTime/BattleForMountHyjal/hyjal.h | 5 +
4 files changed, 384 insertions(+), 213 deletions(-)
create mode 100644 data/sql/updates/pending_db_world/rev_1554524766481187700.sql
diff --git a/data/sql/updates/pending_db_world/rev_1554524766481187700.sql b/data/sql/updates/pending_db_world/rev_1554524766481187700.sql
new file mode 100644
index 000000000..f8627eb25
--- /dev/null
+++ b/data/sql/updates/pending_db_world/rev_1554524766481187700.sql
@@ -0,0 +1,8 @@
+INSERT INTO `version_db_world` (`sql_rev`) VALUES ('1554524766481187700');
+
+DELETE FROM `spell_script_names` WHERE `spell_id` IN (32111, 31984, 35354);
+
+INSERT INTO `spell_script_names` VALUES
+(32111, 'spell_red_sky_effect'),
+(31984, 'spell_finger_of_death'),
+(35354, 'spell_hand_of_death');
diff --git a/src/server/game/Spells/SpellMgr.cpp b/src/server/game/Spells/SpellMgr.cpp
index 8f77de4d6..6eb5357a5 100644
--- a/src/server/game/Spells/SpellMgr.cpp
+++ b/src/server/game/Spells/SpellMgr.cpp
@@ -4481,7 +4481,17 @@ void SpellMgr::LoadDbcDataCorrections()
spellInfo->AuraInterruptFlags |= AURA_INTERRUPT_FLAG_CHANGE_MAP;
break;
-
+ /*
+ Raid: Battle for Mount Hyjal
+ Boss: Archimonde
+ */
+ case 31984: // Spell doesn't need to ignore invulnerabilities
+ case 35354:
+ spellInfo->Attributes = SPELL_ATTR0_ABILITY;
+ break;
+ case 32111: // We only need the animation, no damage
+ spellInfo->CastingTimeIndex = 0;
+ break;
//////////////////////////////////////////
////////// Vault of Archavon (VOA)
diff --git a/src/server/scripts/Kalimdor/CavernsOfTime/BattleForMountHyjal/boss_archimonde.cpp b/src/server/scripts/Kalimdor/CavernsOfTime/BattleForMountHyjal/boss_archimonde.cpp
index b63f5a171..434937416 100644
--- a/src/server/scripts/Kalimdor/CavernsOfTime/BattleForMountHyjal/boss_archimonde.cpp
+++ b/src/server/scripts/Kalimdor/CavernsOfTime/BattleForMountHyjal/boss_archimonde.cpp
@@ -4,12 +4,12 @@
* Copyright (C) 2005-2009 MaNGOS
*/
-/* ScriptData
-SDName: Boss_Archimonde
-SD%Complete: 85
-SDComment: Doomfires not completely offlike due to core limitations for random moving. Tyrande and second phase not fully implemented.
-SDCategory: Caverns of Time, Mount Hyjal
-EndScriptData */
+ /* ScriptData
+ SDName: Boss_Archimonde
+ SD%Complete: 85
+ SDComment: Doomfires not completely offlike due to core limitations for random moving. Tyrande and second phase not fully implemented.
+ SDCategory: Caverns of Time, Mount Hyjal
+ EndScriptData */
#include "ScriptMgr.h"
#include "ScriptedCreature.h"
@@ -17,6 +17,7 @@ EndScriptData */
#include "SpellAuras.h"
#include "hyjal_trash.h"
#include "Player.h"
+#include "SpellScript.h"
enum Texts
{
@@ -39,6 +40,7 @@ enum Spells
SPELL_DRAIN_WORLD_TREE_2 = 39141,
SPELL_FINGER_OF_DEATH = 31984,
+ SPELL_RED_SKY_EFFECT = 32111,
SPELL_HAND_OF_DEATH = 35354,
SPELL_AIR_BURST = 32014,
SPELL_GRIP_OF_THE_LEGION = 31972,
@@ -56,13 +58,33 @@ enum Spells
enum Summons
{
- CREATURE_DOOMFIRE = 18095,
- CREATURE_DOOMFIRE_SPIRIT = 18104,
- CREATURE_ANCIENT_WISP = 17946,
- CREATURE_CHANNEL_TARGET = 22418,
+ CREATURE_DOOMFIRE = 18095,
+ CREATURE_DOOMFIRE_SPIRIT = 18104,
+ CREATURE_ANCIENT_WISP = 17946,
+ CREATURE_CHANNEL_TARGET = 22418,
};
-Position const NordrassilLoc = {5503.713f, -3523.436f, 1608.781f, 0.0f};
+enum Events
+{
+ EVENT_DRAIN_WORLD_TREE = 1,
+ EVENT_SPELL_FEAR = 2,
+ EVENT_SPELL_AIR_BURST = 3,
+ EVENT_SPELL_GRIP_OF_THE_LEGION = 4,
+ EVENT_SPELL_UNLEASH_SOUL_CHARGES = 5,
+ EVENT_SPELL_DOOMFIRE = 6,
+ EVENT_SPELL_FINGER_OF_DEATH = 7,
+ EVENT_SPELL_HAND_OF_DEATH = 8,
+ EVENT_SPELL_PROTECTION_OF_ELUNE = 9,
+ EVENT_ENRAGE = 10,
+ EVENT_CHECK_WORLD_TREE_DISTANCE = 11, // Enrage if too close to the tree
+ EVENT_BELOW_10_PERCENT_HP = 12,
+ EVENT_SUMMON_WISPS = 13,
+ EVENT_TOO_CLOSE_TO_WORLD_TREE = 14,
+ EVENT_ENRAGE_ROOT = 15,
+ EVENT_SPELL_FINGER_OF_DEATH_PHASE_4 = 16
+};
+
+Position const NordrassilLoc = { 5503.713f, -3523.436f, 1608.781f, 0.0f };
class npc_ancient_wisp : public CreatureScript
{
@@ -114,7 +136,8 @@ public:
DoCast(Archimonde, SPELL_ANCIENT_SPARK);
}
CheckTimer = 1000;
- } else CheckTimer -= diff;
+ }
+ else CheckTimer -= diff;
}
};
};
@@ -206,7 +229,8 @@ public:
}
ChangeTargetTimer = 5000;
- } else ChangeTargetTimer -= diff;
+ }
+ else ChangeTargetTimer -= diff;
}
};
};
@@ -229,75 +253,106 @@ public:
return GetInstanceAI(creature);
}
- struct boss_archimondeAI : public hyjal_trashAI
+ struct boss_archimondeAI : public BossAI
{
- boss_archimondeAI(Creature* creature) : hyjal_trashAI(creature)
+ boss_archimondeAI(Creature* creature) : BossAI(creature, BOSS_ARCHIMONDE), summons(me),
+ Enraged(false), BelowTenPercent(false), HasProtected(false), IsChanneling(false)
{
instance = creature->GetInstanceScript();
}
InstanceScript* instance;
+ EventMap events;
uint64 DoomfireSpiritGUID;
uint64 WorldTreeGUID;
- uint32 DrainNordrassilTimer;
- uint32 FearTimer;
- uint32 AirBurstTimer;
- uint32 GripOfTheLegionTimer;
- uint32 DoomfireTimer;
- uint32 SoulChargeTimer;
uint8 SoulChargeCount;
- uint32 MeleeRangeCheckTimer;
- uint32 HandOfDeathTimer;
- uint32 SummonWispTimer;
uint8 WispCount;
- uint32 EnrageTimer;
- uint32 CheckDistanceTimer;
+ SummonList summons;
bool Enraged;
bool BelowTenPercent;
bool HasProtected;
bool IsChanneling;
- void Reset()
+ std::list fingerOfDeathTargets;
+ std::list spellEffectTargets;
+
+ void Reset() override
{
instance->SetData(DATA_ARCHIMONDEEVENT, NOT_STARTED);
DoomfireSpiritGUID = 0;
- damageTaken = 0;
WorldTreeGUID = 0;
-
- DrainNordrassilTimer = 0;
- FearTimer = 42000;
- AirBurstTimer = 30000;
- GripOfTheLegionTimer = urand(5000, 25000);
- DoomfireTimer = 20000;
- SoulChargeTimer = urand(2000, 30000);
- SoulChargeCount = 0;
- MeleeRangeCheckTimer = 15000;
- HandOfDeathTimer = 2000;
- WispCount = 0; // When ~30 wisps are summoned, Archimonde dies
- EnrageTimer = 600000; // 10 minutes
- CheckDistanceTimer = 30000; // This checks if he's too close to the World Tree (75 yards from a point on the tree), if true then he will enrage
- SummonWispTimer = 0;
-
+ WispCount = 0;
Enraged = false;
BelowTenPercent = false;
HasProtected = false;
IsChanneling = false;
+
+ // Reset player's immunity to Spells
+ for (auto it = spellEffectTargets.begin(); it != spellEffectTargets.end(); ++it)
+ {
+ Unit* affected_unit = ObjectAccessor::GetUnit(*me, (*it)->GetGUID());
+
+ // Remove Immunity against Hand of death
+ affected_unit->ApplySpellImmune(SPELL_HAND_OF_DEATH, IMMUNITY_ID, SPELL_HAND_OF_DEATH, false);
+ affected_unit->ApplySpellImmune(0, IMMUNITY_ID, SPELL_HAND_OF_DEATH, false);
+ }
+
+ spellEffectTargets.clear();
+ fingerOfDeathTargets.clear();
+ summons.DespawnAll();
+ events.ScheduleEvent(EVENT_DRAIN_WORLD_TREE, 0);
}
- void EnterCombat(Unit* /*who*/)
+ void DoCastProtection()
+ {
+ // lets get spell info
+ const SpellInfo* info = sSpellMgr->GetSpellInfo(SPELL_PROTECTION_OF_ELUNE);
+
+ if (!info)
+ return;
+
+ // Now lets get archimode threat list
+ ThreatContainer::StorageType const &t_list = me->getThreatManager().getThreatList();
+
+ if (t_list.empty())
+ return;
+
+ ThreatContainer::StorageType::const_iterator itr = t_list.begin();
+
+ if (Unit* target = ObjectAccessor::GetUnit(*me, (*itr)->getUnitGuid()))
+ if (target->IsAlive() && target->GetTypeId() == TYPEID_PLAYER)
+ spellEffectTargets.push_back(target);
+
+ for (auto iter = spellEffectTargets.begin(); iter != spellEffectTargets.end(); ++iter)
+ if (Unit* target = *iter)
+ {
+ target->AddAura(SPELL_PROTECTION_OF_ELUNE, target);
+
+ // Immunity against Hand of death
+ target->ApplySpellImmune(SPELL_HAND_OF_DEATH, IMMUNITY_ID, SPELL_HAND_OF_DEATH, true);
+ target->ApplySpellImmune(0, IMMUNITY_ID, SPELL_HAND_OF_DEATH, true);
+ }
+ }
+
+ void EnterCombat(Unit* /*who*/) override
{
me->InterruptSpell(CURRENT_CHANNELED_SPELL);
Talk(SAY_AGGRO);
DoZoneInCombat();
instance->SetData(DATA_ARCHIMONDEEVENT, IN_PROGRESS);
+ events.ScheduleEvent(EVENT_SPELL_AIR_BURST, urand(25000, 35000));
+ events.ScheduleEvent(EVENT_SPELL_DOOMFIRE, urand(10000, 20000));
+ events.ScheduleEvent(EVENT_SPELL_FEAR, 42000);
+ events.ScheduleEvent(EVENT_SPELL_GRIP_OF_THE_LEGION, 2000);
+ events.ScheduleEvent(EVENT_SPELL_FINGER_OF_DEATH, 1000);
}
- void KilledUnit(Unit* victim)
+ void KilledUnit(Unit* victim) override
{
Talk(SAY_SLAY);
@@ -326,56 +381,75 @@ public:
break;
}
- SoulChargeTimer = urand(2000, 30000);
+ events.ScheduleEvent(EVENT_SPELL_UNLEASH_SOUL_CHARGES, urand(2000, 10000));
++SoulChargeCount;
}
- void JustDied(Unit* killer)
+ void JustDied(Unit* /*killer*/) override
{
- hyjal_trashAI::JustDied(killer);
Talk(SAY_DEATH);
instance->SetData(DATA_ARCHIMONDEEVENT, DONE);
- instance->DoUpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_KILL_CREATURE, me->GetEntry(), 1, me); }
+ instance->DoUpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_KILL_CREATURE, me->GetEntry(), 1, me);
+
+ // Reset scheduled events
+ events.CancelEvent(EVENT_SPELL_FEAR);
+ events.CancelEvent(EVENT_SPELL_AIR_BURST);
+ events.CancelEvent(EVENT_SPELL_GRIP_OF_THE_LEGION);
+ events.CancelEvent(EVENT_SPELL_UNLEASH_SOUL_CHARGES);
+ events.CancelEvent(EVENT_SPELL_DOOMFIRE);
+ events.CancelEvent(EVENT_SPELL_FINGER_OF_DEATH);
+ events.CancelEvent(EVENT_SPELL_HAND_OF_DEATH);
+ events.CancelEvent(EVENT_SPELL_PROTECTION_OF_ELUNE);
+ events.CancelEvent(EVENT_ENRAGE);
+
+ spellEffectTargets.clear();
+ fingerOfDeathTargets.clear();
+ summons.DespawnAll();
+ }
bool CanUseFingerOfDeath()
{
- // First we check if our current victim is in melee range or not.
- Unit* victim = me->GetVictim();
- if (victim && me->IsWithinDistInMap(victim, me->GetAggroRange(victim)))
- return false;
+ // Cast finger of death below 10% health
+ if (BelowTenPercent)
+ return true;
- ThreatContainer::StorageType const &threatlist = me->getThreatManager().getThreatList();
- if (threatlist.empty())
- return false;
-
- std::list targets;
- ThreatContainer::StorageType::const_iterator itr = threatlist.begin();
- for (; itr != threatlist.end(); ++itr)
+ if (me->IsAlive())
{
- Unit* unit = ObjectAccessor::GetUnit(*me, (*itr)->getUnitGuid());
- if (unit && unit->IsAlive())
- targets.push_back(unit);
+ /* Reset the list before checking for new targets
+ * else we will be using old targets that could have
+ * been distant but are no longer.*/
+ fingerOfDeathTargets.clear();
+
+ // First we check if our current victim is in melee range or not.
+ Unit* victim = me->GetVictim();
+ if (victim && me->IsWithinMeleeRange(victim))
+ return false;
+
+ ThreatContainer::StorageType const &threatlist = me->getThreatManager().getThreatList();
+ if (threatlist.empty())
+ return false;
+
+ auto itr = threatlist.begin();
+ for (; itr != threatlist.end(); ++itr)
+ {
+ Unit* unit = ObjectAccessor::GetUnit(*me, (*itr)->getUnitGuid());
+ if (unit && unit->IsAlive() && me->IsWithinMeleeRange(unit))
+ fingerOfDeathTargets.push_back(unit);
+ }
+
+ /* Previous check searched for targets in meele range and
+ * added it to targets list. If there are no targets in meele
+ * range return true, which makes Archimonde cast Finger of Death.
+ */
+ return fingerOfDeathTargets.empty();
}
-
- if (targets.empty())
- return false;
-
- targets.sort(Trinity::ObjectDistanceOrderPred(me));
- Unit* target = targets.front();
- if (target)
- {
- if (!me->IsWithinDistInMap(target, me->GetAggroRange(target)))
- return true; // Cast Finger of Death
- else // This target is closest, he is our new tank
- me->AddThreat(target, me->getThreatManager().getThreat(me->GetVictim()));
- }
-
return false;
}
- void JustSummoned(Creature* summoned)
+ void JustSummoned(Creature* summoned) override
{
+ summons.Summon(summoned);
if (summoned->GetEntry() == CREATURE_ANCIENT_WISP)
summoned->AI()->AttackStart(me);
else
@@ -403,23 +477,37 @@ public:
}
}
+ void DoCastDoomfire()
+ {
+ // Three doomfire can be up at the same time
+ Talk(SAY_DOOMFIRE);
+ Unit* temp = SelectTarget(SELECT_TARGET_RANDOM, 1);
+ if (!temp)
+ temp = me->GetVictim();
+
+ //replace with spell cast 31903 once implicitTarget 73 implemented
+ SummonDoomfire(temp);
+ }
+
//this is code doing close to what the summoning spell would do (spell 31903)
void SummonDoomfire(Unit* target)
{
- me->SummonCreature(CREATURE_DOOMFIRE_SPIRIT,
- target->GetPositionX()+15.0f, target->GetPositionY()+15.0f, target->GetPositionZ(), 0,
+ Unit* doomfire1 = me->SummonCreature(CREATURE_DOOMFIRE_SPIRIT,
+ target->GetPositionX() + 15.0f, target->GetPositionY() + 15.0f, target->GetPositionZ(), 0,
TEMPSUMMON_TIMED_DESPAWN, 27000);
- me->SummonCreature(CREATURE_DOOMFIRE,
- target->GetPositionX()-15.0f, target->GetPositionY()-15.0f, target->GetPositionZ(), 0,
+ Unit* doomfire2 = me->SummonCreature(CREATURE_DOOMFIRE,
+ target->GetPositionX() - 15.0f, target->GetPositionY() - 15.0f, target->GetPositionZ(), 0,
TEMPSUMMON_TIMED_DESPAWN, 27000);
+
+ doomfire1->SetVisible(false);
+ doomfire2->SetVisible(false);
}
void UnleashSoulCharge()
{
me->InterruptNonMeleeSpells(false);
- bool HasCast = false;
uint32 chargeSpell = 0;
uint32 unleashSpell = 0;
@@ -443,16 +531,15 @@ public:
{
me->RemoveAuraFromStack(chargeSpell);
DoCastVictim(unleashSpell);
- HasCast = true;
SoulChargeCount--;
}
-
- if (HasCast)
- SoulChargeTimer = urand(2000, 30000);
}
- void UpdateAI(uint32 diff)
+ void UpdateAI(uint32 diff) override
{
+ events.Update(diff);
+
+ // Event for draining the tree
if (!me->IsInCombat())
{
// Do not let the raid skip straight to Archimonde. Visible and hostile ONLY if Azagalor is finished.
@@ -461,60 +548,52 @@ public:
me->SetVisible(false);
me->setFaction(35);
}
- else if ((instance->GetData(DATA_AZGALOREVENT) >= DONE) && (!me->IsVisible() || (me->getFaction() == 35)))
+
+ if ((instance->GetData(DATA_AZGALOREVENT) >= DONE) && (!me->IsVisible() || (me->getFaction() == 35)))
{
me->setFaction(1720);
me->SetVisible(true);
}
- if (DrainNordrassilTimer <= diff)
+ switch (events.ExecuteEvent())
{
- if (!IsChanneling)
- {
- Creature* temp = me->SummonCreature(CREATURE_CHANNEL_TARGET, NordrassilLoc, TEMPSUMMON_TIMED_DESPAWN, 1200000);
+ case EVENT_DRAIN_WORLD_TREE:
+ if (!IsChanneling)
+ {
+ Creature* temp = me->SummonCreature(CREATURE_CHANNEL_TARGET, NordrassilLoc, TEMPSUMMON_TIMED_DESPAWN, 1200000);
- if (temp)
- WorldTreeGUID = temp->GetGUID();
+ if (temp)
+ WorldTreeGUID = temp->GetGUID();
+
+ if (Unit* Nordrassil = ObjectAccessor::GetUnit(*me, WorldTreeGUID))
+ {
+ Nordrassil->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
+ Nordrassil->SetDisplayId(11686);
+ DoCast(Nordrassil, SPELL_DRAIN_WORLD_TREE);
+ IsChanneling = true;
+ }
+ }
if (Unit* Nordrassil = ObjectAccessor::GetUnit(*me, WorldTreeGUID))
- {
- Nordrassil->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
- Nordrassil->SetDisplayId(11686);
- DoCast(Nordrassil, SPELL_DRAIN_WORLD_TREE);
- IsChanneling = true;
- }
- }
-
- if (Unit* Nordrassil = ObjectAccessor::GetUnit(*me, WorldTreeGUID))
- {
- Nordrassil->CastSpell(me, SPELL_DRAIN_WORLD_TREE_2, true);
- DrainNordrassilTimer = 1000;
- }
- } else DrainNordrassilTimer -= diff;
+ Nordrassil->CastSpell(me, SPELL_DRAIN_WORLD_TREE_2, true);
+ break;
+ }
}
if (!UpdateVictim())
return;
- if (me->HealthBelowPct(10) && !BelowTenPercent && !Enraged)
- BelowTenPercent = true;
+ if (me->HasUnitState(UNIT_STATE_CASTING))
+ return;
- if (!Enraged)
+ if (me->HealthBelowPct(10) && !BelowTenPercent)
+ events.ScheduleEvent(EVENT_BELOW_10_PERCENT_HP, 0);
+
+ switch (events.ExecuteEvent())
{
- if (EnrageTimer <= diff)
+ case EVENT_CHECK_WORLD_TREE_DISTANCE:
{
- if (HealthAbovePct(10))
- {
- me->GetMotionMaster()->Clear(false);
- me->GetMotionMaster()->MoveIdle();
- Enraged = true;
- Talk(SAY_ENRAGE);
- }
- } else EnrageTimer -= diff;
-
- if (CheckDistanceTimer <= diff)
- {
- // To simplify the check, we simply summon a Creature in the location and then check how far we are from the creature
+ // If Archimonde is too close to the world tree this will ENRAGE him
Creature* Check = me->SummonCreature(CREATURE_CHANNEL_TARGET, NordrassilLoc, TEMPSUMMON_TIMED_DESPAWN, 2000);
if (Check)
{
@@ -522,109 +601,178 @@ public:
if (me->IsWithinDistInMap(Check, 75))
{
- me->GetMotionMaster()->Clear(false);
- me->GetMotionMaster()->MoveIdle();
- Enraged = true;
- Talk(SAY_ENRAGE);
+ events.ScheduleEvent(EVENT_TOO_CLOSE_TO_WORLD_TREE, 0);
+ break;
}
}
- CheckDistanceTimer = 5000;
- } else CheckDistanceTimer -= diff;
- }
-
- if (BelowTenPercent)
- {
- if (!HasProtected)
- {
+ events.RepeatEvent(5000);
+ break;
+ }
+ case EVENT_BELOW_10_PERCENT_HP:
+ DoCastProtection(); // Protection of Elune against Finger and Hand of Death
+ BelowTenPercent = true;
me->GetMotionMaster()->Clear(false);
me->GetMotionMaster()->MoveIdle();
-
- //all members of raid must get this buff
- DoCastVictim(SPELL_PROTECTION_OF_ELUNE, true);
- HasProtected = true;
- Enraged = true;
- }
-
- if (SummonWispTimer <= diff)
- {
- DoSpawnCreature(CREATURE_ANCIENT_WISP, float(rand()%40), float(rand()%40), 0, 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000);
- SummonWispTimer = 1500;
+ events.ScheduleEvent(EVENT_ENRAGE, 0);
+ events.ScheduleEvent(EVENT_ENRAGE_ROOT, 0);
+ events.ScheduleEvent(EVENT_SUMMON_WISPS, 1000);
+ events.ScheduleEvent(EVENT_SPELL_HAND_OF_DEATH, 1500);
+ events.ScheduleEvent(EVENT_SPELL_FINGER_OF_DEATH, 2500);
+ break;
+ case EVENT_SUMMON_WISPS:
+ // If there are more than 30 Wisps then kill Archimonde
+ if (WispCount >= 30)
+ {
+ Unit::DealDamage(me, me, me->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false);
+ return; // Finish the encounter and no more event repeat
+ }
+ DoSpawnCreature(CREATURE_ANCIENT_WISP, float(rand() % 40), float(rand() % 40), 0, 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000);
++WispCount;
- } else SummonWispTimer -= diff;
-
- if (WispCount >= 30)
- Unit::DealDamage(me, me, me->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false);
- }
-
- if (Enraged)
- {
- if (HandOfDeathTimer <= diff)
- {
+ events.ScheduleEvent(EVENT_SUMMON_WISPS, 1500);
+ break;
+ case EVENT_SPELL_HAND_OF_DEATH:
+ DoCastVictim(SPELL_RED_SKY_EFFECT);
DoCastVictim(SPELL_HAND_OF_DEATH);
- HandOfDeathTimer = 2000;
- } else HandOfDeathTimer -= diff;
- return; // Don't do anything after this point.
- }
-
- if (SoulChargeCount)
- {
- if (SoulChargeTimer <= diff)
+ events.ScheduleEvent(EVENT_SPELL_HAND_OF_DEATH, 3000);
+ break;
+ case EVENT_SPELL_FINGER_OF_DEATH:
+ if (CanUseFingerOfDeath())
+ {
+ Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0);
+ DoCast(target, SPELL_FINGER_OF_DEATH);
+ DoCastVictim(SPELL_RED_SKY_EFFECT);
+ }
+ events.ScheduleEvent(EVENT_SPELL_FINGER_OF_DEATH, 3500);
+ break;
+ case EVENT_SPELL_GRIP_OF_THE_LEGION:
+ DoCast(SelectTarget(SELECT_TARGET_RANDOM, 0), SPELL_GRIP_OF_THE_LEGION);
+ events.ScheduleEvent(EVENT_SPELL_GRIP_OF_THE_LEGION, urand(5000, 25000));
+ break;
+ case EVENT_SPELL_AIR_BURST:
+ Talk(SAY_AIR_BURST);
+ DoCast(SelectTarget(SELECT_TARGET_RANDOM, 0), SPELL_AIR_BURST);
+ events.ScheduleEvent(EVENT_SPELL_AIR_BURST, urand(25000, 40000));
+ break;
+ case EVENT_SPELL_FEAR:
+ DoCastVictim(SPELL_FEAR);
+ events.ScheduleEvent(EVENT_SPELL_FEAR, 42000);
+ break;
+ case EVENT_SPELL_DOOMFIRE:
+ DoCastDoomfire();
+ events.ScheduleEvent(EVENT_SPELL_DOOMFIRE, 20000);
+ break;
+ case EVENT_SPELL_UNLEASH_SOUL_CHARGES:
UnleashSoulCharge();
- else SoulChargeTimer -= diff;
+ break;
+ case EVENT_ENRAGE:
+ Talk(SAY_ENRAGE);
+ break;
+ case EVENT_TOO_CLOSE_TO_WORLD_TREE:
+ // People dragged the boss near the check and now wipe
+ events.ScheduleEvent(EVENT_ENRAGE, 0);
+ events.ScheduleEvent(EVENT_SPELL_HAND_OF_DEATH, 1000);
+ break;
+ case EVENT_ENRAGE_ROOT:
+ me->GetMotionMaster()->Clear(false);
+ me->GetMotionMaster()->MoveIdle();
+ break;
}
- if (GripOfTheLegionTimer <= diff)
- {
- DoCast(SelectTarget(SELECT_TARGET_RANDOM, 0), SPELL_GRIP_OF_THE_LEGION);
- GripOfTheLegionTimer = urand(5000, 25000);
- } else GripOfTheLegionTimer -= diff;
-
- if (AirBurstTimer <= diff)
- {
- Talk(SAY_AIR_BURST);
- DoCast(SelectTarget(SELECT_TARGET_RANDOM, 1), SPELL_AIR_BURST);//not on tank
- AirBurstTimer = urand(25000, 40000);
- } else AirBurstTimer -= diff;
-
- if (FearTimer <= diff)
- {
- DoCastVictim(SPELL_FEAR);
- FearTimer = 42000;
- } else FearTimer -= diff;
-
- if (DoomfireTimer <= diff)
- {
- Talk(SAY_DOOMFIRE);
- Unit* temp = SelectTarget(SELECT_TARGET_RANDOM, 1);
- if (!temp)
- temp = me->GetVictim();
-
- //replace with spell cast 31903 once implicitTarget 73 implemented
- SummonDoomfire(temp);
-
- //supposedly three doomfire can be up at the same time
- DoomfireTimer = 20000;
- } else DoomfireTimer -= diff;
-
- if (MeleeRangeCheckTimer <= diff)
- {
- if (CanUseFingerOfDeath())
- {
- DoCast(SelectTarget(SELECT_TARGET_RANDOM, 0), SPELL_FINGER_OF_DEATH);
- MeleeRangeCheckTimer = 1000;
- }
-
- MeleeRangeCheckTimer = 5000;
- } else MeleeRangeCheckTimer -= diff;
-
DoMeleeAttackIfReady();
}
- void WaypointReached(uint32 /*waypointId*/) { }
};
};
+class spell_red_sky_effect : public SpellScriptLoader
+{
+ public:
+ spell_red_sky_effect() : SpellScriptLoader("spell_red_sky_effect") { }
+
+ class spell_red_sky_effect_SpellScript : public SpellScript
+ {
+ PrepareSpellScript(spell_red_sky_effect_SpellScript);
+
+ void HandleHit(SpellEffIndex /*effIndex*/)
+ {
+ if (GetHitUnit())
+ PreventHitDamage();
+ }
+
+ void Register() override
+ {
+ OnEffectHitTarget += SpellEffectFn(spell_red_sky_effect_SpellScript::HandleHit, EFFECT_0, SPELL_EFFECT_SCHOOL_DAMAGE);
+ }
+ };
+
+ SpellScript* GetSpellScript() const
+ {
+ return new spell_red_sky_effect_SpellScript();
+ }
+};
+
+class spell_finger_of_death : public SpellScriptLoader
+{
+public:
+ spell_finger_of_death() : SpellScriptLoader("spell_finger_of_death") { }
+
+ class spell_finger_of_death_SpellScript : public SpellScript
+ {
+ PrepareSpellScript(spell_finger_of_death_SpellScript);
+
+ void HandleHit(SpellEffIndex /*effIndex*/)
+ {
+ if (GetHitUnit() && GetHitUnit()->GetAura(SPELL_PROTECTION_OF_ELUNE))
+ PreventHitDamage();
+ else
+ GetHitUnit()->RemoveAurasByType(SPELL_AURA_EFFECT_IMMUNITY);
+ }
+
+ void Register() override
+ {
+ OnEffectHitTarget += SpellEffectFn(spell_finger_of_death_SpellScript::HandleHit, EFFECT_0, SPELL_EFFECT_SCHOOL_DAMAGE);
+ }
+ };
+
+ SpellScript* GetSpellScript() const
+ {
+ return new spell_finger_of_death_SpellScript();
+ }
+};
+
+class spell_hand_of_death : public SpellScriptLoader
+{
+public:
+ spell_hand_of_death() : SpellScriptLoader("spell_hand_of_death") { }
+
+ class spell_hand_of_death_SpellScript : public SpellScript
+ {
+ PrepareSpellScript(spell_hand_of_death_SpellScript);
+
+ void HandleHit(SpellEffIndex /*effIndex*/)
+ {
+ if (GetHitUnit() && GetHitUnit()->GetAura(SPELL_PROTECTION_OF_ELUNE))
+ PreventHitDamage();
+ else
+ GetHitUnit()->RemoveAurasByType(SPELL_AURA_EFFECT_IMMUNITY);
+ }
+
+ void Register() override
+ {
+ OnEffectHitTarget += SpellEffectFn(spell_hand_of_death_SpellScript::HandleHit, EFFECT_0, SPELL_EFFECT_SCHOOL_DAMAGE);
+ }
+ };
+
+ SpellScript* GetSpellScript() const
+ {
+ return new spell_hand_of_death_SpellScript();
+ }
+};
+
void AddSC_boss_archimonde()
{
+ new spell_red_sky_effect();
+ new spell_hand_of_death();
+ new spell_finger_of_death();
new boss_archimonde();
new npc_doomfire();
new npc_doomfire_targetting();
diff --git a/src/server/scripts/Kalimdor/CavernsOfTime/BattleForMountHyjal/hyjal.h b/src/server/scripts/Kalimdor/CavernsOfTime/BattleForMountHyjal/hyjal.h
index 584a2911a..5c5d48851 100644
--- a/src/server/scripts/Kalimdor/CavernsOfTime/BattleForMountHyjal/hyjal.h
+++ b/src/server/scripts/Kalimdor/CavernsOfTime/BattleForMountHyjal/hyjal.h
@@ -13,6 +13,11 @@
uint32 const EncounterCount = 5;
+enum HyjalBosses
+{
+ BOSS_ARCHIMONDE = 0,
+};
+
enum DataTypes
{
DATA_ANETHERON = 1,