aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/server/game/Spells/Spell.cpp3
-rw-r--r--src/server/scripts/EasternKingdoms/SunwellPlateau/boss_kalecgos.cpp1255
-rw-r--r--src/server/scripts/EasternKingdoms/SunwellPlateau/instance_sunwell_plateau.cpp9
-rw-r--r--src/server/scripts/EasternKingdoms/SunwellPlateau/sunwell_plateau.h5
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