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
This commit is contained in:
Pondaveia
2019-05-23 14:28:59 +01:00
committed by José González
parent 6b2254bee7
commit ff7658ed40
4 changed files with 384 additions and 213 deletions
@@ -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');
+11 -1
View File
@@ -4481,7 +4481,17 @@ void SpellMgr::LoadDbcDataCorrections()
spellInfo->AuraInterruptFlags |= AURA_INTERRUPT_FLAG_CHANGE_MAP; spellInfo->AuraInterruptFlags |= AURA_INTERRUPT_FLAG_CHANGE_MAP;
break; 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) ////////// Vault of Archavon (VOA)
@@ -4,12 +4,12 @@
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/> * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*/ */
/* ScriptData /* ScriptData
SDName: Boss_Archimonde SDName: Boss_Archimonde
SD%Complete: 85 SD%Complete: 85
SDComment: Doomfires not completely offlike due to core limitations for random moving. Tyrande and second phase not fully implemented. 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 SDCategory: Caverns of Time, Mount Hyjal
EndScriptData */ EndScriptData */
#include "ScriptMgr.h" #include "ScriptMgr.h"
#include "ScriptedCreature.h" #include "ScriptedCreature.h"
@@ -17,6 +17,7 @@ EndScriptData */
#include "SpellAuras.h" #include "SpellAuras.h"
#include "hyjal_trash.h" #include "hyjal_trash.h"
#include "Player.h" #include "Player.h"
#include "SpellScript.h"
enum Texts enum Texts
{ {
@@ -39,6 +40,7 @@ enum Spells
SPELL_DRAIN_WORLD_TREE_2 = 39141, SPELL_DRAIN_WORLD_TREE_2 = 39141,
SPELL_FINGER_OF_DEATH = 31984, SPELL_FINGER_OF_DEATH = 31984,
SPELL_RED_SKY_EFFECT = 32111,
SPELL_HAND_OF_DEATH = 35354, SPELL_HAND_OF_DEATH = 35354,
SPELL_AIR_BURST = 32014, SPELL_AIR_BURST = 32014,
SPELL_GRIP_OF_THE_LEGION = 31972, SPELL_GRIP_OF_THE_LEGION = 31972,
@@ -62,7 +64,27 @@ enum Summons
CREATURE_CHANNEL_TARGET = 22418, 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 class npc_ancient_wisp : public CreatureScript
{ {
@@ -114,7 +136,8 @@ public:
DoCast(Archimonde, SPELL_ANCIENT_SPARK); DoCast(Archimonde, SPELL_ANCIENT_SPARK);
} }
CheckTimer = 1000; CheckTimer = 1000;
} else CheckTimer -= diff; }
else CheckTimer -= diff;
} }
}; };
}; };
@@ -206,7 +229,8 @@ public:
} }
ChangeTargetTimer = 5000; ChangeTargetTimer = 5000;
} else ChangeTargetTimer -= diff; }
else ChangeTargetTimer -= diff;
} }
}; };
}; };
@@ -229,75 +253,106 @@ public:
return GetInstanceAI<boss_archimondeAI>(creature); return GetInstanceAI<boss_archimondeAI>(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(); instance = creature->GetInstanceScript();
} }
InstanceScript* instance; InstanceScript* instance;
EventMap events;
uint64 DoomfireSpiritGUID; uint64 DoomfireSpiritGUID;
uint64 WorldTreeGUID; uint64 WorldTreeGUID;
uint32 DrainNordrassilTimer;
uint32 FearTimer;
uint32 AirBurstTimer;
uint32 GripOfTheLegionTimer;
uint32 DoomfireTimer;
uint32 SoulChargeTimer;
uint8 SoulChargeCount; uint8 SoulChargeCount;
uint32 MeleeRangeCheckTimer;
uint32 HandOfDeathTimer;
uint32 SummonWispTimer;
uint8 WispCount; uint8 WispCount;
uint32 EnrageTimer; SummonList summons;
uint32 CheckDistanceTimer;
bool Enraged; bool Enraged;
bool BelowTenPercent; bool BelowTenPercent;
bool HasProtected; bool HasProtected;
bool IsChanneling; bool IsChanneling;
void Reset() std::list<Unit*> fingerOfDeathTargets;
std::list<Unit*> spellEffectTargets;
void Reset() override
{ {
instance->SetData(DATA_ARCHIMONDEEVENT, NOT_STARTED); instance->SetData(DATA_ARCHIMONDEEVENT, NOT_STARTED);
DoomfireSpiritGUID = 0; DoomfireSpiritGUID = 0;
damageTaken = 0;
WorldTreeGUID = 0; WorldTreeGUID = 0;
WispCount = 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;
Enraged = false; Enraged = false;
BelowTenPercent = false; BelowTenPercent = false;
HasProtected = false; HasProtected = false;
IsChanneling = 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);
} }
void EnterCombat(Unit* /*who*/) spellEffectTargets.clear();
fingerOfDeathTargets.clear();
summons.DespawnAll();
events.ScheduleEvent(EVENT_DRAIN_WORLD_TREE, 0);
}
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); me->InterruptSpell(CURRENT_CHANNELED_SPELL);
Talk(SAY_AGGRO); Talk(SAY_AGGRO);
DoZoneInCombat(); DoZoneInCombat();
instance->SetData(DATA_ARCHIMONDEEVENT, IN_PROGRESS); 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); Talk(SAY_SLAY);
@@ -326,56 +381,75 @@ public:
break; break;
} }
SoulChargeTimer = urand(2000, 30000); events.ScheduleEvent(EVENT_SPELL_UNLEASH_SOUL_CHARGES, urand(2000, 10000));
++SoulChargeCount; ++SoulChargeCount;
} }
void JustDied(Unit* killer) void JustDied(Unit* /*killer*/) override
{ {
hyjal_trashAI::JustDied(killer);
Talk(SAY_DEATH); Talk(SAY_DEATH);
instance->SetData(DATA_ARCHIMONDEEVENT, DONE); 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() bool CanUseFingerOfDeath()
{ {
// Cast finger of death below 10% health
if (BelowTenPercent)
return true;
if (me->IsAlive())
{
/* 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. // First we check if our current victim is in melee range or not.
Unit* victim = me->GetVictim(); Unit* victim = me->GetVictim();
if (victim && me->IsWithinDistInMap(victim, me->GetAggroRange(victim))) if (victim && me->IsWithinMeleeRange(victim))
return false; return false;
ThreatContainer::StorageType const &threatlist = me->getThreatManager().getThreatList(); ThreatContainer::StorageType const &threatlist = me->getThreatManager().getThreatList();
if (threatlist.empty()) if (threatlist.empty())
return false; return false;
std::list<Unit*> targets; auto itr = threatlist.begin();
ThreatContainer::StorageType::const_iterator itr = threatlist.begin();
for (; itr != threatlist.end(); ++itr) for (; itr != threatlist.end(); ++itr)
{ {
Unit* unit = ObjectAccessor::GetUnit(*me, (*itr)->getUnitGuid()); Unit* unit = ObjectAccessor::GetUnit(*me, (*itr)->getUnitGuid());
if (unit && unit->IsAlive()) if (unit && unit->IsAlive() && me->IsWithinMeleeRange(unit))
targets.push_back(unit); fingerOfDeathTargets.push_back(unit);
} }
if (targets.empty()) /* Previous check searched for targets in meele range and
return false; * added it to targets list. If there are no targets in meele
* range return true, which makes Archimonde cast Finger of Death.
targets.sort(Trinity::ObjectDistanceOrderPred(me)); */
Unit* target = targets.front(); return fingerOfDeathTargets.empty();
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; return false;
} }
void JustSummoned(Creature* summoned) void JustSummoned(Creature* summoned) override
{ {
summons.Summon(summoned);
if (summoned->GetEntry() == CREATURE_ANCIENT_WISP) if (summoned->GetEntry() == CREATURE_ANCIENT_WISP)
summoned->AI()->AttackStart(me); summoned->AI()->AttackStart(me);
else 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) //this is code doing close to what the summoning spell would do (spell 31903)
void SummonDoomfire(Unit* target) void SummonDoomfire(Unit* target)
{ {
me->SummonCreature(CREATURE_DOOMFIRE_SPIRIT, Unit* doomfire1 = me->SummonCreature(CREATURE_DOOMFIRE_SPIRIT,
target->GetPositionX()+15.0f, target->GetPositionY()+15.0f, target->GetPositionZ(), 0, target->GetPositionX() + 15.0f, target->GetPositionY() + 15.0f, target->GetPositionZ(), 0,
TEMPSUMMON_TIMED_DESPAWN, 27000); TEMPSUMMON_TIMED_DESPAWN, 27000);
me->SummonCreature(CREATURE_DOOMFIRE, Unit* doomfire2 = me->SummonCreature(CREATURE_DOOMFIRE,
target->GetPositionX()-15.0f, target->GetPositionY()-15.0f, target->GetPositionZ(), 0, target->GetPositionX() - 15.0f, target->GetPositionY() - 15.0f, target->GetPositionZ(), 0,
TEMPSUMMON_TIMED_DESPAWN, 27000); TEMPSUMMON_TIMED_DESPAWN, 27000);
doomfire1->SetVisible(false);
doomfire2->SetVisible(false);
} }
void UnleashSoulCharge() void UnleashSoulCharge()
{ {
me->InterruptNonMeleeSpells(false); me->InterruptNonMeleeSpells(false);
bool HasCast = false;
uint32 chargeSpell = 0; uint32 chargeSpell = 0;
uint32 unleashSpell = 0; uint32 unleashSpell = 0;
@@ -443,16 +531,15 @@ public:
{ {
me->RemoveAuraFromStack(chargeSpell); me->RemoveAuraFromStack(chargeSpell);
DoCastVictim(unleashSpell); DoCastVictim(unleashSpell);
HasCast = true;
SoulChargeCount--; 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()) if (!me->IsInCombat())
{ {
// Do not let the raid skip straight to Archimonde. Visible and hostile ONLY if Azagalor is finished. // Do not let the raid skip straight to Archimonde. Visible and hostile ONLY if Azagalor is finished.
@@ -461,14 +548,16 @@ public:
me->SetVisible(false); me->SetVisible(false);
me->setFaction(35); 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->setFaction(1720);
me->SetVisible(true); me->SetVisible(true);
} }
if (DrainNordrassilTimer <= diff) switch (events.ExecuteEvent())
{ {
case EVENT_DRAIN_WORLD_TREE:
if (!IsChanneling) if (!IsChanneling)
{ {
Creature* temp = me->SummonCreature(CREATURE_CHANNEL_TARGET, NordrassilLoc, TEMPSUMMON_TIMED_DESPAWN, 1200000); Creature* temp = me->SummonCreature(CREATURE_CHANNEL_TARGET, NordrassilLoc, TEMPSUMMON_TIMED_DESPAWN, 1200000);
@@ -486,35 +575,25 @@ public:
} }
if (Unit* Nordrassil = ObjectAccessor::GetUnit(*me, WorldTreeGUID)) if (Unit* Nordrassil = ObjectAccessor::GetUnit(*me, WorldTreeGUID))
{
Nordrassil->CastSpell(me, SPELL_DRAIN_WORLD_TREE_2, true); Nordrassil->CastSpell(me, SPELL_DRAIN_WORLD_TREE_2, true);
DrainNordrassilTimer = 1000; break;
} }
} else DrainNordrassilTimer -= diff;
} }
if (!UpdateVictim()) if (!UpdateVictim())
return; return;
if (me->HealthBelowPct(10) && !BelowTenPercent && !Enraged) if (me->HasUnitState(UNIT_STATE_CASTING))
BelowTenPercent = true; return;
if (!Enraged) if (me->HealthBelowPct(10) && !BelowTenPercent)
{ events.ScheduleEvent(EVENT_BELOW_10_PERCENT_HP, 0);
if (EnrageTimer <= diff)
{
if (HealthAbovePct(10))
{
me->GetMotionMaster()->Clear(false);
me->GetMotionMaster()->MoveIdle();
Enraged = true;
Talk(SAY_ENRAGE);
}
} else EnrageTimer -= diff;
if (CheckDistanceTimer <= diff) switch (events.ExecuteEvent())
{ {
// To simplify the check, we simply summon a Creature in the location and then check how far we are from the creature case EVENT_CHECK_WORLD_TREE_DISTANCE:
{
// 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); Creature* Check = me->SummonCreature(CREATURE_CHANNEL_TARGET, NordrassilLoc, TEMPSUMMON_TIMED_DESPAWN, 2000);
if (Check) if (Check)
{ {
@@ -522,109 +601,178 @@ public:
if (me->IsWithinDistInMap(Check, 75)) if (me->IsWithinDistInMap(Check, 75))
{ {
events.ScheduleEvent(EVENT_TOO_CLOSE_TO_WORLD_TREE, 0);
break;
}
}
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()->Clear(false);
me->GetMotionMaster()->MoveIdle(); me->GetMotionMaster()->MoveIdle();
Enraged = true; events.ScheduleEvent(EVENT_ENRAGE, 0);
Talk(SAY_ENRAGE); events.ScheduleEvent(EVENT_ENRAGE_ROOT, 0);
} events.ScheduleEvent(EVENT_SUMMON_WISPS, 1000);
} events.ScheduleEvent(EVENT_SPELL_HAND_OF_DEATH, 1500);
CheckDistanceTimer = 5000; events.ScheduleEvent(EVENT_SPELL_FINGER_OF_DEATH, 2500);
} else CheckDistanceTimer -= diff; break;
} case EVENT_SUMMON_WISPS:
// If there are more than 30 Wisps then kill Archimonde
if (BelowTenPercent)
{
if (!HasProtected)
{
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;
++WispCount;
} else SummonWispTimer -= diff;
if (WispCount >= 30) if (WispCount >= 30)
{
Unit::DealDamage(me, me, me->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); 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);
if (Enraged) ++WispCount;
{ events.ScheduleEvent(EVENT_SUMMON_WISPS, 1500);
if (HandOfDeathTimer <= diff) break;
{ case EVENT_SPELL_HAND_OF_DEATH:
DoCastVictim(SPELL_RED_SKY_EFFECT);
DoCastVictim(SPELL_HAND_OF_DEATH); DoCastVictim(SPELL_HAND_OF_DEATH);
HandOfDeathTimer = 2000; events.ScheduleEvent(EVENT_SPELL_HAND_OF_DEATH, 3000);
} else HandOfDeathTimer -= diff; break;
return; // Don't do anything after this point. case EVENT_SPELL_FINGER_OF_DEATH:
}
if (SoulChargeCount)
{
if (SoulChargeTimer <= diff)
UnleashSoulCharge();
else SoulChargeTimer -= diff;
}
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()) if (CanUseFingerOfDeath())
{ {
DoCast(SelectTarget(SELECT_TARGET_RANDOM, 0), SPELL_FINGER_OF_DEATH); Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0);
MeleeRangeCheckTimer = 1000; 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();
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;
} }
MeleeRangeCheckTimer = 5000;
} else MeleeRangeCheckTimer -= diff;
DoMeleeAttackIfReady(); 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() void AddSC_boss_archimonde()
{ {
new spell_red_sky_effect();
new spell_hand_of_death();
new spell_finger_of_death();
new boss_archimonde(); new boss_archimonde();
new npc_doomfire(); new npc_doomfire();
new npc_doomfire_targetting(); new npc_doomfire_targetting();
@@ -13,6 +13,11 @@
uint32 const EncounterCount = 5; uint32 const EncounterCount = 5;
enum HyjalBosses
{
BOSS_ARCHIMONDE = 0,
};
enum DataTypes enum DataTypes
{ {
DATA_ANETHERON = 1, DATA_ANETHERON = 1,