/* * This file is part of the TrinityCore 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 General Public License as published by the * Free Software Foundation; either version 2 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 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 . */ #include "ScriptMgr.h" #include "GameObject.h" #include "GameObjectAI.h" #include "InstanceScript.h" #include "MotionMaster.h" #include "Player.h" #include "ScriptedCreature.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_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 { 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 { ACTION_START_OUTRO = 1, ACTION_ENRAGE }; enum KalecSayPhases { PHASE_SAY_ONE = 1, PHASE_SAY_TWO, PHASE_SAY_THREE, PHASE_SAY_FOUR, PHASE_OUTRO }; enum KalecgosPoints { POINT_OUTRO_1 = 0, POINT_OUTRO_2 }; 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 } }; uint32 const WildMagicSpells[6] = { 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) { } void Reset() override { _isEnraged = false; _isBanished = false; _Reset(); events.ScheduleEvent(EVENT_ARCANE_BUFFET, 8s); events.ScheduleEvent(EVENT_FROST_BREATH, 15s); events.ScheduleEvent(EVENT_WILD_MAGIC, 10s); events.ScheduleEvent(EVENT_TAIL_LASH, 25s); events.ScheduleEvent(EVENT_SPECTRAL_BLAST, 20s, 25s); events.ScheduleEvent(EVENT_CHECK_TIMER, 1s); } void EnterEvadeMode(EvadeReason /*why*/) override { if (events.IsInPhase(PHASE_OUTRO) || me->HasAura(SPELL_BANISH)) return; _EnterEvadeMode(); instance->SendEncounterUnit(ENCOUNTER_FRAME_DISENGAGE, me); instance->DoRemoveAurasDueToSpellOnPlayers(SPELL_SPECTRAL_REALM_AURA, true, true); summons.DespawnAll(); DespawnPortals(); if (Creature* sathrovar = instance->GetCreature(DATA_SATHROVARR)) _DespawnAtEvade(Seconds(10), sathrovar); _DespawnAtEvade(Seconds(10)); } void DespawnPortals() { std::vector portals; me->GetGameObjectListWithEntryInGrid(portals, GO_SPECTRAL_RIFT); for (GameObject* portal : portals) portal->Delete(); } void DoAction(int32 action) override { switch (action) { case ACTION_START_OUTRO: events.ScheduleEvent(EVENT_OUTRO_START, 1s); break; case ACTION_ENRAGE: _isEnraged = true; Talk(EMOTE_ENRAGE); DoCastSelf(SPELL_ENRAGE, true); break; default: break; } } void DamageTaken(Unit* who, uint32& damage, DamageEffectType /*damageType*/, SpellInfo const* /*spellInfo = nullptr*/) override { if (damage >= me->GetHealth() && (!who || who->GetGUID() != me->GetGUID())) damage = 0; } void JustEngagedWith(Unit* who) override { instance->SendEncounterUnit(ENCOUNTER_FRAME_ENGAGE, me); Talk(SAY_EVIL_AGGRO); BossAI::JustEngagedWith(who); if (Creature* kalecgosHuman = me->SummonCreature(NPC_KALECGOS_HUMAN, KalecgosSummonPos, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 1s)) if (Creature* sathrovar = instance->GetCreature(DATA_SATHROVARR)) { sathrovar->SetInCombatWith(kalecgosHuman); kalecgosHuman->SetInCombatWith(sathrovar); } } void KilledUnit(Unit* who) override { if (who->GetTypeId() == TYPEID_PLAYER && roll_chance_i(50)) Talk(SAY_EVIL_SLAY); } void MovementInform(uint32 type, uint32 id) override { if (type != POINT_MOTION_TYPE) return; switch (id) { 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; while (uint32 eventId = events.ExecuteEvent()) { switch (eventId) { 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 (HealthBelowPct(1)) { if (Creature* sathrovarr = instance->GetCreature(DATA_SATHROVARR)) { if (sathrovarr->HasAura(SPELL_BANISH)) { sathrovarr->CastSpell(sathrovarr, SPELL_TAP_CHECK, true); break; } } if (_isBanished) break; _isBanished = true; DoCastSelf(SPELL_BANISH, true); events.Reset(); } events.Repeat(Seconds(1)); break; case EVENT_OUTRO_START: events.Reset(); events.SetPhase(PHASE_OUTRO); me->SetRegenerateHealth(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 (me->HasUnitState(UNIT_STATE_CASTING)) return; } } private: bool _isEnraged; bool _isBanished; }; struct boss_kalecgos_human : public ScriptedAI { boss_kalecgos_human(Creature* creature) : ScriptedAI(creature), _instance(creature->GetInstanceScript()) { } void Reset() override { _events.Reset(); _events.SetPhase(PHASE_SAY_ONE); if (Creature* sath = _instance->GetCreature(DATA_SATHROVARR)) _sathGUID = sath->GetGUID(); _events.ScheduleEvent(EVENT_REVITALIZE, 5s); _events.ScheduleEvent(EVENT_HEROIC_STRIKE, 3s); } void JustDied(Unit* /*killer*/) override { Talk(SAY_GOOD_DEATH); } void DamageTaken(Unit* who, uint32& damage, DamageEffectType /*damageType*/, SpellInfo const* /*spellInfo = nullptr*/) override { if (!who || who->GetGUID() != _sathGUID) damage = 0; if (HealthBelowPct(75) && _events.IsInPhase(PHASE_SAY_ONE)) { Talk(SAY_GOOD_NEAR_DEATH_0); _events.SetPhase(PHASE_SAY_TWO); } else if (HealthBelowPct(50) && _events.IsInPhase(PHASE_SAY_TWO)) { _events.SetPhase(PHASE_SAY_THREE); Talk(SAY_GOOD_NEAR_DEATH_1); } else if (HealthBelowPct(10) && _events.IsInPhase(PHASE_SAY_THREE)) { _events.SetPhase(PHASE_SAY_FOUR); Talk(SAY_GOOD_NEAR_DEATH_2); } } void UpdateAI(uint32 diff) override { if (!UpdateVictim()) return; _events.Update(diff); if (me->HasUnitState(UNIT_STATE_CASTING)) return; while (uint32 eventId = _events.ExecuteEvent()) { switch (eventId) { case EVENT_REVITALIZE: DoCastSelf(SPELL_REVITALIZE); _events.Repeat(Seconds(5)); break; case EVENT_HEROIC_STRIKE: DoCastVictim(SPELL_HEROIC_STRIKE); _events.Repeat(Seconds(2)); break; default: break; } if (me->HasUnitState(UNIT_STATE_CASTING)) return; } } private: InstanceScript* _instance; EventMap _events; ObjectGuid _sathGUID; }; class CurseAgonySelector : NonTankTargetSelector { public: CurseAgonySelector(Unit* source) : NonTankTargetSelector(source, true) { } bool operator()(WorldObject* target) const { 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_sathrovarr : public BossAI { boss_sathrovarr(Creature* creature) : BossAI(creature, DATA_KALECGOS), _isEnraged(false), _isBanished(false) { } void Reset() override { _isEnraged = false; _isBanished = false; _Reset(); events.ScheduleEvent(EVENT_SHADOWBOLT, 7s, 10s); events.ScheduleEvent(EVENT_AGONY_CURSE, 20s); events.ScheduleEvent(EVENT_CORRUPTION_STRIKE, 13s); events.ScheduleEvent(EVENT_CHECK_TIMER, 1s); } void JustEngagedWith(Unit* who) override { BossAI::JustEngagedWith(who); Talk(SAY_SATH_AGGRO); } void EnterEvadeMode(EvadeReason why) override { if (Creature* kalecgos = instance->GetCreature(DATA_KALECGOS_DRAGON)) kalecgos->AI()->EnterEvadeMode(why); } void SpellHit(WorldObject* caster, SpellInfo const* spellInfo) override { Unit* unitCaster = caster->ToUnit(); if (!unitCaster) return; if (spellInfo->Id == SPELL_TAP_CHECK_DAMAGE) { DoCastSelf(SPELL_TELEPORT_BACK, true); Unit::Kill(unitCaster, me); } } void DamageTaken(Unit* who, uint32& damage, DamageEffectType /*damageType*/, SpellInfo const* /*spellInfo = nullptr*/) override { if (damage >= me->GetHealth() && (!who || who->GetGUID() != me->GetGUID())) damage = 0; } void KilledUnit(Unit* target) override { if (target->GetTypeId() == TYPEID_PLAYER) Talk(SAY_SATH_SLAY); else if (Creature* kalecgosHuman = instance->GetCreature(DATA_KALECGOS_HUMAN)) { if (kalecgosHuman->GetGUID() == target->GetGUID()) EnterEvadeMode(EvadeReason::Other); } } void JustDied(Unit* /*killer*/) override { _JustDied(); Talk(SAY_SATH_DEATH); instance->DoRemoveAurasDueToSpellOnPlayers(SPELL_SPECTRAL_REALM_AURA, true, true); if (Creature* kalecgos = instance->GetCreature(DATA_KALECGOS_DRAGON)) kalecgos->AI()->DoAction(ACTION_START_OUTRO); } void ExecuteEvent(uint32 eventId) override { switch (eventId) { 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: { CastSpellExtraArgs args(TRIGGERED_FULL_MASK); args.AddSpellMod(SPELLVALUE_MAX_TARGETS, 1); if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, CurseAgonySelector(me))) DoCast(target, SPELL_AGONY_CURSE, args); else DoCastVictim(SPELL_AGONY_CURSE, args); 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: { if (HealthBelowPct(10) && !_isEnraged) { _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)) { DoCastSelf(SPELL_TAP_CHECK, true); break; } } if (_isBanished) break; _isBanished = true; DoCastSelf(SPELL_BANISH, true); } events.Repeat(Seconds(1)); break; } default: break; } } private: bool _isEnraged; bool _isBanished; }; class go_kalecgos_spectral_rift : public GameObjectScript { public: go_kalecgos_spectral_rift() : GameObjectScript("go_kalecgos_spectral_rift") { } struct go_kalecgos_spectral_riftAI : public GameObjectAI { go_kalecgos_spectral_riftAI(GameObject* go) : GameObjectAI(go) { } bool OnGossipHello(Player* player) override { if (!player->HasAura(SPELL_SPECTRAL_EXHAUSTION)) player->CastSpell(player, SPELL_SPECTRAL_REALM_TRIGGER, true); return true; } }; GameObjectAI* GetAI(GameObject* go) const override { return GetSunwellPlateauAI(go); } }; // 46732 - Tap Check class spell_kalecgos_tap_check : public SpellScript { bool Validate(SpellInfo const* spellInfo) override { return ValidateSpellEffect({ { spellInfo->Id, EFFECT_0 } }) && ValidateSpellInfo({ uint32(spellInfo->GetEffect(EFFECT_0).CalcValue()) }); } void HandleDummy(SpellEffIndex /*effIndex*/) { GetHitUnit()->CastSpell(GetCaster(), GetEffectInfo().CalcValue(), true); } void Register() override { OnEffectHitTarget += SpellEffectFn(spell_kalecgos_tap_check::HandleDummy, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT); } }; class SpectralBlastSelector : NonTankTargetSelector { public: SpectralBlastSelector(Unit* source) : NonTankTargetSelector(source, true) { } bool operator()(WorldObject* target) const { if (Unit* unitTarget = target->ToUnit()) return !NonTankTargetSelector::operator()(unitTarget) && !unitTarget->HasAura(SPELL_SPECTRAL_EXHAUSTION) && !unitTarget->HasAura(SPELL_SPECTRAL_REALM_AURA); return false; } }; // 44869 - Spectral Blast class spell_kalecgos_spectral_blast : public SpellScript { bool Validate(SpellInfo const* /*spell*/) override { return ValidateSpellInfo( { SPELL_SPECTRAL_BLAST_EFFECT, SPELL_SPECTRAL_BLAST_VISUAL, SPELL_SPECTRAL_REALM_TRIGGER }); } void FilterTargets(std::list& targets) { targets.remove_if(SpectralBlastSelector(GetCaster())); } void HandleDummy(SpellEffIndex /*effIndex*/) { Unit* caster = GetCaster(); Unit* target = GetHitUnit(); target->CastSpell(target, SPELL_SPECTRAL_BLAST_EFFECT, true); caster->CastSpell(target, SPELL_SPECTRAL_BLAST_VISUAL, true); caster->CastSpell(target, SPELL_SPECTRAL_REALM_TRIGGER, true); } 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); } }; // 44811 - Spectral Realm class spell_kalecgos_spectral_realm_trigger : public SpellScript { bool Validate(SpellInfo const* /*spellInfo*/) override { return ValidateSpellInfo( { SPELL_SPECTRAL_REALM_TELEPORT, SPELL_SPECTRAL_REALM_AURA, SPELL_SPECTRAL_REALM_2, SPELL_SPECTRAL_REALM_REACTION }); } 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 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 { bool Validate(SpellInfo const* /*spellInfo*/) override { return ValidateSpellInfo( { SPELL_SPECTRAL_REALM_REACTION, SPELL_TELEPORT_BACK, SPELL_SPECTRAL_EXHAUSTION }); } 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 Register() override { AfterEffectRemove += AuraEffectRemoveFn(spell_kalecgos_spectral_realm_aura::OnRemove, EFFECT_0, SPELL_AURA_MOD_INVISIBILITY_DETECT, AURA_EFFECT_HANDLE_REAL); } }; // 45032, 45034 - Curse of Boundless Agony class spell_kalecgos_curse_of_boundless_agony : public AuraScript { bool Validate(SpellInfo const* /*spellInfo*/) override { return ValidateSpellInfo( { SPELL_AGONY_CURSE_VISUAL_1, SPELL_AGONY_CURSE_VISUAL_2, SPELL_AGONY_CURSE_VISUAL_3, SPELL_AGONY_CURSE_ALLY }); } void OnApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) { if (InstanceScript* instance = GetTarget()->GetInstanceScript()) if (instance->GetBossState(DATA_KALECGOS) == IN_PROGRESS) return; Remove(AURA_REMOVE_BY_CANCEL); } 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); } void HandleEffectPeriodicUpdate(AuraEffect* aurEff) { if (aurEff->GetTickNumber() > 1 && aurEff->GetTickNumber() % 5 == 1) aurEff->SetAmount(aurEff->GetAmount() * 2); } void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) { if (GetTargetApplication()->GetRemoveMode() == AURA_REMOVE_BY_CANCEL) return; CastSpellExtraArgs args(TRIGGERED_FULL_MASK); args.AddSpellMod(SPELLVALUE_MAX_TARGETS, 1); GetTarget()->CastSpell(GetTarget(), SPELL_AGONY_CURSE_ALLY, args); } 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() { 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); RegisterSpellScript(spell_kalecgos_spectral_realm_aura); RegisterSpellScript(spell_kalecgos_curse_of_boundless_agony); }