diff options
author | Gustavo <sirikfoll@hotmail.com> | 2017-08-08 22:36:40 -0300 |
---|---|---|
committer | Shauren <shauren.trinity@gmail.com> | 2020-08-22 21:13:01 +0200 |
commit | 6135ee20a9e96b6981b9a9b37f098c5abd12229f (patch) | |
tree | 9a87933d0f6d9cb5a1acf820ec775f88f3a3e440 /src | |
parent | b538cdc129e6132ddd6afc2c5ac5ccaae2959730 (diff) |
Core/Scripts: Rewrite Boss Kalecgos (Sunwell Plateau) (#19897)
* Core/Scripts: Rewrite Boss Kalecgos (Sunwell Plateau)
Scripted all spells
Corrected behavior of Spectral Blast and Curse of Boundless Agony
Removed wrong wipe behavior
Fix problem where bosses would be stuck with banish
Added Boundaries
Corrected texts
Removed old hacks
Other minor fixes
(cherry picked from commit e9cd7af2dfcb7948f27e83e73398da0086190aab)
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 |