diff --git a/src/server/scripts/EasternKingdoms/Karazhan/boss_moroes.cpp b/src/server/scripts/EasternKingdoms/Karazhan/boss_moroes.cpp
index c78c7fa7c..13778decd 100644
--- a/src/server/scripts/EasternKingdoms/Karazhan/boss_moroes.cpp
+++ b/src/server/scripts/EasternKingdoms/Karazhan/boss_moroes.cpp
@@ -121,8 +121,6 @@ struct boss_moroes : public BossAI
context.Repeat(5s);
}).Schedule(1min, 2min, GROUP_PRECOMBAT_TALK, [this](TaskContext context)
{
- //this was not scheduled in the previous commit
- //does this have to be removed?
Talk(SAY_OUT_OF_COMBAT);
context.Repeat(1min, 2min);
});
diff --git a/src/server/scripts/EasternKingdoms/Karazhan/boss_netherspite.cpp b/src/server/scripts/EasternKingdoms/Karazhan/boss_netherspite.cpp
index 9625e2303..a86c05a0c 100644
--- a/src/server/scripts/EasternKingdoms/Karazhan/boss_netherspite.cpp
+++ b/src/server/scripts/EasternKingdoms/Karazhan/boss_netherspite.cpp
@@ -15,13 +15,6 @@
* with this program. If not, see .
*/
-/* ScriptData
-SDName: Boss_Netherspite
-SD%Complete: 90
-SDComment: Not sure about timing and portals placing
-SDCategory: Karazhan
-EndScriptData */
-
#include "Player.h"
#include "ScriptMgr.h"
#include "ScriptedCreature.h"
@@ -29,19 +22,35 @@ EndScriptData */
#include "SpellAuraEffects.h"
#include "SpellScript.h"
-enum Netherspite
+enum Emotes
{
- EMOTE_PHASE_PORTAL = 0,
- EMOTE_PHASE_BANISH = 1,
+ EMOTE_PHASE_PORTAL = 0,
+ EMOTE_PHASE_BANISH = 1
+};
- SPELL_NETHERBURN_AURA = 30522,
- SPELL_VOIDZONE = 37063,
- SPELL_NETHER_INFUSION = 38688,
- SPELL_NETHERBREATH = 38523,
- SPELL_BANISH_VISUAL = 39833,
- SPELL_BANISH_ROOT = 42716,
- SPELL_EMPOWERMENT = 38549,
- SPELL_NETHERSPITE_ROAR = 38684,
+enum Spells
+{
+ SPELL_NETHERBURN_AURA = 30522,
+ SPELL_VOIDZONE = 37063,
+ SPELL_NETHER_INFUSION = 38688,
+ SPELL_NETHERBREATH = 38523,
+ SPELL_BANISH_VISUAL = 39833,
+ SPELL_BANISH_ROOT = 42716,
+ SPELL_EMPOWERMENT = 38549,
+ SPELL_NETHERSPITE_ROAR = 38684
+};
+
+enum Portals
+{
+ RED_PORTAL = 0, // Perseverence
+ GREEN_PORTAL = 1, // Serenity
+ BLUE_PORTAL = 2 // Dominance
+};
+
+enum Groups
+{
+ PORTAL_PHASE = 0,
+ VANISH_PHASE = 1
};
const float PortalCoord[3][3] =
@@ -51,302 +60,255 @@ const float PortalCoord[3][3] =
{-11094.493164f, -1591.969238f, 279.949188f} // Back side
};
-enum Netherspite_Portal
-{
- RED_PORTAL = 0, // Perseverence
- GREEN_PORTAL = 1, // Serenity
- BLUE_PORTAL = 2 // Dominance
-};
-
-const uint32 PortalID[3] = {17369, 17367, 17368};
+const uint32 PortalID[3] = {17369, 17367, 17368};
const uint32 PortalVisual[3] = {30487, 30490, 30491};
-const uint32 PortalBeam[3] = {30465, 30464, 30463};
-const uint32 PlayerBuff[3] = {30421, 30422, 30423};
-const uint32 NetherBuff[3] = {30466, 30467, 30468};
+const uint32 PortalBeam[3] = {30465, 30464, 30463};
+const uint32 PlayerBuff[3] = {30421, 30422, 30423};
+const uint32 NetherBuff[3] = {30466, 30467, 30468};
const uint32 PlayerDebuff[3] = {38637, 38638, 38639};
-class boss_netherspite : public CreatureScript
+struct boss_netherspite : public BossAI
{
-public:
- boss_netherspite() : CreatureScript("boss_netherspite") { }
+ boss_netherspite(Creature* creature) : BossAI(creature, DATA_NETHERSPITE) {}
- CreatureAI* GetAI(Creature* creature) const override
+ bool IsBetween(WorldObject* u1, WorldObject* target, WorldObject* u2) // the in-line checker
{
- return GetKarazhanAI(creature);
+ if (!u1 || !u2 || !target)
+ return false;
+
+ float xn, yn, xp, yp, xh, yh;
+ xn = u1->GetPositionX();
+ yn = u1->GetPositionY();
+ xp = u2->GetPositionX();
+ yp = u2->GetPositionY();
+ xh = target->GetPositionX();
+ yh = target->GetPositionY();
+
+ // check if target is between (not checking distance from the beam yet)
+ if (dist(xn, yn, xh, yh) >= dist(xn, yn, xp, yp) || dist(xp, yp, xh, yh) >= dist(xn, yn, xp, yp))
+ return false;
+ // check distance from the beam
+ return (std::abs((xn - xp) * yh + (yp - yn) * xh - xn * yp + xp * yn) / dist(xn, yn, xp, yp) < 1.5f);
}
- struct boss_netherspiteAI : public ScriptedAI
+ float dist(float xa, float ya, float xb, float yb) // auxiliary method for distance
{
- boss_netherspiteAI(Creature* creature) : ScriptedAI(creature)
+ return std::sqrt((xa - xb) * (xa - xb) + (ya - yb) * (ya - yb));
+ }
+
+ void Reset() override
+ {
+ BossAI::Reset();
+ berserk = false;
+ HandleDoors(true);
+ DestroyPortals();
+ }
+
+ void SummonPortals()
+ {
+ uint8 r = rand() % 4;
+ uint8 pos[3];
+ pos[RED_PORTAL] = ((r % 2) ? (r > 1 ? 2 : 1) : 0);
+ pos[GREEN_PORTAL] = ((r % 2) ? 0 : (r > 1 ? 2 : 1));
+ pos[BLUE_PORTAL] = (r > 1 ? 1 : 2); // Blue Portal not on the left side (0)
+ for (int i = 0; i < 3; ++i)
{
- instance = creature->GetInstanceScript();
- }
-
- InstanceScript* instance;
-
- bool PortalPhase;
- bool Berserk;
- uint32 PhaseTimer; // timer for phase switching
- uint32 VoidZoneTimer;
- uint32 NetherInfusionTimer; // berserking timer
- uint32 NetherbreathTimer;
- uint32 EmpowermentTimer;
- uint32 PortalTimer; // timer for beam checking
- ObjectGuid PortalGUID[3]; // guid's of portals
- ObjectGuid BeamerGUID[3]; // guid's of auxiliary beaming portals
- ObjectGuid BeamTarget[3]; // guid's of portals' current targets
-
- bool IsBetween(WorldObject* u1, WorldObject* target, WorldObject* u2) // the in-line checker
- {
- if (!u1 || !u2 || !target)
- return false;
-
- float xn, yn, xp, yp, xh, yh;
- xn = u1->GetPositionX();
- yn = u1->GetPositionY();
- xp = u2->GetPositionX();
- yp = u2->GetPositionY();
- xh = target->GetPositionX();
- yh = target->GetPositionY();
-
- // check if target is between (not checking distance from the beam yet)
- if (dist(xn, yn, xh, yh) >= dist(xn, yn, xp, yp) || dist(xp, yp, xh, yh) >= dist(xn, yn, xp, yp))
- return false;
- // check distance from the beam
- return (std::abs((xn - xp) * yh + (yp - yn) * xh - xn * yp + xp * yn) / dist(xn, yn, xp, yp) < 1.5f);
- }
-
- float dist(float xa, float ya, float xb, float yb) // auxiliary method for distance
- {
- return std::sqrt((xa - xb) * (xa - xb) + (ya - yb) * (ya - yb));
- }
-
- void Reset() override
- {
- Berserk = false;
- NetherInfusionTimer = 540000;
- VoidZoneTimer = 15000;
- NetherbreathTimer = 3000;
-
- HandleDoors(true);
- DestroyPortals();
- }
-
- void SummonPortals()
- {
- uint8 r = rand() % 4;
- uint8 pos[3];
- pos[RED_PORTAL] = ((r % 2) ? (r > 1 ? 2 : 1) : 0);
- pos[GREEN_PORTAL] = ((r % 2) ? 0 : (r > 1 ? 2 : 1));
- pos[BLUE_PORTAL] = (r > 1 ? 1 : 2); // Blue Portal not on the left side (0)
-
- for (int i = 0; i < 3; ++i)
- if (Creature* portal = me->SummonCreature(PortalID[i], PortalCoord[pos[i]][0], PortalCoord[pos[i]][1], PortalCoord[pos[i]][2], 0, TEMPSUMMON_TIMED_DESPAWN, 60000))
- {
- PortalGUID[i] = portal->GetGUID();
- portal->AddAura(PortalVisual[i], portal);
- }
- }
-
- void DestroyPortals()
- {
- for (int i = 0; i < 3; ++i)
+ if (Creature* portal = me->SummonCreature(PortalID[i], PortalCoord[pos[i]][0], PortalCoord[pos[i]][1], PortalCoord[pos[i]][2], 0, TEMPSUMMON_TIMED_DESPAWN, 60000))
{
- if (Creature* portal = ObjectAccessor::GetCreature(*me, PortalGUID[i]))
- portal->DisappearAndDie();
- if (Creature* portal = ObjectAccessor::GetCreature(*me, BeamerGUID[i]))
- portal->DisappearAndDie();
- PortalGUID[i].Clear();
- BeamTarget[i].Clear();
+ PortalGUID[i] = portal->GetGUID();
+ portal->AddAura(PortalVisual[i], portal);
}
}
+ }
- void UpdatePortals() // Here we handle the beams' behavior
+ void DestroyPortals()
+ {
+ for (int i = 0; i < 3; ++i)
{
- for (int j = 0; j < 3; ++j) // j = color
- if (Creature* portal = ObjectAccessor::GetCreature(*me, PortalGUID[j]))
+ if (Creature* portal = ObjectAccessor::GetCreature(*me, PortalGUID[i]))
+ {
+ portal->DisappearAndDie();
+ }
+ if (Creature* portal = ObjectAccessor::GetCreature(*me, BeamerGUID[i]))
+ {
+ portal->DisappearAndDie();
+ }
+ PortalGUID[i].Clear();
+ BeamTarget[i].Clear();
+ }
+ }
+
+ void UpdatePortals() // Here we handle the beams' behavior
+ {
+ for (int j = 0; j < 3; ++j) // j = color
+ {
+ if (Creature* portal = ObjectAccessor::GetCreature(*me, PortalGUID[j]))
+ {
+ // the one who's been cast upon before
+ Unit* current = ObjectAccessor::GetUnit(*portal, BeamTarget[j]);
+ // temporary store for the best suitable beam reciever
+ Unit* target = me;
+
+ if (Map* map = me->GetMap())
{
- // the one who's been cast upon before
- Unit* current = ObjectAccessor::GetUnit(*portal, BeamTarget[j]);
- // temporary store for the best suitable beam reciever
- Unit* target = me;
+ Map::PlayerList const& players = map->GetPlayers();
- if (Map* map = me->GetMap())
+ // get the best suitable target
+ for (Map::PlayerList::const_iterator i = players.begin(); i != players.end(); ++i)
{
- Map::PlayerList const& players = map->GetPlayers();
-
- // get the best suitable target
- for (Map::PlayerList::const_iterator i = players.begin(); i != players.end(); ++i)
- {
- Player* p = i->GetSource();
- if (p && p->IsAlive() // alive
- && (!target || target->GetDistance2d(portal) > p->GetDistance2d(portal)) // closer than current best
- && !p->HasAura(PlayerDebuff[j]) // not exhausted
- && !p->HasAura(PlayerBuff[(j + 1) % 3]) // not on another beam
- && !p->HasAura(PlayerBuff[(j + 2) % 3])
- && IsBetween(me, p, portal)) // on the beam
- target = p;
- }
+ Player* p = i->GetSource();
+ if (p && p->IsAlive() // alive
+ && (!target || target->GetDistance2d(portal) > p->GetDistance2d(portal)) // closer than current best
+ && !p->HasAura(PlayerDebuff[j]) // not exhausted
+ && !p->HasAura(PlayerBuff[(j + 1) % 3]) // not on another beam
+ && !p->HasAura(PlayerBuff[(j + 2) % 3])
+ && IsBetween(me, p, portal)) // on the beam
+ target = p;
}
- // buff the target
- if (target->GetTypeId() == TYPEID_PLAYER)
- target->AddAura(PlayerBuff[j], target);
- else
- target->AddAura(NetherBuff[j], target);
- // cast visual beam on the chosen target if switched
- // simple target switching isn't working -> using BeamerGUID to cast (workaround)
- if (!current || target != current)
- {
- BeamTarget[j] = target->GetGUID();
- // remove currently beaming portal
- if (Creature* beamer = ObjectAccessor::GetCreature(*portal, BeamerGUID[j]))
- {
- beamer->CastSpell(target, PortalBeam[j], false);
- beamer->DisappearAndDie();
- BeamerGUID[j].Clear();
- }
- // create new one and start beaming on the target
- if (Creature* beamer = portal->SummonCreature(PortalID[j], portal->GetPositionX(), portal->GetPositionY(), portal->GetPositionZ(), portal->GetOrientation(), TEMPSUMMON_TIMED_DESPAWN, 60000))
- {
- beamer->CastSpell(target, PortalBeam[j], false);
- BeamerGUID[j] = beamer->GetGUID();
- }
- }
- // aggro target if Red Beam
- if (j == RED_PORTAL && me->GetVictim() != target && target->GetTypeId() == TYPEID_PLAYER)
- me->GetThreatMgr().AddThreat(target, 100000.0f + DoGetThreat(me->GetVictim()));
}
+ // buff the target
+ if (target->GetTypeId() == TYPEID_PLAYER)
+ {
+ target->AddAura(PlayerBuff[j], target);
+ }
+ else
+ {
+ target->AddAura(NetherBuff[j], target);
+ }
+ // cast visual beam on the chosen target if switched
+ // simple target switching isn't working -> using BeamerGUID to cast (workaround)
+ if (!current || target != current)
+ {
+ BeamTarget[j] = target->GetGUID();
+ // remove currently beaming portal
+ if (Creature* beamer = ObjectAccessor::GetCreature(*portal, BeamerGUID[j]))
+ {
+ beamer->CastSpell(target, PortalBeam[j], false);
+ beamer->DisappearAndDie();
+ BeamerGUID[j].Clear();
+ }
+ // create new one and start beaming on the target
+ if (Creature* beamer = portal->SummonCreature(PortalID[j], portal->GetPositionX(), portal->GetPositionY(), portal->GetPositionZ(), portal->GetOrientation(), TEMPSUMMON_TIMED_DESPAWN, 60000))
+ {
+ beamer->CastSpell(target, PortalBeam[j], false);
+ BeamerGUID[j] = beamer->GetGUID();
+ }
+ }
+ // aggro target if Red Beam
+ if (j == RED_PORTAL && me->GetVictim() != target && target->GetTypeId() == TYPEID_PLAYER)
+ {
+ me->GetThreatMgr().AddThreat(target, 100000.0f + DoGetThreat(me->GetVictim()));
+ }
+ }
}
+ }
- void SwitchToPortalPhase()
+ void SwitchToPortalPhase()
+ {
+ scheduler.CancelGroup(VANISH_PHASE);
+ me->RemoveAurasDueToSpell(SPELL_BANISH_ROOT);
+ me->RemoveAurasDueToSpell(SPELL_BANISH_VISUAL);
+ SummonPortals();
+ scheduler.Schedule(60s, [this](TaskContext /*context*/)
{
- me->RemoveAurasDueToSpell(SPELL_BANISH_ROOT);
- me->RemoveAurasDueToSpell(SPELL_BANISH_VISUAL);
- SummonPortals();
- PhaseTimer = 60000;
- PortalPhase = true;
- PortalTimer = 10000;
- EmpowermentTimer = 10000;
- Talk(EMOTE_PHASE_PORTAL);
- }
-
- void SwitchToBanishPhase()
- {
- me->RemoveAurasDueToSpell(SPELL_EMPOWERMENT);
- me->RemoveAurasDueToSpell(SPELL_NETHERBURN_AURA);
- DoCast(me, SPELL_BANISH_VISUAL, true);
- DoCast(me, SPELL_BANISH_ROOT, true);
- DestroyPortals();
- PhaseTimer = 30000;
- PortalPhase = false;
- Talk(EMOTE_PHASE_BANISH);
-
- for (uint8 i = 0; i < 3; ++i)
- me->RemoveAurasDueToSpell(NetherBuff[i]);
- }
-
- void HandleDoors(bool open) // Massive Door switcher
- {
- if (GameObject* Door = ObjectAccessor::GetGameObject(*me, instance->GetGuidData(DATA_GO_MASSIVE_DOOR) ))
- Door->SetGoState(open ? GO_STATE_ACTIVE : GO_STATE_READY);
- }
-
- void JustEngagedWith(Unit* /*who*/) override
- {
- HandleDoors(false);
- SwitchToPortalPhase();
- DoZoneInCombat();
- }
-
- void JustDied(Unit* /*killer*/) override
- {
- HandleDoors(true);
- DestroyPortals();
- }
-
- void UpdateAI(uint32 diff) override
- {
- if (!UpdateVictim())
+ if (!me->IsNonMeleeSpellCast(false))
+ {
+ SwitchToBanishPhase();
return;
-
- // Void Zone
- if (VoidZoneTimer <= diff)
- {
- DoCast(SelectTarget(SelectTargetMethod::Random, 1, 45, true), SPELL_VOIDZONE, true);
- VoidZoneTimer = 15000;
}
- else
- VoidZoneTimer -= diff;
+ }).Schedule(10s, PORTAL_PHASE, [this](TaskContext context)
+ {
+ UpdatePortals();
+ context.Repeat(1s);
+ }).Schedule(10s, PORTAL_PHASE, [this](TaskContext context)
+ {
+ DoCastSelf(SPELL_EMPOWERMENT);
+ me->AddAura(SPELL_NETHERBURN_AURA, me);
+ context.Repeat(90s);
+ });
+ Talk(EMOTE_PHASE_PORTAL);
+ }
- // NetherInfusion Berserk
- if (!Berserk && NetherInfusionTimer <= diff)
+ void SwitchToBanishPhase()
+ {
+ scheduler.CancelGroup(PORTAL_PHASE);
+ me->RemoveAurasDueToSpell(SPELL_EMPOWERMENT);
+ me->RemoveAurasDueToSpell(SPELL_NETHERBURN_AURA);
+ DoCastSelf(SPELL_BANISH_VISUAL, true);
+ DoCastSelf(SPELL_BANISH_ROOT, true);
+ DestroyPortals();
+ scheduler.Schedule(30s, [this](TaskContext /*context*/)
+ {
+ if (!me->IsNonMeleeSpellCast(false))
{
- me->AddAura(SPELL_NETHER_INFUSION, me);
- DoCast(me, SPELL_NETHERSPITE_ROAR);
- Berserk = true;
+ SwitchToPortalPhase();
+ return;
}
- else
- NetherInfusionTimer -= diff;
-
- if (PortalPhase) // PORTAL PHASE
- {
- // Distribute beams and buffs
- if (PortalTimer <= diff)
- {
- UpdatePortals();
- PortalTimer = 1000;
- }
- else
- PortalTimer -= diff;
-
- // Empowerment & Nether Burn
- if (EmpowermentTimer <= diff)
- {
- DoCast(me, SPELL_EMPOWERMENT);
- me->AddAura(SPELL_NETHERBURN_AURA, me);
- EmpowermentTimer = 90000;
- }
- else
- EmpowermentTimer -= diff;
-
- if (PhaseTimer <= diff)
- {
- if (!me->IsNonMeleeSpellCast(false))
- {
- SwitchToBanishPhase();
- return;
- }
- }
- else
- PhaseTimer -= diff;
- }
- else // BANISH PHASE
- {
- // Netherbreath
- if (NetherbreathTimer <= diff)
- {
- if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 40, true))
- DoCast(target, SPELL_NETHERBREATH);
- NetherbreathTimer = urand(5000, 7000);
- }
- else
- NetherbreathTimer -= diff;
-
- if (PhaseTimer <= diff)
- {
- if (!me->IsNonMeleeSpellCast(false))
- {
- SwitchToPortalPhase();
- return;
- }
- }
- else
- PhaseTimer -= diff;
- }
-
- DoMeleeAttackIfReady();
+ }).Schedule(10s, VANISH_PHASE, [this](TaskContext context)
+ {
+ DoCastRandomTarget(SPELL_NETHERBREATH, 0, 40.0f, true);
+ context.Repeat(5s, 7s);
+ });
+ Talk(EMOTE_PHASE_BANISH);
+ for (uint8 i = 0; i < 3; ++i)
+ {
+ me->RemoveAurasDueToSpell(NetherBuff[i]);
}
- };
+ }
+
+ void HandleDoors(bool open)
+ {
+ if (GameObject* door = ObjectAccessor::GetGameObject(*me, instance->GetGuidData(DATA_GO_MASSIVE_DOOR)))
+ {
+ door->SetGoState(open ? GO_STATE_ACTIVE : GO_STATE_READY);
+ }
+ }
+
+ void JustEngagedWith(Unit* who) override
+ {
+ BossAI::JustEngagedWith(who);
+ HandleDoors(false);
+ SwitchToPortalPhase();
+ DoZoneInCombat();
+ scheduler.Schedule(15s, [this](TaskContext context)
+ {
+ DoCastRandomTarget(SPELL_VOIDZONE, 1, 45.0f, true, true);
+ context.Repeat(15s);
+ }).Schedule(9min, [this](TaskContext /*context*/)
+ {
+ if (!berserk)
+ {
+ DoCastSelf(SPELL_NETHER_INFUSION);
+ DoCastAOE(SPELL_NETHERSPITE_ROAR);
+ berserk = true;
+ }
+ });
+ }
+
+ void JustDied(Unit* killer) override
+ {
+ BossAI::JustDied(killer);
+ HandleDoors(true);
+ DestroyPortals();
+ }
+
+ void UpdateAI(uint32 diff) override
+ {
+ if (!UpdateVictim())
+ return;
+
+ scheduler.Update(diff);
+ if (me->HasUnitState(UNIT_STATE_CASTING))
+ return;
+
+ DoMeleeAttackIfReady();
+ }
+
+private:
+ bool berserk;
+ ObjectGuid PortalGUID[3]; // guid's of portals
+ ObjectGuid BeamerGUID[3]; // guid's of auxiliary beaming portals
+ ObjectGuid BeamTarget[3]; // guid's of portals' current targets
};
class spell_nether_portal_perseverence : public AuraScript
@@ -366,6 +328,6 @@ class spell_nether_portal_perseverence : public AuraScript
void AddSC_boss_netherspite()
{
- new boss_netherspite();
+ RegisterKarazhanCreatureAI(boss_netherspite);
RegisterSpellScript(spell_nether_portal_perseverence);
}