aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGustavo <sirikfoll@hotmail.com>2017-08-08 22:36:40 -0300
committerGitHub <noreply@github.com>2017-08-08 22:36:40 -0300
commite9cd7af2dfcb7948f27e83e73398da0086190aab (patch)
tree8b6976068631714eb22d6ca2ea8c3be709b062fb /src
parent4cf49614e6e3e4a2da09c0f00404f323ae948590 (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
Diffstat (limited to 'src')
-rw-r--r--src/server/game/Spells/Spell.cpp5
-rw-r--r--src/server/scripts/EasternKingdoms/SunwellPlateau/boss_kalecgos.cpp1249
-rw-r--r--src/server/scripts/EasternKingdoms/SunwellPlateau/instance_sunwell_plateau.cpp7
-rw-r--r--src/server/scripts/EasternKingdoms/SunwellPlateau/sunwell_plateau.h5
4 files changed, 625 insertions, 641 deletions
diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp
index 48dddb23ca5..be01f88c2d5 100644
--- a/src/server/game/Spells/Spell.cpp
+++ b/src/server/game/Spells/Spell.cpp
@@ -2552,7 +2552,8 @@ SpellMissInfo Spell::DoSpellHitOnUnit(Unit* unit, uint32 effectMask, bool scaleA
// 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->Speed > 0.0f && unit->GetTypeId() == TYPEID_PLAYER && !m_spellInfo->IsPositive() && m_spellInfo->Id != 63881)
+ // 45034 - Curse of Boundless Agony jump spell (Kalecgos)
+ if (m_spellInfo->Speed > 0.0f && unit->GetTypeId() == TYPEID_PLAYER && !m_spellInfo->IsPositive() && m_spellInfo->Id != 63881 && m_spellInfo->Id != 45034)
return SPELL_MISS_EVADE;
// assisting case, healing and resurrection
@@ -7882,7 +7883,7 @@ bool WorldObjectSpellAreaTargetCheck::operator()(WorldObject* target)
if (!isInsideCylinder)
return false;
}
-
+
return WorldObjectSpellTargetCheck::operator ()(target);
}
diff --git a/src/server/scripts/EasternKingdoms/SunwellPlateau/boss_kalecgos.cpp b/src/server/scripts/EasternKingdoms/SunwellPlateau/boss_kalecgos.cpp
index 5dd4a3248ac..065448261b7 100644
--- a/src/server/scripts/EasternKingdoms/SunwellPlateau/boss_kalecgos.cpp
+++ b/src/server/scripts/EasternKingdoms/SunwellPlateau/boss_kalecgos.cpp
@@ -1,6 +1,5 @@
/*
* Copyright (C) 2008-2017 TrinityCore <http://www.trinitycore.org/>
- * Copyright (C) 2006-2009 ScriptDev2 <https://scriptdev2.svn.sourceforge.net/>
*
* 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
@@ -16,808 +15,782 @@
* 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 "SpellAuraEffects.h"
+#include "SpellScript.h"
#include "sunwell_plateau.h"
#include "TemporarySummon.h"
#include "WorldSession.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 = 44836,
- 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 = 44836,
+ 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_kalecgosAI : public ScriptedAI
+struct boss_kalecgos : public BossAI
+{
+ boss_kalecgos(Creature* creature) : BossAI(creature, DATA_KALECGOS), _isEnraged(false), _isBanished(false) { }
+
+ 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*/)
+ {
+ if (events.IsInPhase(PHASE_OUTRO))
+ 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->RemoveFlag(UNIT_FIELD_FLAGS, 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 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;
- void EnterEvadeMode(EvadeReason why) override
+ switch (id)
{
- bJustReset = true;
- me->SetVisible(false);
- me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE + UNIT_FLAG_NOT_SELECTABLE);
- ScriptedAI::EnterEvadeMode(why);
+ 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 DoAction(int32 param) override
+ while (uint32 eventId = events.ExecuteEvent())
{
- switch (param)
+ switch (eventId)
{
- case DO_ENRAGE:
- isEnraged = true;
- me->CastSpell(me, SPELL_ENRAGE, true);
+ case EVENT_ARCANE_BUFFET:
+ if (roll_chance_i(20))
+ Talk(SAY_ARCANE_BUFFET);
+ DoCastAOE(SPELL_ARCANE_BUFFET);
+ events.Repeat(Seconds(8));
break;
- case DO_BANISH:
- isBanished = true;
- me->CastSpell(me, SPELL_BANISH, true);
+ case EVENT_FROST_BREATH:
+ DoCastAOE(SPELL_FROST_BREATH);
+ events.Repeat(Seconds(15));
break;
- }
- }
-
- void UpdateAI(uint32 diff) override
- {
- if (TalkTimer)
- {
- if (!TalkSequence)
- {
- me->SetFlag(UNIT_FIELD_FLAGS, 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
- {
- if (bJustReset)
- {
- if (ResetTimer <= diff)
- {
- me->RemoveFlag(UNIT_FIELD_FLAGS, 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_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);
+
+ if (me->HasUnitState(UNIT_STATE_CASTING))
+ return;
- void BadEnding()
+ while (uint32 eventId = _events.ExecuteEvent())
{
- switch (TalkSequence)
+ switch (eventId)
{
- case 1:
- Talk(SAY_EVIL_ENRAGE);
- TalkTimer = 3000;
+ case EVENT_REVITALIZE:
+ DoCastSelf(SPELL_REVITALIZE);
+ _events.Repeat(Seconds(5));
break;
- case 2:
- me->SetDisableGravity(true);
- me->GetMotionMaster()->MovePoint(0, FLY_X, FLY_Y, FLY_Z);
- TalkTimer = 15000;
- 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)
+ {
+ 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:
{
- switch (YellSequence)
+ 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:
+ {
+ 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 ValidateSpellInfo({ uint32(spellInfo->Effects[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)GetSpellInfo()->Effects[EFFECT_0].CalcValue(), true);
+ }
- void Initialize()
+ 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
{
- 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)
- {
- 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 6b3c2b1bcaf..e5df84f8ba1 100644
--- a/src/server/scripts/EasternKingdoms/SunwellPlateau/instance_sunwell_plateau.cpp
+++ b/src/server/scripts/EasternKingdoms/SunwellPlateau/instance_sunwell_plateau.cpp
@@ -16,6 +16,7 @@
*/
#include "ScriptMgr.h"
+#include "AreaBoundary.h"
#include "InstanceScript.h"
#include "Log.h"
#include "Map.h"
@@ -60,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:
@@ -73,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 cec43582958..85fbde015fb 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 @@ AI* GetSunwellPlateauAI(T* obj)
return GetInstanceAI<AI>(obj, SunwellPlateauScriptName);
}
+#define RegisterSunwellPlateauCreatureAI(ai_name) RegisterCreatureAIWithFactory(ai_name, GetSunwellPlateauAI)
+
#endif // SUNWELL_PLATEAU_H