EverWrath/src/server/scripts/Northrend/UtgardeKeep/UtgardePinnacle/boss_svala.cpp
Benjamin Jackson 1edac37ac3
refactor(Core): Make more use of helpers. (#19835)
* Init.

* Reword.

* Update codestyle script.

Co-Authored-By: Kitzunu <24550914+Kitzunu@users.noreply.github.com>

* Add gameobject type ID check, reorder checks.

* Add helper/codestyle check for unit type.

* `IsUnit()` -> `IsCreature()`

* Add `IsUnit()` method.

* Use type mask.

https: //github.com/TrinityCore/TrinityCore/commit/cc71da35b5dc74abf71f8691161525a23d870bb5
Co-Authored-By: Giacomo Pozzoni <giacomopoz@gmail.com>
Co-Authored-By: Ovahlord <18347559+Ovahlord@users.noreply.github.com>

* Replace instances of `isType` with `IsUnit`.

---------

Co-authored-by: Kitzunu <24550914+Kitzunu@users.noreply.github.com>
Co-authored-by: Giacomo Pozzoni <giacomopoz@gmail.com>
Co-authored-by: Ovahlord <18347559+Ovahlord@users.noreply.github.com>
2024-09-03 14:41:31 -03:00

441 lines
16 KiB
C++

/*
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by the
* Free Software Foundation; either version 3 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "CreatureScript.h"
#include "PassiveAI.h"
#include "Player.h"
#include "ScriptedCreature.h"
#include "SpellScript.h"
#include "SpellScriptLoader.h"
#include "utgarde_pinnacle.h"
enum Misc
{
// SAY
TALK_INTRO_A1 = 0,
TALK_INTRO_A2 = 1,
TALK_INTRO_S1 = 0,
TALK_INTRO_S2 = 0,
TALK_INTRO_S3 = 1,
SAY_AGGRO = 2,
SAY_SLAY = 3,
SAY_DEATH = 4,
SAY_SACRIFICE_PLAYER = 5,
// SPELLS
// INTRO
SPELL_ARTHAS_TRANSFORMING_SVALA = 54142,
SPELL_SVALA_TRANSFORMING1 = 54205,
SPELL_SVALA_TRANSFORMING2 = 54140,
// SORROWGRAVE
SPELL_CALL_FLAMES = 48258,
SPELL_BALL_OF_FLAME = 48246,
SPELL_RITUAL_OF_THE_SWORD = 48276,
SPELL_RITUAL_STRIKE = 48331,
SPELL_SINSTER_STRIKE_N = 15667,
SPELL_SINSTER_STRIKE_H = 59409,
EQUIP_SWORD = 40343,
// CHANNELERS
SPELL_PARALYZE = 48278,
SPELL_SHADOWS_IN_THE_DARK = 59407,
SPELL_TELEPORT_VISUAL = 64446,
// NPCS
NPC_RITUAL_CHANNELER = 27281,
NPC_ARTHAS = 29280,
NPC_FLAME_BRAZIER = 27273,
};
enum Events
{
// BASE EVENT START
EVENT_SVALA_START = 1,
EVENT_SVALA_TALK1 = 2,
EVENT_SVALA_TALK2 = 3,
EVENT_SVALA_TALK3 = 4,
EVENT_SVALA_TALK4 = 5,
EVENT_SVALA_TALK5 = 6,
EVENT_SVALA_TALK6 = 7,
EVENT_SVALA_TALK7 = 8,
EVENT_SVALA_TALK8 = 9,
EVENT_SVALA_TALK9 = 20,
// FIGHT
EVENT_SORROWGRAVE_SS = 10,
EVENT_SORROWGRAVE_FLAMES = 11,
EVENT_SORROWGRAVE_FLAMES2 = 12,
EVENT_SORROWGRAVE_RITUAL = 13,
EVENT_SORROWGRAVE_RITUAL_SPELLS = 14,
EVENT_SORROWGRAVE_FINISH_RITUAL = 15,
};
const Position RitualChannelerLoc[3] =
{
{296.42f, -355.01f, 90.94f, 0.0f},
{302.36f, -352.01f, 90.54f, 0.0f},
{291.39f, -350.89f, 90.54f, 0.0f}
};
/*######
## Boss Svala
######*/
class boss_svala : public CreatureScript
{
public:
boss_svala() : CreatureScript("boss_svala") { }
CreatureAI* GetAI(Creature* creature) const override
{
return GetUtgardePinnacleAI<boss_svalaAI>(creature);
}
struct boss_svalaAI : public ScriptedAI
{
boss_svalaAI(Creature* creature) : ScriptedAI(creature), summons(me)
{
instance = creature->GetInstanceScript();
Started = false;
ArthasGUID.Clear();
}
ObjectGuid ArthasGUID;
bool Started;
InstanceScript* instance;
EventMap events;
EventMap events2;
SummonList summons;
void Reset() override
{
if (instance)
{
instance->SetData(DATA_SVALA_SORROWGRAVE, NOT_STARTED);
instance->SetData(DATA_SVALA_ACHIEVEMENT, false);
}
summons.DespawnAll();
events.Reset();
events2.Reset();
if (!Started)
me->SetImmuneToAll(true);
else
{
me->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
me->SetImmuneToAll(false);
me->SetHover(true);
}
}
void EnterEvadeMode(EvadeReason why) override
{
me->SetControlled(false, UNIT_STATE_ROOT);
ScriptedAI::EnterEvadeMode(why);
}
void SetData(uint32 data, uint32 param) override
{
if (data != 1 || param != 1 || Started || (instance && instance->GetData(DATA_SVALA_SORROWGRAVE) == DONE))
return;
me->SetImmuneToAll(true);
Started = true;
me->setActive(true);
events2.ScheduleEvent(EVENT_SVALA_START, 5000);
if (Creature* pArthas = me->SummonCreature(NPC_ARTHAS, 295.81f, -366.16f, 92.57f, 1.58f, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 59000))
ArthasGUID = pArthas->GetGUID();
if (instance)
{
instance->SetData(DATA_SVALA_SORROWGRAVE, IN_PROGRESS);
if (GameObject* mirror = ObjectAccessor::GetGameObject(*me, instance->GetGuidData(GO_SVALA_MIRROR)))
mirror->SetGoState(GO_STATE_READY);
}
}
void JustSummoned(Creature* summon) override
{
summons.Summon(summon);
if (summon->GetEntry() == NPC_RITUAL_CHANNELER)
summon->CastSpell(summon, SPELL_TELEPORT_VISUAL, true);
}
void JustEngagedWith(Unit*) override
{
me->SetInCombatWithZone();
Talk(SAY_AGGRO);
events.ScheduleEvent(EVENT_SORROWGRAVE_SS, 3s);
events.ScheduleEvent(EVENT_SORROWGRAVE_FLAMES, 11s);
events.ScheduleEvent(EVENT_SORROWGRAVE_RITUAL, 25s);
if (instance)
instance->SetData(DATA_SVALA_SORROWGRAVE, IN_PROGRESS);
}
void JustDied(Unit*) override
{
summons.DespawnAll();
Talk(SAY_DEATH);
if(instance)
instance->SetData(DATA_SVALA_SORROWGRAVE, DONE);
}
void KilledUnit(Unit* victim) override
{
if (victim->GetEntry() == NPC_SCOURGE_HULK && instance)
{
instance->SetData(DATA_SVALA_ACHIEVEMENT, true);
instance->DoUpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_KILL_CREATURE, 26555, 1, nullptr);
}
if (victim->IsPlayer())
Talk(SAY_SLAY);
}
void UpdateAI(uint32 diff) override
{
events2.Update(diff);
switch (events2.ExecuteEvent())
{
case EVENT_SVALA_START:
Talk(TALK_INTRO_S1);
events2.ScheduleEvent(EVENT_SVALA_TALK1, 8s);
break;
case EVENT_SVALA_TALK1:
if (Creature* Arthas = ObjectAccessor::GetCreature(*me, ArthasGUID))
Arthas->AI()->Talk(TALK_INTRO_A1);
events2.ScheduleEvent(EVENT_SVALA_TALK2, 9s);
break;
case EVENT_SVALA_TALK2:
if (Creature* Arthas = ObjectAccessor::GetCreature(*me, ArthasGUID))
Arthas->CastSpell(me, SPELL_ARTHAS_TRANSFORMING_SVALA, false);
me->CastSpell(me, SPELL_SVALA_TRANSFORMING2, true);
events2.ScheduleEvent(EVENT_SVALA_TALK3, 3s);
break;
case EVENT_SVALA_TALK3:
me->SetFloatValue(UNIT_FIELD_HOVERHEIGHT, 6.0f);
me->SetHover(true);
me->AddUnitState(UNIT_STATE_NO_ENVIRONMENT_UPD);
events2.ScheduleEvent(30, 1s);
events2.ScheduleEvent(EVENT_SVALA_TALK4, 9s);
break;
case 30:
{
WorldPacket data(SMSG_SPLINE_MOVE_SET_HOVER, 9);
data << me->GetPackGUID();
me->SendMessageToSet(&data, false);
break;
}
case EVENT_SVALA_TALK4:
{
me->CastSpell(me, SPELL_SVALA_TRANSFORMING1, true);
me->UpdateEntry(NPC_SVALA_SORROWGRAVE);
me->SetCorpseDelay(sWorld->getIntConfig(CONFIG_CORPSE_DECAY_ELITE));
me->SetFloatValue(UNIT_FIELD_HOVERHEIGHT, 6.0f);
me->SetImmuneToAll(true);
if (Creature* Arthas = ObjectAccessor::GetCreature(*me, ArthasGUID))
Arthas->InterruptNonMeleeSpells(false);
me->RemoveAllAuras();
me->SetWalk(false);
events2.ScheduleEvent(EVENT_SVALA_TALK5, 2s);
std::list<Creature*> creatureList;
me->GetCreaturesWithEntryInRange(creatureList, 100.0f, NPC_DRAGONFLAYER_SPECTATOR);
for (std::list<Creature*>::const_iterator itr = creatureList.begin(); itr != creatureList.end(); ++itr)
(*itr)->AI()->SetData(1, 2);
break;
}
case EVENT_SVALA_TALK5:
Talk(TALK_INTRO_S2);
events2.ScheduleEvent(EVENT_SVALA_TALK6, 12s);
break;
case EVENT_SVALA_TALK6:
if (Creature* Arthas = ObjectAccessor::GetCreature(*me, ArthasGUID))
Arthas->AI()->Talk(TALK_INTRO_A2);
events2.ScheduleEvent(EVENT_SVALA_TALK7, 9s);
break;
case EVENT_SVALA_TALK7:
me->SetFacingTo(M_PI / 2.0f);
Talk(TALK_INTRO_S3);
if (GameObject* mirror = ObjectAccessor::GetGameObject(*me, instance->GetGuidData(GO_SVALA_MIRROR)))
mirror->SetGoState(GO_STATE_ACTIVE);
events2.ScheduleEvent(EVENT_SVALA_TALK8, 13s);
break;
case EVENT_SVALA_TALK8:
me->GetMotionMaster()->MoveFall(0, true);
events2.ScheduleEvent(EVENT_SVALA_TALK9, 2s);
break;
case EVENT_SVALA_TALK9:
me->SetFloatValue(UNIT_FIELD_HOVERHEIGHT, 3.0f);
me->SetImmuneToAll(false);
me->LoadEquipment(1, true);
me->setActive(false);
if (Player* target = SelectTargetFromPlayerList(100.0f))
AttackStart(target);
return;
}
if (!UpdateVictim())
return;
events.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
switch (events.ExecuteEvent())
{
case EVENT_SORROWGRAVE_SS:
me->CastSpell(me->GetVictim(), IsHeroic() ? SPELL_SINSTER_STRIKE_H : SPELL_SINSTER_STRIKE_N, false);
events.ScheduleEvent(EVENT_SORROWGRAVE_SS, 3s, 5s);
break;
case EVENT_SORROWGRAVE_FLAMES:
summons.DespawnAll();
me->CastSpell(me, SPELL_CALL_FLAMES, false);
events.ScheduleEvent(EVENT_SORROWGRAVE_FLAMES2, 500ms);
events.ScheduleEvent(EVENT_SORROWGRAVE_FLAMES2, 1s);
events.ScheduleEvent(EVENT_SORROWGRAVE_FLAMES, 8s, 12s);
break;
case EVENT_SORROWGRAVE_FLAMES2:
{
std::list<Creature*> braziers;
me->GetCreaturesWithEntryInRange(braziers, 100.0f, NPC_FLAME_BRAZIER);
if (!braziers.empty())
{
for (std::list<Creature*>::const_iterator itr = braziers.begin(); itr != braziers.end(); ++itr)
(*itr)->CastCustomSpell(SPELL_BALL_OF_FLAME, SPELLVALUE_MAX_TARGETS, 1, (*itr), true);
}
break;
}
case EVENT_SORROWGRAVE_RITUAL:
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 0.0f, true))
{
Talk(SAY_SACRIFICE_PLAYER);
for (uint8 i = 0; i < 3; ++i)
if (Creature* cr = me->SummonCreature(NPC_RITUAL_CHANNELER, RitualChannelerLoc[i], TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 360000))
cr->AI()->AttackStart(target);
me->GetMotionMaster()->MoveIdle();
DoTeleportPlayer(target, 296.632f, -346.075f, 90.63f, 4.6f);
me->NearTeleportTo(296.632f, -346.075f, 110.0f, 4.6f, false);
me->SetControlled(true, UNIT_STATE_ROOT);
me->RemoveAurasByType(SPELL_AURA_PERIODIC_DAMAGE);
me->RemoveAurasByType(SPELL_AURA_PERIODIC_DAMAGE_PERCENT);
me->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
}
events.DelayEvents(25001); // +1 just to be sure
events.ScheduleEvent(EVENT_SORROWGRAVE_RITUAL_SPELLS, 0ms);
events.ScheduleEvent(EVENT_SORROWGRAVE_FINISH_RITUAL, 25s);
return;
case EVENT_SORROWGRAVE_RITUAL_SPELLS:
//me->CastSpell(me, SPELL_RITUAL_OF_THE_SWORD, false);
me->CastSpell(me, SPELL_RITUAL_STRIKE, true);
return;
case EVENT_SORROWGRAVE_FINISH_RITUAL:
me->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
me->SetControlled(false, UNIT_STATE_ROOT);
AttackStart(me->GetVictim());
me->GetMotionMaster()->MoveFall(0, true);
summons.DespawnAll();
break;
}
DoMeleeAttackIfReady();
}
};
};
/*######
## Mob Ritual Channeler
######*/
class npc_ritual_channeler : public CreatureScript
{
public:
npc_ritual_channeler() : CreatureScript("npc_ritual_channeler") { }
CreatureAI* GetAI(Creature* pCreature) const override
{
return GetUtgardePinnacleAI<npc_ritual_channelerAI>(pCreature);
}
struct npc_ritual_channelerAI : public NullCreatureAI
{
npc_ritual_channelerAI(Creature* pCreature) : NullCreatureAI(pCreature) {}
void AttackStart(Unit* pWho) override
{
if (me->GetMap()->GetDifficulty() == DUNGEON_DIFFICULTY_HEROIC)
me->AddAura(SPELL_SHADOWS_IN_THE_DARK, me);
if (pWho)
{
me->AddThreat(pWho, 10000000.0f);
me->CastSpell(pWho, SPELL_PARALYZE, false);
}
}
};
};
class spell_svala_ritual_strike : public SpellScript
{
PrepareSpellScript(spell_svala_ritual_strike);
void HandleDummyEffect(SpellEffIndex /*effIndex*/)
{
if (Unit* unitTarget = GetHitUnit())
{
if (!unitTarget->IsCreature())
return;
Unit::DealDamage(GetCaster(), unitTarget, 7000, nullptr, DIRECT_DAMAGE);
}
}
void Register() override
{
OnEffectHitTarget += SpellEffectFn(spell_svala_ritual_strike::HandleDummyEffect, EFFECT_2, SPELL_EFFECT_DUMMY);
}
};
class spell_svala_ritual_strike_aura : public AuraScript
{
PrepareAuraScript(spell_svala_ritual_strike_aura);
void CalculateAmount(AuraEffect const* /*aurEff*/, int32& amount, bool& /*canBeRecalculated*/)
{
// Set amount based on difficulty
amount = (GetCaster()->GetMap()->IsHeroic() ? 2000 : 1000);
}
void Register() override
{
DoEffectCalcAmount += AuraEffectCalcAmountFn(spell_svala_ritual_strike_aura::CalculateAmount, EFFECT_1, SPELL_AURA_PERIODIC_DAMAGE);
}
};
void AddSC_boss_svala()
{
new boss_svala();
new npc_ritual_channeler();
RegisterSpellAndAuraScriptPair(spell_svala_ritual_strike, spell_svala_ritual_strike_aura);
}