From 750e0b4c23881c584df7d154800e937cd62f06eb Mon Sep 17 00:00:00 2001 From: Eddy Vega <61223313+Si1ker@users.noreply.github.com> Date: Thu, 27 Jul 2023 06:03:19 -0600 Subject: [PATCH] refactor(Scripts/Karazhan): Update Netherspite (#16756) * init * . * . * review * . * Remove whitespace at the end of the lines * . * . --- .../EasternKingdoms/Karazhan/boss_moroes.cpp | 2 - .../Karazhan/boss_netherspite.cpp | 534 ++++++++---------- 2 files changed, 248 insertions(+), 288 deletions(-) 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); }