diff options
Diffstat (limited to 'src')
4 files changed, 626 insertions, 646 deletions
diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp index 84695d84eda..bc68a92561c 100644 --- a/src/server/game/Spells/Spell.cpp +++ b/src/server/game/Spells/Spell.cpp @@ -2615,7 +2615,8 @@ SpellMissInfo Spell::DoSpellHitOnUnit(Unit* unit, uint32 effectMask) // for delayed spells ignore negative spells (after duel end) for friendly targets /// @todo this cause soul transfer bugged // 63881 - Malady of the Mind jump spell (Yogg-Saron) - if (m_spellInfo->HasHitDelay() && unit->GetTypeId() == TYPEID_PLAYER && !m_spellInfo->IsPositive() && m_spellInfo->Id != 63881) + // 45034 - Curse of Boundless Agony jump spell (Kalecgos) + if (m_spellInfo->HasHitDelay() && unit->GetTypeId() == TYPEID_PLAYER && !m_spellInfo->IsPositive() && m_spellInfo->Id != 63881 && m_spellInfo->Id != 45034) return SPELL_MISS_EVADE; // assisting case, healing and resurrection diff --git a/src/server/scripts/EasternKingdoms/SunwellPlateau/boss_kalecgos.cpp b/src/server/scripts/EasternKingdoms/SunwellPlateau/boss_kalecgos.cpp index 4911ad56a07..db30bde2134 100644 --- a/src/server/scripts/EasternKingdoms/SunwellPlateau/boss_kalecgos.cpp +++ b/src/server/scripts/EasternKingdoms/SunwellPlateau/boss_kalecgos.cpp @@ -15,810 +15,781 @@ * with this program. If not, see <http://www.gnu.org/licenses/>. */ -/* ScriptData -SDName: Boss_Kalecgos -SD%Complete: 95 -SDComment: -SDCategory: Sunwell_Plateau -EndScriptData */ - #include "ScriptMgr.h" +#include "GameObject.h" +#include "GameObjectAI.h" #include "InstanceScript.h" -#include "Log.h" -#include "Map.h" #include "MotionMaster.h" -#include "ObjectAccessor.h" #include "Player.h" #include "ScriptedCreature.h" -#include "GameObjectAI.h" -#include "GameObject.h" +#include "SpellAuraEffects.h" +#include "SpellScript.h" #include "sunwell_plateau.h" #include "TemporarySummon.h" enum Yells { - SAY_SATH_AGGRO = 0, - SAY_SATH_SLAY = 1, - SAY_SATH_DEATH = 2, - SAY_SATH_SPELL1 = 3, - SAY_SATH_SPELL2 = 4, - - SAY_EVIL_AGGRO = 0, - SAY_EVIL_SLAY = 1, - SAY_GOOD_PLRWIN = 2, - SAY_EVIL_ENRAGE = 3, - - SAY_GOOD_AGGRO = 0, - SAY_GOOD_NEAR_DEATH = 1, - SAY_GOOD_NEAR_DEATH2 = 2 + SAY_SATH_AGGRO = 0, + SAY_SATH_SLAY = 1, + SAY_SATH_DEATH = 2, + SAY_SATH_SPELL1 = 3, + SAY_SATH_SPELL2 = 4, + + SAY_EVIL_AGGRO = 0, + SAY_EVIL_SLAY = 1, + SAY_OUTRO_1 = 2, + SAY_OUTRO_2 = 3, + EMOTE_ENRAGE = 4, + SAY_ARCANE_BUFFET = 6, + + SAY_GOOD_NEAR_DEATH_0 = 0, + SAY_GOOD_NEAR_DEATH_1 = 1, + SAY_GOOD_NEAR_DEATH_2 = 2, + SAY_GOOD_DEATH = 3 }; enum Spells { - AURA_SUNWELL_RADIANCE = 45769, - AURA_SPECTRAL_EXHAUSTION = 44867, - AURA_SPECTRAL_REALM = 46021, - AURA_SPECTRAL_INVISIBILITY = 44801, - AURA_DEMONIC_VISUAL = 44800, - - SPELL_SPECTRAL_BLAST = 44869, - SPELL_TELEPORT_SPECTRAL = 46019, - SPELL_ARCANE_BUFFET = 45018, - SPELL_FROST_BREATH = 44799, - SPELL_TAIL_LASH = 45122, - - SPELL_BANISH = 136466, // Changed in MoP - Patch 5.3 for solo player. - SPELL_TRANSFORM_KALEC = 44670, - SPELL_ENRAGE = 44807, - - SPELL_CORRUPTION_STRIKE = 45029, - SPELL_AGONY_CURSE = 45032, - SPELL_SHADOW_BOLT = 45031, - - SPELL_HEROIC_STRIKE = 45026, - SPELL_REVITALIZE = 45027 + SPELL_SPECTRAL_BLAST = 44869, + SPELL_ARCANE_BUFFET = 45018, + SPELL_FROST_BREATH = 44799, + SPELL_TAIL_LASH = 45122, + SPELL_WILD_MAGIC_1 = 45001, + SPELL_WILD_MAGIC_2 = 45002, + SPELL_WILD_MAGIC_3 = 45004, + SPELL_WILD_MAGIC_4 = 45006, + SPELL_WILD_MAGIC_5 = 45010, + SPELL_WILD_MAGIC_6 = 44978, + SPELL_BANISH = 136466, // Changed in MoP - Patch 5.3 for solo player. + SPELL_ENRAGE = 44807, + SPELL_DEMONIC_VISUAL = 44800, + SPELL_CORRUPTION_STRIKE = 45029, + SPELL_AGONY_CURSE = 45032, + SPELL_SHADOW_BOLT = 45031, + SPELL_TAP_CHECK = 46732, + SPELL_TAP_CHECK_DAMAGE = 46733, + SPELL_AGONY_CURSE_VISUAL_1 = 45083, + SPELL_AGONY_CURSE_VISUAL_2 = 45084, + SPELL_AGONY_CURSE_VISUAL_3 = 45085, + SPELL_AGONY_CURSE_ALLY = 45034, + SPELL_HEROIC_STRIKE = 45026, + SPELL_REVITALIZE = 45027, + SPELL_SPECTRAL_BLAST_EFFECT = 44866, + SPELL_SPECTRAL_BLAST_VISUAL = 46648, + SPELL_SPECTRAL_REALM_TRIGGER = 44811, + SPELL_SPECTRAL_REALM_TELEPORT = 46019, + SPELL_SPECTRAL_REALM_AURA = 46021, + SPELL_SPECTRAL_REALM_2 = 44845, + SPELL_SPECTRAL_REALM_REACTION = 44852, + SPELL_SPECTRAL_EXHAUSTION = 44867, + SPELL_TELEPORT_BACK = 46020 +}; + +enum KalecgosEvents +{ + EVENT_ARCANE_BUFFET = 1, + EVENT_FROST_BREATH, + EVENT_WILD_MAGIC, + EVENT_TAIL_LASH, + EVENT_SPECTRAL_BLAST, + EVENT_CHECK_TIMER, + EVENT_OUTRO_START, + EVENT_OUTRO_1, + EVENT_OUTRO_2, + EVENT_OUTRO_3, + EVENT_REVITALIZE, + EVENT_HEROIC_STRIKE, + EVENT_SHADOWBOLT, + EVENT_AGONY_CURSE, + EVENT_CORRUPTION_STRIKE }; enum SWPActions { - DO_ENRAGE = 1, - DO_BANISH = 2 + ACTION_START_OUTRO = 1, + ACTION_ENRAGE }; -enum Misc +enum KalecSayPhases { - FLY_X = 1679, - FLY_Y = 900, - FLY_Z = 82, - CENTER_X = 1705, - CENTER_Y = 930, - RADIUS = 30, - MAX_PLAYERS_IN_SPECTRAL_REALM = 0 // over this, teleport object won't work, 0 disables check + PHASE_SAY_ONE = 1, + PHASE_SAY_TWO, + PHASE_SAY_THREE, + PHASE_SAY_FOUR, + PHASE_OUTRO }; -#define DRAGON_REALM_Z 53.079f -#define DEMON_REALM_Z -74.558f +enum KalecgosPoints +{ + POINT_OUTRO_1 = 0, + POINT_OUTRO_2 +}; -uint32 WildMagic[] = { 44978, 45001, 45002, 45004, 45006, 45010 }; +Position const KalecgosSummonPos = { 1709.094f, 927.5035f, -74.28364f, 2.932153f }; +Position const FlyPos[2] = +{ + { 1704.18f, 927.999f, 57.888f }, + { 1614.355f, 846.9694f, 119.0971f } +}; -class boss_kalecgos : public CreatureScript +uint32 const WildMagicSpells[6] = { -public: - boss_kalecgos() : CreatureScript("boss_kalecgos") { } + SPELL_WILD_MAGIC_1, + SPELL_WILD_MAGIC_2, + SPELL_WILD_MAGIC_3, + SPELL_WILD_MAGIC_4, + SPELL_WILD_MAGIC_5, + SPELL_WILD_MAGIC_6 +}; + +struct boss_kalecgos : public BossAI +{ + boss_kalecgos(Creature* creature) : BossAI(creature, DATA_KALECGOS), _isEnraged(false), _isBanished(false) { } - struct boss_kalecgosAI : public ScriptedAI + void Reset() override { - boss_kalecgosAI(Creature* creature) : ScriptedAI(creature) - { - Initialize(); - instance = creature->GetInstanceScript(); - bJustReset = false; - me->setActive(true); - } + _isEnraged = false; + _isBanished = false; + _Reset(); + events.ScheduleEvent(EVENT_ARCANE_BUFFET, Seconds(8)); + events.ScheduleEvent(EVENT_FROST_BREATH, Seconds(15)); + events.ScheduleEvent(EVENT_WILD_MAGIC, Seconds(10)); + events.ScheduleEvent(EVENT_TAIL_LASH, Seconds(25)); + events.ScheduleEvent(EVENT_SPECTRAL_BLAST, Seconds(20), Seconds(25)); + events.ScheduleEvent(EVENT_CHECK_TIMER, Seconds(1)); + } - void Initialize() - { - SathGUID.Clear(); - ArcaneBuffetTimer = 8000; - FrostBreathTimer = 15000; - WildMagicTimer = 10000; - TailLashTimer = 25000; - SpectralBlastTimer = urand(20000, 25000); - CheckTimer = 1000; - ResetTimer = 30000; - - TalkTimer = 0; - TalkSequence = 0; - isFriendly = false; - isEnraged = false; - isBanished = false; - } + void EnterEvadeMode(EvadeReason /*why*/) override + { + if (events.IsInPhase(PHASE_OUTRO) || me->HasAura(SPELL_BANISH)) + return; - InstanceScript* instance; + _EnterEvadeMode(); + instance->SendEncounterUnit(ENCOUNTER_FRAME_DISENGAGE, me); + instance->DoRemoveAurasDueToSpellOnPlayers(SPELL_SPECTRAL_REALM_AURA); + summons.DespawnAll(); + DespawnPortals(); - uint32 ArcaneBuffetTimer; - uint32 FrostBreathTimer; - uint32 WildMagicTimer; - uint32 SpectralBlastTimer; - uint32 TailLashTimer; - uint32 CheckTimer; - uint32 TalkTimer; - uint32 TalkSequence; - uint32 ResetTimer; + if (Creature* sathrovar = instance->GetCreature(DATA_SATHROVARR)) + _DespawnAtEvade(Seconds(10), sathrovar); - bool isFriendly; - bool isEnraged; - bool isBanished; - bool bJustReset; + _DespawnAtEvade(Seconds(10)); + } - ObjectGuid SathGUID; + void DespawnPortals() + { + std::vector<GameObject*> portals; + me->GetGameObjectListWithEntryInGrid(portals, GO_SPECTRAL_RIFT); + for (GameObject* portal : portals) + portal->Delete(); + } - void Reset() override + void DoAction(int32 action) override + { + switch (action) { - if (Creature* sath = instance->GetCreature(DATA_SATHROVARR)) - SathGUID = sath->GetGUID(); + case ACTION_START_OUTRO: + events.ScheduleEvent(EVENT_OUTRO_START, Seconds(1)); + break; + case ACTION_ENRAGE: + _isEnraged = true; + Talk(EMOTE_ENRAGE); + DoCastSelf(SPELL_ENRAGE, true); + break; + default: + break; + } + } - instance->SetBossState(DATA_KALECGOS, NOT_STARTED); + void DamageTaken(Unit* who, uint32 &damage) override + { + if (damage >= me->GetHealth() && who->GetGUID() != me->GetGUID()) + damage = 0; + } - if (Creature* Sath = ObjectAccessor::GetCreature(*me, SathGUID)) - Sath->AI()->EnterEvadeMode(); + void EnterCombat(Unit* /*who*/) override + { + instance->SendEncounterUnit(ENCOUNTER_FRAME_ENGAGE, me); + Talk(SAY_EVIL_AGGRO); + _EnterCombat(); - me->SetFaction(FACTION_MONSTER); - if (!bJustReset) //first reset at create + if (Creature* kalecgosHuman = me->SummonCreature(NPC_KALECGOS_HUMAN, KalecgosSummonPos, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 1000)) + if (Creature* sathrovar = instance->GetCreature(DATA_SATHROVARR)) { - me->RemoveUnitFlag(UnitFlags(UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE)); - me->SetDisableGravity(false); - me->SetVisible(true); - me->SetStandState(UNIT_STAND_STATE_SLEEP); + sathrovar->SetInCombatWith(kalecgosHuman); + kalecgosHuman->SetInCombatWith(sathrovar); } - me->SetFullHealth(); //dunno why it does not resets health at evade.. - } + } - void EnterEvadeMode(EvadeReason why) override - { - if (me->HasAura(SPELL_BANISH)) - return; + void KilledUnit(Unit* who) override + { + if (who->GetTypeId() == TYPEID_PLAYER && roll_chance_i(50)) + Talk(SAY_EVIL_SLAY); + } - bJustReset = true; - me->SetVisible(false); - me->AddUnitFlag(UnitFlags(UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE)); - ScriptedAI::EnterEvadeMode(why); - } + void MovementInform(uint32 type, uint32 id) override + { + if (type != POINT_MOTION_TYPE) + return; - void DoAction(int32 param) override + switch (id) { - switch (param) - { - case DO_ENRAGE: - isEnraged = true; - me->CastSpell(me, SPELL_ENRAGE, true); - break; - case DO_BANISH: - isBanished = true; - me->CastSpell(me, SPELL_BANISH, true); - break; - } + case POINT_OUTRO_1: + Talk(SAY_OUTRO_1); + events.ScheduleEvent(EVENT_OUTRO_3, Seconds(9)); + break; + case POINT_OUTRO_2: + me->SetVisible(false); + DespawnPortals(); + me->KillSelf(); + break; + default: + break; } + } + + void UpdateAI(uint32 diff) override + { + if (!UpdateVictim() && !events.IsInPhase(PHASE_OUTRO)) + return; + + events.Update(diff); + + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; - void UpdateAI(uint32 diff) override + while (uint32 eventId = events.ExecuteEvent()) { - if (TalkTimer) - { - if (!TalkSequence) - { - me->AddUnitFlag(UnitFlags(UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE)); - me->InterruptNonMeleeSpells(true); - me->RemoveAllAuras(); - me->GetThreatManager().ClearAllThreat(); - me->CombatStop(); - ++TalkSequence; - } - if (TalkTimer <= diff) - { - if (isFriendly) - GoodEnding(); - else - BadEnding(); - ++TalkSequence; - } else TalkTimer -= diff; - } - else + switch (eventId) { - if (bJustReset) - { - if (ResetTimer <= diff) - { - me->RemoveUnitFlag(UnitFlags(UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE)); - me->SetDisableGravity(false); - me->SetVisible(true); - me->SetStandState(UNIT_STAND_STATE_SLEEP); - ResetTimer = 10000; - bJustReset = false; - } else ResetTimer -= diff; - return; - } - - if (!UpdateVictim()) - return; + case EVENT_ARCANE_BUFFET: + if (roll_chance_i(20)) + Talk(SAY_ARCANE_BUFFET); + DoCastAOE(SPELL_ARCANE_BUFFET); + events.Repeat(Seconds(8)); + break; + case EVENT_FROST_BREATH: + DoCastAOE(SPELL_FROST_BREATH); + events.Repeat(Seconds(15)); + break; + case EVENT_TAIL_LASH: + DoCastAOE(SPELL_TAIL_LASH); + events.Repeat(Seconds(15)); + break; + case EVENT_WILD_MAGIC: + DoCastAOE(WildMagicSpells[urand(0, 5)], true); + events.Repeat(Seconds(20)); + break; + case EVENT_SPECTRAL_BLAST: + DoCastAOE(SPELL_SPECTRAL_BLAST, true); + events.Repeat(Seconds(20), Seconds(25)); + break; + case EVENT_CHECK_TIMER: + if (!_isEnraged && HealthBelowPct(10)) + DoAction(ACTION_ENRAGE); - if (CheckTimer <= diff) - { - if (me->GetDistance(CENTER_X, CENTER_Y, DRAGON_REALM_Z) >= 75) - { - EnterEvadeMode(EVADE_REASON_BOUNDARY); - return; - } - if (HealthBelowPct(10) && !isEnraged) + if (HealthBelowPct(1)) { - if (Creature* Sath = ObjectAccessor::GetCreature(*me, SathGUID)) - Sath->AI()->DoAction(DO_ENRAGE); - DoAction(DO_ENRAGE); - } - if (!isBanished && HealthBelowPct(1)) - { - if (Creature* Sath = ObjectAccessor::GetCreature(*me, SathGUID)) + if (Creature* sathrovarr = instance->GetCreature(DATA_SATHROVARR)) { - if (Sath->HasAura(SPELL_BANISH)) + if (sathrovarr->HasAura(SPELL_BANISH)) { - Sath->DealDamage(Sath, Sath->GetHealth()); - return; + sathrovarr->CastSpell(sathrovarr, SPELL_TAP_CHECK, true); + break; } - else - DoAction(DO_BANISH); - } - else - { - TC_LOG_ERROR("scripts", "Didn't find Shathrowar. Kalecgos event reseted."); - EnterEvadeMode(EVADE_REASON_OTHER); - return; } + if (_isBanished) + break; + + _isBanished = true; + DoCastSelf(SPELL_BANISH, true); + events.Reset(); } - CheckTimer = 1000; - } else CheckTimer -= diff; + events.Repeat(Seconds(1)); + break; + case EVENT_OUTRO_START: + events.Reset(); + events.SetPhase(PHASE_OUTRO); + me->setRegeneratingHealth(false); + me->SetReactState(REACT_PASSIVE); + me->InterruptNonMeleeSpells(true); + me->RemoveAllAttackers(); + me->AttackStop(); + me->SetFaction(FACTION_FRIENDLY); + me->RemoveAllAuras(); + instance->SendEncounterUnit(ENCOUNTER_FRAME_DISENGAGE, me); + events.ScheduleEvent(EVENT_OUTRO_1, Seconds(3)); + break; + case EVENT_OUTRO_1: + me->SetDisableGravity(true); + me->HandleEmoteCommand(EMOTE_ONESHOT_LIFTOFF); + events.ScheduleEvent(EVENT_OUTRO_2, Seconds(3)); + break; + case EVENT_OUTRO_2: + me->GetMotionMaster()->MovePoint(POINT_OUTRO_1, FlyPos[0]); + break; + case EVENT_OUTRO_3: + Talk(SAY_OUTRO_2); + me->GetMotionMaster()->MovePoint(POINT_OUTRO_2, FlyPos[1], false); + break; + default: + break; + } - if (ArcaneBuffetTimer <= diff) - { - DoCastAOE(SPELL_ARCANE_BUFFET); - ArcaneBuffetTimer = 8000; - } else ArcaneBuffetTimer -= diff; + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + } - if (FrostBreathTimer <= diff) - { - DoCastAOE(SPELL_FROST_BREATH); - FrostBreathTimer = 15000; - } else FrostBreathTimer -= diff; + DoMeleeAttackIfReady(); + } - if (TailLashTimer <= diff) - { - DoCastAOE(SPELL_TAIL_LASH); - TailLashTimer = 15000; - } else TailLashTimer -= diff; +private: + bool _isEnraged; + bool _isBanished; +}; - if (WildMagicTimer <= diff) - { - DoCastAOE(WildMagic[rand32() % 6]); - WildMagicTimer = 20000; - } else WildMagicTimer -= diff; +struct boss_kalecgos_human : public ScriptedAI +{ + boss_kalecgos_human(Creature* creature) : ScriptedAI(creature), _instance(creature->GetInstanceScript()) { } - if (SpectralBlastTimer <= diff) - { - ThreatContainer::StorageType const& m_threatlist = me->GetThreatManager().getThreatList(); - std::list<Unit*> targetList; - for (ThreatContainer::StorageType::const_iterator itr = m_threatlist.begin(); itr!= m_threatlist.end(); ++itr) - { - Unit* target = (*itr)->getTarget(); - if (target - && target->GetTypeId() == TYPEID_PLAYER - && (!target->GetVictim() || target->GetGUID() != me->EnsureVictim()->GetGUID()) - && target->GetPositionZ() > me->GetPositionZ() - 5 - && !target->HasAura(AURA_SPECTRAL_EXHAUSTION)) - { - targetList.push_back(target); - } - } - if (targetList.empty()) - { - SpectralBlastTimer = 1000; - return; - } + void Reset() override + { + _events.Reset(); + _events.SetPhase(PHASE_SAY_ONE); - std::list<Unit*>::const_iterator i = targetList.begin(); - advance(i, rand32() % targetList.size()); - if ((*i)) - { - (*i)->CastSpell((*i), SPELL_SPECTRAL_BLAST, true); - SpectralBlastTimer = 20000 + rand32() % 5000; - } else SpectralBlastTimer = 1000; - } else SpectralBlastTimer -= diff; + if (Creature* sath = _instance->GetCreature(DATA_SATHROVARR)) + _sathGUID = sath->GetGUID(); - DoMeleeAttackIfReady(); - } - } + _events.ScheduleEvent(EVENT_REVITALIZE, Seconds(5)); + _events.ScheduleEvent(EVENT_HEROIC_STRIKE, Seconds(3)); + } - void MoveInLineOfSight(Unit* who) override - { - if (bJustReset)//boss is invisible, don't attack - return; + void JustDied(Unit* /*killer*/) override + { + Talk(SAY_GOOD_DEATH); + } - if (!me->GetVictim() && me->IsValidAttackTarget(who)) - { - float attackRadius = me->GetAttackDistance(who); - if (me->IsWithinDistInMap(who, attackRadius)) - AttackStart(who); - } - } + void DamageTaken(Unit* who, uint32 &damage) override + { + if (who->GetGUID() != _sathGUID) + damage = 0; - void DamageTaken(Unit* done_by, uint32 &damage) override + if (HealthBelowPct(75) && _events.IsInPhase(PHASE_SAY_ONE)) { - if (damage >= me->GetHealth() && done_by != me) - damage = 0; + Talk(SAY_GOOD_NEAR_DEATH_0); + _events.SetPhase(PHASE_SAY_TWO); } - - void EnterCombat(Unit* /*who*/) override + else if (HealthBelowPct(50) && _events.IsInPhase(PHASE_SAY_TWO)) { - me->SetStandState(UNIT_STAND_STATE_STAND); - Talk(SAY_EVIL_AGGRO); - DoZoneInCombat(); - - instance->SetBossState(DATA_KALECGOS, IN_PROGRESS); + _events.SetPhase(PHASE_SAY_THREE); + Talk(SAY_GOOD_NEAR_DEATH_1); } - - void KilledUnit(Unit* /*victim*/) override + else if (HealthBelowPct(10) && _events.IsInPhase(PHASE_SAY_THREE)) { - Talk(SAY_EVIL_SLAY); + _events.SetPhase(PHASE_SAY_FOUR); + Talk(SAY_GOOD_NEAR_DEATH_2); } + } - void MovementInform(uint32 type, uint32 /*id*/) override - { - if (type != POINT_MOTION_TYPE) - return; - me->SetVisible(false); - if (isFriendly) - { - me->setDeathState(JUST_DIED); - me->GetMap()->ToInstanceMap()->PermBindAllPlayers(); - } - else - { - me->GetMotionMaster()->MoveTargetedHome(); - TalkTimer = 1000; - } - } + void UpdateAI(uint32 diff) override + { + if (!UpdateVictim()) + return; - void GoodEnding() - { - switch (TalkSequence) - { - case 1: - me->SetFaction(FACTION_FRIENDLY); - TalkTimer = 1000; - break; - case 2: - Talk(SAY_GOOD_PLRWIN); - TalkTimer = 10000; - break; - case 3: - me->SetDisableGravity(true); - me->GetMotionMaster()->MovePoint(0, FLY_X, FLY_Y, FLY_Z); - TalkTimer = 600000; - break; - default: - break; - } - } + _events.Update(diff); - void BadEnding() + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + + while (uint32 eventId = _events.ExecuteEvent()) { - switch (TalkSequence) + switch (eventId) { - case 1: - Talk(SAY_EVIL_ENRAGE); - TalkTimer = 3000; - break; - case 2: - me->SetDisableGravity(true); - me->GetMotionMaster()->MovePoint(0, FLY_X, FLY_Y, FLY_Z); - TalkTimer = 15000; + case EVENT_REVITALIZE: + DoCastSelf(SPELL_REVITALIZE); + _events.Repeat(Seconds(5)); break; - case 3: - EnterEvadeMode(EVADE_REASON_OTHER); + case EVENT_HEROIC_STRIKE: + DoCastVictim(SPELL_HEROIC_STRIKE); + _events.Repeat(Seconds(2)); break; default: break; } + + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; } - }; - CreatureAI* GetAI(Creature* creature) const override - { - return GetSunwellPlateauAI<boss_kalecgosAI>(creature); + DoMeleeAttackIfReady(); } + +private: + InstanceScript* _instance; + EventMap _events; + ObjectGuid _sathGUID; }; -class boss_kalec : public CreatureScript +class CurseAgonySelector : NonTankTargetSelector { public: - boss_kalec() : CreatureScript("boss_kalec") { } + CurseAgonySelector(Unit* source) : NonTankTargetSelector(source, true) { } - CreatureAI* GetAI(Creature* creature) const override + bool operator()(WorldObject* target) const { - return GetSunwellPlateauAI<boss_kalecAI>(creature); + if (Unit* unitTarget = target->ToUnit()) + return !NonTankTargetSelector::operator()(unitTarget) + || unitTarget->HasAura(SPELL_AGONY_CURSE) || unitTarget->HasAura(SPELL_AGONY_CURSE_ALLY) + || !unitTarget->HasAura(SPELL_SPECTRAL_REALM_AURA); + return false; } +}; - struct boss_kalecAI : public ScriptedAI - { - InstanceScript* instance; +struct boss_sathrovarr : public BossAI +{ + boss_sathrovarr(Creature* creature) : BossAI(creature, DATA_KALECGOS), _isEnraged(false), _isBanished(false) { } - uint32 RevitalizeTimer; - uint32 HeroicStrikeTimer; - uint32 YellTimer; - uint32 YellSequence; + void Reset() override + { + _isEnraged = false; + _isBanished = false; + _Reset(); + events.ScheduleEvent(EVENT_SHADOWBOLT, Seconds(7), Seconds(10)); + events.ScheduleEvent(EVENT_AGONY_CURSE, Seconds(20)); + events.ScheduleEvent(EVENT_CORRUPTION_STRIKE, Seconds(13)); + events.ScheduleEvent(EVENT_CHECK_TIMER, Seconds(1)); + } - ObjectGuid SathGUID; + void EnterCombat(Unit* /*who*/) override + { + _EnterCombat(); + Talk(SAY_SATH_AGGRO); + } - bool isEnraged; // if demon is enraged + void EnterEvadeMode(EvadeReason why) override + { + if (Creature* kalecgos = instance->GetCreature(DATA_KALECGOS_DRAGON)) + kalecgos->AI()->EnterEvadeMode(why); + } - boss_kalecAI(Creature* creature) : ScriptedAI(creature) + void SpellHit(Unit* caster, SpellInfo const* spell) override + { + if (spell->Id == SPELL_TAP_CHECK_DAMAGE) { - Initialize(); - instance = creature->GetInstanceScript(); + DoCastSelf(SPELL_TELEPORT_BACK, true); + caster->Kill(me); } + } - void Initialize() - { - RevitalizeTimer = 5000; - HeroicStrikeTimer = 3000; - YellTimer = 5000; - YellSequence = 0; - - isEnraged = false; - } + void DamageTaken(Unit* who, uint32 &damage) override + { + if (damage >= me->GetHealth() && who->GetGUID() != me->GetGUID()) + damage = 0; + } - void Reset() override + void KilledUnit(Unit* target) override + { + if (target->GetTypeId() == TYPEID_PLAYER) + Talk(SAY_SATH_SLAY); + else if (Creature* kalecgosHuman = instance->GetCreature(DATA_KALECGOS_HUMAN)) { - if (Creature* sath = instance->GetCreature(DATA_SATHROVARR)) - SathGUID = sath->GetGUID(); - - Initialize(); + if (kalecgosHuman->GetGUID() == target->GetGUID()) + EnterEvadeMode(EVADE_REASON_OTHER); } + } - void DamageTaken(Unit* done_by, uint32 &damage) override - { - if (done_by->GetGUID() != SathGUID) - damage = 0; - else if (isEnraged) - damage *= 3; - } + void JustDied(Unit* /*killer*/) override + { + _JustDied(); + Talk(SAY_SATH_DEATH); + instance->DoRemoveAurasDueToSpellOnPlayers(SPELL_SPECTRAL_REALM_AURA); + if (Creature* kalecgos = instance->GetCreature(DATA_KALECGOS_DRAGON)) + kalecgos->AI()->DoAction(ACTION_START_OUTRO); + } - void UpdateAI(uint32 diff) override + void ExecuteEvent(uint32 eventId) override + { + switch (eventId) { - if (!me->HasAura(AURA_SPECTRAL_INVISIBILITY)) - me->CastSpell(me, AURA_SPECTRAL_INVISIBILITY, true); - - if (!UpdateVictim()) - return; - - if (YellTimer <= diff) + case EVENT_SHADOWBOLT: + if (roll_chance_i(20)) + Talk(SAY_SATH_SPELL1); + DoCastAOE(SPELL_SHADOW_BOLT); + events.Repeat(Seconds(7), Seconds(10)); + break; + case EVENT_AGONY_CURSE: + { + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, CurseAgonySelector(me))) + DoCast(target, SPELL_AGONY_CURSE); + else + DoCastVictim(SPELL_AGONY_CURSE); + events.Repeat(Seconds(20)); + break; + } + case EVENT_CORRUPTION_STRIKE: + if (roll_chance_i(20)) + Talk(SAY_SATH_SPELL2); + DoCastVictim(SPELL_CORRUPTION_STRIKE); + events.Repeat(Seconds(13)); + break; + case EVENT_CHECK_TIMER: { - switch (YellSequence) + if (HealthBelowPct(10) && !_isEnraged) { - case 0: - Talk(SAY_GOOD_AGGRO); - ++YellSequence; - break; - case 1: - if (HealthBelowPct(50)) - { - Talk(SAY_GOOD_NEAR_DEATH); - ++YellSequence; - } - break; - case 2: - if (HealthBelowPct(10)) + _isEnraged = true; + if (Creature* kalecgos = instance->GetCreature(DATA_KALECGOS_DRAGON)) + kalecgos->AI()->DoAction(ACTION_ENRAGE); + } + + if (HealthBelowPct(1)) + { + if (Creature* kalecgos = instance->GetCreature(DATA_KALECGOS_DRAGON)) + { + if (kalecgos->HasAura(SPELL_BANISH)) { - Talk(SAY_GOOD_NEAR_DEATH2); - ++YellSequence; + DoCastSelf(SPELL_TAP_CHECK, true); + break; } + } + if (_isBanished) break; - default: - break; + + _isBanished = true; + DoCastSelf(SPELL_BANISH, true); } - YellTimer = 5000; + events.Repeat(Seconds(1)); + break; } - - if (RevitalizeTimer <= diff) - { - DoCast(me, SPELL_REVITALIZE); - RevitalizeTimer = 5000; - } else RevitalizeTimer -= diff; - - if (HeroicStrikeTimer <= diff) - { - DoCastVictim(SPELL_HEROIC_STRIKE); - HeroicStrikeTimer = 2000; - } else HeroicStrikeTimer -= diff; - - DoMeleeAttackIfReady(); + default: + break; } - }; + } + +private: + bool _isEnraged; + bool _isBanished; }; -class kalecgos_teleporter : public GameObjectScript +class go_kalecgos_spectral_rift : public GameObjectScript { -public: - kalecgos_teleporter() : GameObjectScript("kalecgos_teleporter") { } - - struct kalecgos_teleporterAI : public GameObjectAI - { - kalecgos_teleporterAI(GameObject* go) : GameObjectAI(go) { } + public: + go_kalecgos_spectral_rift() : GameObjectScript("go_kalecgos_spectral_rift") { } - bool GossipHello(Player* player) override + struct go_kalecgos_spectral_riftAI : public GameObjectAI { -#if MAX_PLAYERS_IN_SPECTRAL_REALM > 0 - uint8 SpectralPlayers = 0; - Map::PlayerList const &PlayerList = go->GetMap()->GetPlayers(); - for (Map::PlayerList::const_iterator i = PlayerList.begin(); i != PlayerList.end(); ++i) - { - if (i->GetSource() && i->GetSource()->GetPositionZ() < DEMON_REALM_Z + 5) - ++SpectralPlayers; - } + go_kalecgos_spectral_riftAI(GameObject* go) : GameObjectAI(go) { } - if (player->HasAura(AURA_SPECTRAL_EXHAUSTION) || SpectralPlayers >= MAX_PLAYERS_IN_SPECTRAL_REALM) + bool GossipHello(Player* player) override { + if (!player->HasAura(SPELL_SPECTRAL_EXHAUSTION)) + player->CastSpell(player, SPELL_SPECTRAL_REALM_TRIGGER, true); return true; } -#endif + }; - player->CastSpell(player, SPELL_TELEPORT_SPECTRAL, true); - return true; + GameObjectAI* GetAI(GameObject* go) const override + { + return GetSunwellPlateauAI<go_kalecgos_spectral_riftAI>(go); } - }; - - GameObjectAI* GetAI(GameObject* go) const override - { - return GetSunwellPlateauAI<kalecgos_teleporterAI>(go); - } }; -class boss_sathrovarr : public CreatureScript +// 46732 - Tap Check +class spell_kalecgos_tap_check : public SpellScript { -public: - boss_sathrovarr() : CreatureScript("boss_sathrovarr") { } + PrepareSpellScript(spell_kalecgos_tap_check); - CreatureAI* GetAI(Creature* creature) const override + bool Validate(SpellInfo const* spellInfo) override { - return GetSunwellPlateauAI<boss_sathrovarrAI>(creature); + return spellInfo->GetEffect(EFFECT_0) && ValidateSpellInfo({ uint32(spellInfo->GetEffect(EFFECT_0)->CalcValue()) }); } - struct boss_sathrovarrAI : public ScriptedAI + void HandleDummy(SpellEffIndex /*effIndex*/) { - boss_sathrovarrAI(Creature* creature) : ScriptedAI(creature) - { - Initialize(); - instance = creature->GetInstanceScript(); - } + GetHitUnit()->CastSpell(GetCaster(), (uint32)GetEffectInfo(EFFECT_0)->CalcValue(), true); + } + + void Register() override + { + OnEffectHitTarget += SpellEffectFn(spell_kalecgos_tap_check::HandleDummy, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT); + } +}; - void Initialize() +class SpectralBlastSelector : NonTankTargetSelector +{ + public: + SpectralBlastSelector(Unit* source) : NonTankTargetSelector(source, true) { } + + bool operator()(WorldObject* target) const { - ShadowBoltTimer = urand(7, 10) * 1000; - AgonyCurseTimer = 20000; - CorruptionStrikeTimer = 13000; - CheckTimer = 1000; - ResetThreat = 1000; - isEnraged = false; - isBanished = false; + if (Unit* unitTarget = target->ToUnit()) + return !NonTankTargetSelector::operator()(unitTarget) || + unitTarget->HasAura(SPELL_SPECTRAL_EXHAUSTION) || unitTarget->HasAura(SPELL_SPECTRAL_REALM_AURA); + return false; } +}; - InstanceScript* instance; +// 44869 - Spectral Blast +class spell_kalecgos_spectral_blast : public SpellScript +{ + PrepareSpellScript(spell_kalecgos_spectral_blast); - uint32 CorruptionStrikeTimer; - uint32 AgonyCurseTimer; - uint32 ShadowBoltTimer; - uint32 CheckTimer; - uint32 ResetThreat; + bool Validate(SpellInfo const* /*spell*/) override + { + return ValidateSpellInfo( + { + SPELL_SPECTRAL_BLAST_EFFECT, + SPELL_SPECTRAL_BLAST_VISUAL, + SPELL_SPECTRAL_REALM_TRIGGER + }); + } - ObjectGuid KalecGUID; - ObjectGuid KalecgosGUID; + void FilterTargets(std::list<WorldObject*>& targets) + { + targets.remove_if(SpectralBlastSelector(GetCaster())); + } - bool isEnraged; - bool isBanished; + void HandleDummy(SpellEffIndex /*effIndex*/) + { + Unit* caster = GetCaster(); + Unit* target = GetHitUnit(); - void Reset() override - { - me->SetFullHealth();//dunno why it does not resets health at evade.. - me->setActive(true); - if (Creature* kalecgos = instance->GetCreature(DATA_KALECGOS_DRAGON)) - KalecgosGUID = kalecgos->GetGUID(); - instance->SetBossState(DATA_KALECGOS, NOT_STARTED); - if (!KalecGUID.IsEmpty()) - { - if (Creature* Kalec = ObjectAccessor::GetCreature(*me, KalecGUID)) - Kalec->setDeathState(JUST_DIED); - KalecGUID.Clear(); - } + target->CastSpell(target, SPELL_SPECTRAL_BLAST_EFFECT, true); + caster->CastSpell(target, SPELL_SPECTRAL_BLAST_VISUAL, true); + caster->CastSpell(target, SPELL_SPECTRAL_REALM_TRIGGER, true); + } - Initialize(); + void Register() override + { + OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_kalecgos_spectral_blast::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY); + OnEffectHitTarget += SpellEffectFn(spell_kalecgos_spectral_blast::HandleDummy, EFFECT_0, SPELL_EFFECT_DUMMY); + } +}; - me->CastSpell(me, AURA_DEMONIC_VISUAL, true); - TeleportAllPlayersBack(); - } +// 44811 - Spectral Realm +class spell_kalecgos_spectral_realm_trigger : public SpellScript +{ + PrepareSpellScript(spell_kalecgos_spectral_realm_trigger); - void EnterCombat(Unit* /*who*/) override + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo( { - if (Creature* Kalec = me->SummonCreature(NPC_KALECGOS_HUMAN, me->GetPositionX() + 10, me->GetPositionY() + 5, me->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 0)) - { - KalecGUID = Kalec->GetGUID(); - me->CombatStart(Kalec); - AddThreat(Kalec, 100.0f); - Kalec->setActive(true); - } - Talk(SAY_SATH_AGGRO); - } + SPELL_SPECTRAL_REALM_TELEPORT, + SPELL_SPECTRAL_REALM_AURA, + SPELL_SPECTRAL_REALM_2, + SPELL_SPECTRAL_REALM_REACTION + }); + } - void DamageTaken(Unit* done_by, uint32 &damage) override - { - if (damage >= me->GetHealth() && done_by != me) - damage = 0; - } + void HandleDummy(SpellEffIndex /*effIndex*/) + { + Unit* target = GetHitUnit(); + target->CastSpell(target, SPELL_SPECTRAL_REALM_TELEPORT, true); + target->CastSpell(target, SPELL_SPECTRAL_REALM_AURA, true); + target->CastSpell(target, SPELL_SPECTRAL_REALM_2, true); + target->CastSpell(target, SPELL_SPECTRAL_REALM_REACTION, true); + } - void KilledUnit(Unit* target) override - { - if (target->GetGUID() == KalecGUID) - { - TeleportAllPlayersBack(); - if (Creature* Kalecgos = ObjectAccessor::GetCreature(*me, KalecgosGUID)) - { - ENSURE_AI(boss_kalecgos::boss_kalecgosAI, Kalecgos->AI())->TalkTimer = 1; - ENSURE_AI(boss_kalecgos::boss_kalecgosAI, Kalecgos->AI())->isFriendly = false; - } - EnterEvadeMode(); - return; - } - Talk(SAY_SATH_SLAY); - } + void Register() override + { + OnEffectHitTarget += SpellEffectFn(spell_kalecgos_spectral_realm_trigger::HandleDummy, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT); + } +}; + +// 46021 - Spectral Realm +class spell_kalecgos_spectral_realm_aura : public AuraScript +{ + PrepareAuraScript(spell_kalecgos_spectral_realm_aura); - void JustDied(Unit* /*killer*/) override + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo( { - Talk(SAY_SATH_DEATH); - me->UpdatePosition(me->GetPositionX(), me->GetPositionY(), DRAGON_REALM_Z, me->GetOrientation()); - TeleportAllPlayersBack(); - if (Creature* Kalecgos = ObjectAccessor::GetCreature(*me, KalecgosGUID)) - { - ENSURE_AI(boss_kalecgos::boss_kalecgosAI, Kalecgos->AI())->TalkTimer = 1; - ENSURE_AI(boss_kalecgos::boss_kalecgosAI, Kalecgos->AI())->isFriendly = true; - } + SPELL_SPECTRAL_REALM_REACTION, + SPELL_TELEPORT_BACK, + SPELL_SPECTRAL_EXHAUSTION + }); + } - instance->SetBossState(DATA_KALECGOS, DONE); - } + void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) + { + Unit* target = GetTarget(); + target->RemoveAurasDueToSpell(SPELL_SPECTRAL_REALM_REACTION); + target->CastSpell(target, SPELL_TELEPORT_BACK, true); + target->CastSpell(target, SPELL_SPECTRAL_EXHAUSTION, true); + } - void TeleportAllPlayersBack() - { - Map::PlayerList const &playerList = me->GetMap()->GetPlayers(); - Position const& homePos = me->GetHomePosition(); - for (Map::PlayerList::const_iterator itr = playerList.begin(); itr != playerList.end(); ++itr) - { - Player* player = itr->GetSource(); - if (player->IsInDist(&homePos, 50.0f) && player->GetPositionZ() <= DEMON_REALM_Z + 10.f) - { - player->RemoveAura(AURA_SPECTRAL_REALM); - player->TeleportTo(me->GetMap()->GetId(), player->GetPositionX(), - player->GetPositionY(), DRAGON_REALM_Z + 5, player->GetOrientation()); - } - } - } + void Register() override + { + AfterEffectRemove += AuraEffectRemoveFn(spell_kalecgos_spectral_realm_aura::OnRemove, EFFECT_0, SPELL_AURA_MOD_INVISIBILITY_DETECT, AURA_EFFECT_HANDLE_REAL); + } +}; - void DoAction(int32 param) override - { - switch (param) - { - case DO_ENRAGE: - isEnraged = true; - me->CastSpell(me, SPELL_ENRAGE, true); - break; - case DO_BANISH: - isBanished = true; - me->CastSpell(me, SPELL_BANISH, true); - break; - } - } +// 45032, 45034 - Curse of Boundless Agony +class spell_kalecgos_curse_of_boundless_agony : public AuraScript +{ + PrepareAuraScript(spell_kalecgos_curse_of_boundless_agony); - void UpdateAI(uint32 diff) override + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo( { - if (!me->HasAura(AURA_SPECTRAL_INVISIBILITY)) - me->CastSpell(me, AURA_SPECTRAL_INVISIBILITY, true); + SPELL_AGONY_CURSE_VISUAL_1, + SPELL_AGONY_CURSE_VISUAL_2, + SPELL_AGONY_CURSE_VISUAL_3, + SPELL_AGONY_CURSE_ALLY + }); + } - if (!UpdateVictim()) + void OnApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) + { + if (InstanceScript* instance = GetTarget()->GetInstanceScript()) + if (instance->GetBossState(DATA_KALECGOS) == IN_PROGRESS) return; - if (CheckTimer <= diff) - { - Creature* Kalec = ObjectAccessor::GetCreature(*me, KalecGUID); - if (!Kalec || !Kalec->IsAlive()) - { - if (Creature* Kalecgos = ObjectAccessor::GetCreature(*me, KalecgosGUID)) - Kalecgos->AI()->EnterEvadeMode(); - return; - } - - if (HealthBelowPct(10) && !isEnraged) - { - if (Creature* Kalecgos = ObjectAccessor::GetCreature(*me, KalecgosGUID)) - Kalecgos->AI()->DoAction(DO_ENRAGE); - DoAction(DO_ENRAGE); - } - - Creature* Kalecgos = ObjectAccessor::GetCreature(*me, KalecgosGUID); - if (Kalecgos && !Kalecgos->IsInCombat()) - { - EnterEvadeMode(); - return; - } - - if (!isBanished && HealthBelowPct(1)) - { - if (Kalecgos) - { - if (Kalecgos->HasAura(SPELL_BANISH)) - { - me->DealDamage(me, me->GetHealth()); - return; - } - DoAction(DO_BANISH); - } - else - { - EnterEvadeMode(); - return; - } - } - CheckTimer = 1000; - } else CheckTimer -= diff; + Remove(AURA_REMOVE_BY_CANCEL); + } - if (ResetThreat <= diff) - { - ThreatContainer::StorageType threatlist = me->GetThreatManager().getThreatList(); - for (ThreatContainer::StorageType::const_iterator itr = threatlist.begin(); itr != threatlist.end(); ++itr) - { - if (Unit* unit = ObjectAccessor::GetUnit(*me, (*itr)->getUnitGuid())) - if (unit->GetPositionZ() > me->GetPositionZ() + 5) - me->GetThreatManager().ModifyThreatByPercent(unit, -100); - } - ResetThreat = 1000; - } else ResetThreat -= diff; + void OnPeriodic(AuraEffect const* aurEff) + { + if (aurEff->GetTickNumber() <= 5) + GetTarget()->CastSpell(GetTarget(), SPELL_AGONY_CURSE_VISUAL_1, true); + else if (aurEff->GetTickNumber() <= 10) + GetTarget()->CastSpell(GetTarget(), SPELL_AGONY_CURSE_VISUAL_2, true); + else + GetTarget()->CastSpell(GetTarget(), SPELL_AGONY_CURSE_VISUAL_3, true); + } - if (ShadowBoltTimer <= diff) - { - if (!(rand32() % 5)) - Talk(SAY_SATH_SPELL1); - DoCast(me, SPELL_SHADOW_BOLT); - ShadowBoltTimer = 7000 + (rand32() % 3000); - } else ShadowBoltTimer -= diff; + void HandleEffectPeriodicUpdate(AuraEffect* aurEff) + { + if (aurEff->GetTickNumber() > 1 && aurEff->GetTickNumber() % 5 == 1) + aurEff->SetAmount(aurEff->GetAmount() * 2); + } - if (AgonyCurseTimer <= diff) - { - Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 1); - if (!target) - target = me->GetVictim(); - DoCast(target, SPELL_AGONY_CURSE); - AgonyCurseTimer = 20000; - } else AgonyCurseTimer -= diff; - - if (CorruptionStrikeTimer <= diff) - { - if (!(rand32() % 5))Talk(SAY_SATH_SPELL2); - DoCastVictim(SPELL_CORRUPTION_STRIKE); - CorruptionStrikeTimer = 13000; - } else CorruptionStrikeTimer -= diff; + void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) + { + if (GetTargetApplication()->GetRemoveMode() != AURA_REMOVE_BY_CANCEL) + GetTarget()->CastSpell(GetTarget(), SPELL_AGONY_CURSE_ALLY, true); + } - DoMeleeAttackIfReady(); - } - }; + void Register() override + { + AfterEffectApply += AuraEffectApplyFn(spell_kalecgos_curse_of_boundless_agony::OnApply, EFFECT_0, SPELL_AURA_PERIODIC_DAMAGE, AURA_EFFECT_HANDLE_REAL); + OnEffectPeriodic += AuraEffectPeriodicFn(spell_kalecgos_curse_of_boundless_agony::OnPeriodic, EFFECT_0, SPELL_AURA_PERIODIC_DAMAGE); + OnEffectUpdatePeriodic += AuraEffectUpdatePeriodicFn(spell_kalecgos_curse_of_boundless_agony::HandleEffectPeriodicUpdate, EFFECT_0, SPELL_AURA_PERIODIC_DAMAGE); + AfterEffectRemove += AuraEffectRemoveFn(spell_kalecgos_curse_of_boundless_agony::OnRemove, EFFECT_0, SPELL_AURA_PERIODIC_DAMAGE, AURA_EFFECT_HANDLE_REAL); + } }; void AddSC_boss_kalecgos() { - new boss_kalecgos(); - new boss_sathrovarr(); - new boss_kalec(); - new kalecgos_teleporter(); + RegisterSunwellPlateauCreatureAI(boss_kalecgos); + RegisterSunwellPlateauCreatureAI(boss_sathrovarr); + RegisterSunwellPlateauCreatureAI(boss_kalecgos_human); + new go_kalecgos_spectral_rift(); + RegisterSpellScript(spell_kalecgos_tap_check); + RegisterSpellScript(spell_kalecgos_spectral_blast); + RegisterSpellScript(spell_kalecgos_spectral_realm_trigger); + RegisterAuraScript(spell_kalecgos_spectral_realm_aura); + RegisterAuraScript(spell_kalecgos_curse_of_boundless_agony); } diff --git a/src/server/scripts/EasternKingdoms/SunwellPlateau/instance_sunwell_plateau.cpp b/src/server/scripts/EasternKingdoms/SunwellPlateau/instance_sunwell_plateau.cpp index a077212480f..c2960845be9 100644 --- a/src/server/scripts/EasternKingdoms/SunwellPlateau/instance_sunwell_plateau.cpp +++ b/src/server/scripts/EasternKingdoms/SunwellPlateau/instance_sunwell_plateau.cpp @@ -16,8 +16,7 @@ */ #include "ScriptMgr.h" -#include "Creature.h" -#include "GameObject.h" +#include "AreaBoundary.h" #include "InstanceScript.h" #include "Log.h" #include "Map.h" @@ -62,6 +61,11 @@ ObjectData const creatureData[] = { 0, 0 } // END }; +BossBoundaryData const boundaries = +{ + { DATA_KALECGOS, new BoundaryUnionBoundary(new CircleBoundary(Position(1704.9f, 928.4f), 34.0), new RectangleBoundary(1689.2f, 1713.3f, 762.2f, 1074.8f)) } +}; + class instance_sunwell_plateau : public InstanceMapScript { public: @@ -75,6 +79,7 @@ class instance_sunwell_plateau : public InstanceMapScript SetBossNumber(EncounterCount); LoadDoorData(doorData); LoadObjectData(creatureData, nullptr); + LoadBossBoundaries(boundaries); } Player const* GetPlayerInMap() const diff --git a/src/server/scripts/EasternKingdoms/SunwellPlateau/sunwell_plateau.h b/src/server/scripts/EasternKingdoms/SunwellPlateau/sunwell_plateau.h index 90b8df36f33..1ea9a56f7ec 100644 --- a/src/server/scripts/EasternKingdoms/SunwellPlateau/sunwell_plateau.h +++ b/src/server/scripts/EasternKingdoms/SunwellPlateau/sunwell_plateau.h @@ -111,7 +111,8 @@ enum SWPGameObjectIds GO_BOSS_COLLISION_2 = 188524, GO_FIRE_BARRIER = 188075, GO_MURUS_GATE_1 = 187990, - GO_MURUS_GATE_2 = 188118 + GO_MURUS_GATE_2 = 188118, + GO_SPECTRAL_RIFT = 187055 }; template <class AI, class T> @@ -120,4 +121,6 @@ inline AI* GetSunwellPlateauAI(T* obj) return GetInstanceAI<AI>(obj, SunwellPlateauScriptName); } +#define RegisterSunwellPlateauCreatureAI(ai_name) RegisterCreatureAIWithFactory(ai_name, GetSunwellPlateauAI) + #endif // SUNWELL_PLATEAU_H |