aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorOvah <dreadkiller@gmx.de>2019-01-28 15:01:20 -0300
committerShauren <shauren.trinity@gmail.com>2021-11-23 00:21:42 +0100
commit3847d7b2778c0799b8942f2ed70ee40771d28533 (patch)
treee89df6e38e1e72f5891a1f1d589a8622fcd645db /src
parent4af28946263be5cd2631f97f92eb2ebe86d901cb (diff)
Scripts/Magister Terrace: Felblood Kaelthas rewrite
Cherrypick of https://github.com/Ovahlord/TrinityCore/commit/ae440400aaf90de11cf92010839ab98a8403c003 (cherry picked from commit 00958c9178781ac11a9dcabd034ed2e82120fad6)
Diffstat (limited to 'src')
-rw-r--r--src/server/game/Spells/Auras/SpellAuraEffects.cpp12
-rw-r--r--src/server/game/Spells/SpellMgr.cpp3
-rw-r--r--src/server/scripts/EasternKingdoms/MagistersTerrace/boss_felblood_kaelthas.cpp957
-rw-r--r--src/server/scripts/EasternKingdoms/MagistersTerrace/instance_magisters_terrace.cpp145
-rw-r--r--src/server/scripts/EasternKingdoms/MagistersTerrace/magisters_terrace.h45
5 files changed, 525 insertions, 637 deletions
diff --git a/src/server/game/Spells/Auras/SpellAuraEffects.cpp b/src/server/game/Spells/Auras/SpellAuraEffects.cpp
index d2ed2ca186b..47c7bb7ba8a 100644
--- a/src/server/game/Spells/Auras/SpellAuraEffects.cpp
+++ b/src/server/game/Spells/Auras/SpellAuraEffects.cpp
@@ -4514,20 +4514,8 @@ void AuraEffect::HandleAuraDummy(AuraApplication const* aurApp, uint8 mode, bool
}
break;
case 36730: // Flame Strike
- {
target->CastSpell(target, 36731, this);
break;
- }
- case 44191: // Flame Strike
- {
- if (target->GetMap()->IsDungeon())
- {
- uint32 spellId = target->GetMap()->IsHeroic() ? 46163 : 44190;
-
- target->CastSpell(target, spellId, this);
- }
- break;
- }
case 43681: // Inactive
{
if (target->GetTypeId() != TYPEID_PLAYER || aurApp->GetRemoveMode() != AURA_REMOVE_BY_EXPIRE)
diff --git a/src/server/game/Spells/SpellMgr.cpp b/src/server/game/Spells/SpellMgr.cpp
index 50dc075c120..111cf8fa367 100644
--- a/src/server/game/Spells/SpellMgr.cpp
+++ b/src/server/game/Spells/SpellMgr.cpp
@@ -4632,6 +4632,9 @@ void SpellMgr::LoadSpellInfoCorrections()
properties->Title = AsUnderlyingType(SummonTitle::Totem);
if (SummonPropertiesEntry* properties = const_cast<SummonPropertiesEntry*>(sSummonPropertiesStore.LookupEntry(628))) // Hungry Plaguehound
properties->Control = SUMMON_CATEGORY_PET;
+ // Came with 00958c9178781ac11a9dcabd034ed2e82120fad6 but as of 9.1.5 there are 533 other spells using this summon properties
+ //if (SummonPropertiesEntry* properties = const_cast<SummonPropertiesEntry*>(sSummonPropertiesStore.LookupEntry(61))) // Summon Arcane Spheres
+ // properties->Title = AsUnderlyingType(SummonTitle::None);
TC_LOG_INFO("server.loading", ">> Loaded SpellInfo corrections in %u ms", GetMSTimeDiffToNow(oldMSTime));
}
diff --git a/src/server/scripts/EasternKingdoms/MagistersTerrace/boss_felblood_kaelthas.cpp b/src/server/scripts/EasternKingdoms/MagistersTerrace/boss_felblood_kaelthas.cpp
index b41a3d78c81..0cfae13f8ee 100644
--- a/src/server/scripts/EasternKingdoms/MagistersTerrace/boss_felblood_kaelthas.cpp
+++ b/src/server/scripts/EasternKingdoms/MagistersTerrace/boss_felblood_kaelthas.cpp
@@ -15,13 +15,6 @@
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-/* ScriptData
-SDName: Boss_Felblood_Kaelthas
-SD%Complete: 80
-SDComment: Normal and Heroic Support. Issues: Arcane Spheres do not initially follow targets.
-SDCategory: Magisters' Terrace
-EndScriptData */
-
#include "ScriptMgr.h"
#include "GameObject.h"
#include "InstanceScript.h"
@@ -29,661 +22,497 @@ EndScriptData */
#include "MotionMaster.h"
#include "ObjectAccessor.h"
#include "ScriptedCreature.h"
+#include "SpellAuraEffects.h"
+#include "SpellScript.h"
#include "TemporarySummon.h"
enum Says
{
- SAY_AGGRO = 0, //This yell should be done when the room is cleared. For now, set it as a movelineofsight yell.
- SAY_PHOENIX = 1,
- SAY_FLAMESTRIKE = 2,
- SAY_GRAVITY_LAPSE = 3,
- SAY_TIRED = 4,
- SAY_RECAST_GRAVITY = 5,
- SAY_DEATH = 6
+ // Kael'thas Sunstrider
+ SAY_INTRO_1 = 0,
+ SAY_INTRO_2 = 1,
+ SAY_GRAVITY_LAPSE_1 = 2,
+ SAY_GRAVITY_LAPSE_2 = 3,
+ SAY_POWER_FEEDBACK = 4,
+ SAY_SUMMON_PHOENIX = 5,
+ SAY_ANNOUNCE_PYROBLAST = 6,
+ SAY_FLAME_STRIKE = 7,
+ SAY_DEATH = 8
};
-
enum Spells
{
- // Phase 1 spells
- SPELL_FIREBALL_NORMAL = 44189, // Deals 2700-3300 damage at current target
- SPELL_FIREBALL_HEROIC = 46164, // 4950-6050
-
- SPELL_PHOENIX = 44194, // Summons a phoenix (Doesn't work?)
- SPELL_PHOENIX_BURN = 44197, // A spell Phoenix uses to damage everything around
- SPELL_REBIRTH_DMG = 44196, // DMG if a Phoenix rebirth happen
-
- SPELL_FLAMESTRIKE1_NORMAL = 44190, // Damage part
- SPELL_FLAMESTRIKE1_HEROIC = 46163, // Heroic damage part
- SPELL_FLAMESTRIKE2 = 44191, // Flamestrike indicator before the damage
- SPELL_FLAMESTRIKE3 = 44192, // Summons the trigger + animation (projectile)
-
- SPELL_SHOCK_BARRIER = 46165, // Heroic only; 10k damage shield, followed by Pyroblast
- SPELL_PYROBLAST = 36819, // Heroic only; 45-55k fire damage
-
-// Phase 2 spells
- SPELL_GRAVITY_LAPSE_INITIAL = 44224, // Cast at the beginning of every Gravity Lapse
- SPELL_GRAVITY_LAPSE_CHANNEL = 44251, // Channeled; blue beam animation to every enemy in range
- SPELL_TELEPORT_CENTER = 44218, // Should teleport people to the center. Requires DB entry in spell_target_position.
- SPELL_GRAVITY_LAPSE_FLY = 44227, // Hastens flyspeed and allows flying for 1 minute. For some reason removes 44226.
- SPELL_GRAVITY_LAPSE_DOT = 44226, // Knocks up in the air and applies a 300 DPS DoT.
- SPELL_ARCANE_SPHERE_PASSIVE = 44263, // Passive auras on Arcane Spheres
- SPELL_POWER_FEEDBACK = 44233 // Stuns him, making him take 50% more damage for 10 seconds. Cast after Gravity Lapse
+ // Kael'thas Sunstrider
+ SPELL_FIREBALL = 44189,
+ SPELL_GRAVITY_LAPSE_CENTER_TELEPORT = 44218,
+ SPELL_GRAVITY_LAPSE_LEFT_TELEPORT = 44219,
+ SPELL_GRAVITY_LAPSE_FRONT_LEFT_TELEPORT = 44220,
+ SPELL_GRAVITY_LAPSE_FRONT_TELEPORT = 44221,
+ SPELL_GRAVITY_LAPSE_FRONT_RIGHT_TELEPORT = 44222,
+ SPELL_GRAVITY_LAPSE_RIGHT_TELEPORT = 44223,
+ SPELL_GRAVITY_LAPSE_INITIAL = 44224,
+ SPELL_GRAVITY_LAPSE_FLY = 44227,
+ SPELL_GRAVITY_LAPSE_BEAM_VISUAL_PERIODIC = 44251,
+ SPELL_SUMMON_ARCANE_SPHERE = 44265,
+ SPELL_POWER_FEEDBACK = 44233,
+ SPELL_FLAME_STRIKE = 46162,
+ SPELL_SHOCK_BARRIER = 46165,
+ SPELL_PYROBLAST = 36819,
+ SPELL_PHOENIX = 44194,
+ SPELL_EMOTE_TALK_EXCLAMATION = 48348,
+ SPELL_EMOTE_POINT = 48349,
+ SPELL_EMOTE_ROAR = 48350,
+ SPELL_CLEAR_FLIGHT = 44232,
+ SPELL_QUITE_SUICIDE = 3617, // Serverside spell
+
+ // Flame Strike
+ SPELL_FLAME_STRIKE_DUMMY = 44191,
+ SPELL_FLAME_STRIKE_DAMAGE = 44190,
+
+ // Phoenix
+ SPELL_REBIRTH = 44196,
+ SPELL_BURN = 44197,
+ SPELL_EMBER_BLAST = 44199,
+ SPELL_SUMMON_PHOENIX_EGG = 44195, // Serverside spell
+ SPELL_FULL_HEAL = 17683
};
-enum Creatures
+uint32 gravityLapseTeleportSpells[] =
{
- CREATURE_PHOENIX = 24674,
- CREATURE_PHOENIX_EGG = 24675,
- CREATURE_ARCANE_SPHERE = 24708
+ SPELL_GRAVITY_LAPSE_LEFT_TELEPORT,
+ SPELL_GRAVITY_LAPSE_FRONT_LEFT_TELEPORT,
+ SPELL_GRAVITY_LAPSE_FRONT_TELEPORT,
+ SPELL_GRAVITY_LAPSE_FRONT_RIGHT_TELEPORT,
+ SPELL_GRAVITY_LAPSE_RIGHT_TELEPORT
};
+#define SPELL_GRAVITY_LAPSE_DAMAGE DUNGEON_MODE<uint32>(49887, 44226)
-/** Locations **/
-float KaelLocations[3][2]=
+enum Events
{
- {148.744659f, 181.377426f},
- {140.823883f, 195.403046f},
- {156.574188f, 195.650482f},
+ // Kael'thas Sunstrider
+ EVENT_TALK_INTRO_1 = 1,
+ EVENT_TALK_INTRO_2,
+ EVENT_LAUGH_EMOTE,
+ EVENT_FINISH_INTRO,
+ EVENT_FIREBALL,
+ EVENT_FLAME_STRIKE,
+ EVENT_SHOCK_BARRIER,
+ EVENT_PYROBLAST,
+ EVENT_PHOENIX,
+ EVENT_PREPARE_GRAVITY_LAPSE,
+ EVENT_GRAVITY_LAPSE_CENTER_TELEPORT,
+ EVENT_GRAVITY_LAPSE,
+ EVENT_GRAVITY_LAPSE_BEAM_VISUAL_PERIODIC,
+ EVENT_SUMMON_ARCANE_SPHERE,
+ EVENT_POWER_FEEDBACK,
+ EVENT_TALK_NEXT_GRAVITY_LAPSE,
+ EVENT_EMOTE_TALK_EXCLAMATION,
+ EVENT_EMOTE_POINT,
+ EVENT_EMOTE_ROAR,
+ EVENT_QUITE_SUICIDE,
+
+ // Phoenix
+ EVENT_ATTACK_PLAYERS,
+ EVENT_HATCH_FROM_EGG,
+ EVENT_REBIRTH,
+ EVENT_PREPARE_REENGAGE
};
-#define LOCATION_Z -16.727455f
-
-class boss_felblood_kaelthas : public CreatureScript
+enum Phases
{
-public:
- boss_felblood_kaelthas() : CreatureScript("boss_felblood_kaelthas") { }
+ PHASE_INTRO = 0,
+ PHASE_ONE = 1,
+ PHASE_TWO = 2,
+ PHASE_OUTRO = 3
+};
- CreatureAI* GetAI(Creature* c) const override
- {
- return GetMagistersTerraceAI<boss_felblood_kaelthasAI>(c);
- }
+class GravityElapseKnockupEvent : public BasicEvent
+{
+ public:
+ GravityElapseKnockupEvent(Unit* caster, uint32 difficultySpellId) : _caster(caster), _difficultySpellId(difficultySpellId) { }
- struct boss_felblood_kaelthasAI : public ScriptedAI
- {
- boss_felblood_kaelthasAI(Creature* creature) : ScriptedAI(creature)
+ bool Execute(uint64 /*time*/, uint32 /*diff*/) override
{
- Initialize();
- instance = creature->GetInstanceScript();
+ _caster->CastSpell(_caster, _difficultySpellId);
+ _caster->CastSpell(_caster, SPELL_GRAVITY_LAPSE_FLY);
+ return true;
}
+ private:
+ Unit* _caster;
+ uint32 _difficultySpellId;
+};
- void Initialize()
- {
- /// @todo Timers
- FireballTimer = 0;
- PhoenixTimer = 10000;
- FlameStrikeTimer = 25000;
- CombatPulseTimer = 0;
-
- PyroblastTimer = 60000;
-
- GravityLapseTimer = 0;
- GravityLapsePhase = 0;
-
- FirstGravityLapse = true;
- HasTaunted = false;
-
- Phase = 0;
- }
-
- InstanceScript* instance;
-
- uint32 FireballTimer;
- uint32 PhoenixTimer;
- uint32 FlameStrikeTimer;
- uint32 CombatPulseTimer;
-
- //Heroic only
- uint32 PyroblastTimer;
+struct boss_felblood_kaelthas : public BossAI
+{
+ boss_felblood_kaelthas(Creature* creature) : BossAI(creature, DATA_KAELTHAS_SUNSTRIDER)
+ {
+ Initialize();
+ }
- uint32 GravityLapseTimer;
- uint32 GravityLapsePhase;
- // 0 = No Gravity Lapse
- // 1 = Casting Gravity Lapse visual
- // 2 = Teleported people to self
- // 3 = Knocked people up in the air
- // 4 = Applied an aura that allows them to fly, channeling visual, relased Arcane Orbs.
+ void Initialize()
+ {
+ _gravityLapseTargetCount = 0;
+ _firstGravityLapse = true;
+ }
- bool FirstGravityLapse;
- bool HasTaunted;
+ void JustEngagedWith(Unit* /*who*/) override
+ {
+ _JustEngagedWith();
+ events.SetPhase(PHASE_ONE);
+ events.ScheduleEvent(EVENT_FIREBALL, 1ms, 0, PHASE_ONE);
+ events.ScheduleEvent(EVENT_FLAME_STRIKE, 44s, 0, PHASE_ONE);
+ events.ScheduleEvent(EVENT_PHOENIX, 12s, 0, PHASE_ONE);
+ if (IsHeroic())
+ events.ScheduleEvent(EVENT_SHOCK_BARRIER, 1min + 1s, 0, PHASE_ONE);
+ }
- uint8 Phase;
- // 0 = Not started
- // 1 = Fireball; Summon Phoenix; Flamestrike
- // 2 = Gravity Lapses
+ void Reset() override
+ {
+ _Reset();
+ Initialize();
+ if (instance->GetData(DATA_KAELTHAS_INTRO_STATE) != DONE)
+ me->SetImmuneToPC(true);
+ }
- void Reset() override
- {
- Initialize();
+ void JustDied(Unit* /*killer*/) override
+ {
+ // No _JustDied() here because otherwise we would reset the events which will trigger the death sequence twice.
+ instance->SetBossState(DATA_KAELTHAS_SUNSTRIDER, DONE);
+ }
- instance->SetBossState(DATA_KAELTHAS, NOT_STARTED);
- }
+ void EnterEvadeMode(EvadeReason why) override
+ {
+ DoCastAOE(SPELL_CLEAR_FLIGHT, true);
+ _EnterEvadeMode();
+ summons.DespawnAll();
+ events.Reset();
+ me->SetReactState(REACT_AGGRESSIVE);
+ me->ReleaseFocus();
+ BossAI::EnterEvadeMode(why);
+ }
- void JustDied(Unit* /*killer*/) override
+ void DamageTaken(Unit* attacker, uint32 &damage) override
+ {
+ // Checking for lethal damage first so we trigger the outro phase without triggering phase two in case of oneshot attacks
+ if (damage >= me->GetHealth() && !events.IsInPhase(PHASE_OUTRO))
{
+ me->AttackStop();
+ me->SetReactState(REACT_PASSIVE);
+ me->InterruptNonMeleeSpells(true);
+ me->RemoveAurasDueToSpell(SPELL_POWER_FEEDBACK);
+ summons.DespawnAll();
+ DoCastAOE(SPELL_CLEAR_FLIGHT);
Talk(SAY_DEATH);
-
- instance->SetBossState(DATA_KAELTHAS, DONE);
-
- // Enable the Translocation Orb Exit
- if (GameObject* escapeOrb = ObjectAccessor::GetGameObject(*me, instance->GetGuidData(DATA_ESCAPE_ORB)))
- escapeOrb->RemoveFlag(GO_FLAG_NOT_SELECTABLE);
- }
-
- void DamageTaken(Unit* /*done_by*/, uint32 &damage) override
- {
- if (damage > me->GetHealth())
- RemoveGravityLapse(); // Remove Gravity Lapse so that players fall to ground if they kill him when in air.
- }
-
- void JustEngagedWith(Unit* /*who*/) override
- {
- instance->SetBossState(DATA_KAELTHAS, IN_PROGRESS);
- }
-
- void MoveInLineOfSight(Unit* who) override
-
- {
- if (!HasTaunted && me->IsWithinDistInMap(who, 40.0f))
- {
- Talk(SAY_AGGRO);
- HasTaunted = true;
- }
-
- ScriptedAI::MoveInLineOfSight(who);
- }
-
- void SetThreatList(Creature* summonedUnit)
- {
- if (!summonedUnit)
- return;
-
- for (auto* ref : me->GetThreatManager().GetUnsortedThreatList())
- {
- Unit* unit = ref->GetVictim();
- if (unit && unit->IsAlive())
- AddThreat(unit, ref->GetThreat(), summonedUnit);
- }
+ events.SetPhase(PHASE_OUTRO);
+ events.ScheduleEvent(EVENT_EMOTE_TALK_EXCLAMATION, 1s, 0, PHASE_OUTRO);
+ events.ScheduleEvent(EVENT_EMOTE_POINT, 3s + 800ms, 0, PHASE_OUTRO);
+ events.ScheduleEvent(EVENT_EMOTE_ROAR, 7s + 400ms, 0, PHASE_OUTRO);
+ events.ScheduleEvent(EVENT_EMOTE_ROAR, 10s, 0, PHASE_OUTRO);
+ events.ScheduleEvent(EVENT_QUITE_SUICIDE, 11s, 0, PHASE_OUTRO);
}
- void TeleportPlayersToSelf()
+ // Phase two checks. Skip phase two if we are in the outro already
+ if (me->HealthBelowPctDamaged(50, damage) && !events.IsInPhase(PHASE_TWO) && !events.IsInPhase(PHASE_OUTRO))
{
- me->UpdatePosition(KaelLocations[0][0], KaelLocations[0][1], LOCATION_Z, 0.0f);
- for (auto const& pair : me->GetCombatManager().GetPvECombatRefs())
- {
- Unit* unit = pair.second->GetOther(me);
- if (unit->GetTypeId() == TYPEID_PLAYER)
- unit->CastSpell(unit, SPELL_TELEPORT_CENTER, true);
- }
- DoCast(me, SPELL_TELEPORT_CENTER, true);
+ events.SetPhase(PHASE_TWO);
+ events.ScheduleEvent(EVENT_PREPARE_GRAVITY_LAPSE, 1ms, 0, PHASE_TWO);
}
- void CastGravityLapseKnockUp()
- {
- for (auto const& pair : me->GetCombatManager().GetPvECombatRefs())
- {
- Unit* unit = pair.second->GetOther(me);
- if (unit->GetTypeId() == TYPEID_PLAYER)
- {
- CastSpellExtraArgs args;
- args.TriggerFlags = TRIGGERED_FULL_MASK;
- args.OriginalCaster = me->GetGUID();
- unit->CastSpell(unit, SPELL_GRAVITY_LAPSE_DOT, args);
- }
- }
- }
-
- void CastGravityLapseFly() // Use Fly Packet hack for now as players can't cast "fly" spells unless in map 530. Has to be done a while after they get knocked into the air...
- {
- for (auto const& pair : me->GetCombatManager().GetPvECombatRefs())
- {
- Unit* unit = pair.second->GetOther(me);
- if (unit->GetTypeId() == TYPEID_PLAYER)
- {
- // Also needs an exception in spell system.
- CastSpellExtraArgs args;
- args.TriggerFlags = TRIGGERED_FULL_MASK;
- args.OriginalCaster = me->GetGUID();
- unit->CastSpell(unit, SPELL_GRAVITY_LAPSE_FLY, args);
- unit->SetCanFly(true);
- }
- }
- }
+ // Kael'thas may only kill himself via Quite Suicide
+ if (damage >= me->GetHealth() && attacker != me)
+ damage = me->GetHealth() - 1;
+ }
- void RemoveGravityLapse()
+ void SetData(uint32 type, uint32 /*data*/) override
+ {
+ if (type == DATA_KAELTHAS_INTRO)
{
- for (auto const& pair : me->GetCombatManager().GetPvECombatRefs())
- {
- Unit* unit = pair.second->GetOther(me);
- if (unit->GetTypeId() == TYPEID_PLAYER)
- {
- unit->RemoveAurasDueToSpell(SPELL_GRAVITY_LAPSE_FLY);
- unit->RemoveAurasDueToSpell(SPELL_GRAVITY_LAPSE_DOT);
- unit->SetCanFly(false);
- }
- }
+ events.SetPhase(PHASE_INTRO);
+ events.ScheduleEvent(EVENT_TALK_INTRO_1, 6s, 0, PHASE_INTRO);
}
+ }
- void UpdateAI(uint32 diff) override
+ void SpellHitTarget(Unit* target, SpellInfo const* spell) override
+ {
+ switch (spell->Id)
{
- //Return since we have no target
- if (!UpdateVictim())
- return;
-
- switch (Phase)
- {
- case 0:
- {
- // *Heroic mode only:
- if (IsHeroic())
- {
- if (PyroblastTimer <= diff)
- {
- me->InterruptSpell(CURRENT_CHANNELED_SPELL);
- me->InterruptSpell(CURRENT_GENERIC_SPELL);
- DoCast(me, SPELL_SHOCK_BARRIER, true);
- DoCastVictim(SPELL_PYROBLAST);
- PyroblastTimer = 60000;
- } else PyroblastTimer -= diff;
- }
-
- if (FireballTimer <= diff)
- {
- DoCastVictim(SPELL_FIREBALL_NORMAL);
- FireballTimer = urand(2000, 6000);
- } else FireballTimer -= diff;
-
- if (PhoenixTimer <= diff)
- {
- Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 1);
-
- uint8 random = urand(1, 2);
- float x = KaelLocations[random][0];
- float y = KaelLocations[random][1];
-
- Creature* Phoenix = me->SummonCreature(CREATURE_PHOENIX, x, y, LOCATION_Z, 0, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 60000);
- if (Phoenix)
- {
- Phoenix->RemoveUnitFlag(UnitFlags(UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_NON_ATTACKABLE));
- SetThreatList(Phoenix);
- Phoenix->AI()->AttackStart(target);
- }
-
- Talk(SAY_PHOENIX);
-
- PhoenixTimer = 60000;
- } else PhoenixTimer -= diff;
-
- if (FlameStrikeTimer <= diff)
- {
- if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true))
- {
- me->InterruptSpell(CURRENT_CHANNELED_SPELL);
- me->InterruptSpell(CURRENT_GENERIC_SPELL);
- DoCast(target, SPELL_FLAMESTRIKE3, true);
- Talk(SAY_FLAMESTRIKE);
- }
- FlameStrikeTimer = urand(15000, 25000);
- } else FlameStrikeTimer -= diff;
-
- // Below 50%
- if (HealthBelowPct(50))
- {
- me->ApplySpellImmune(0, IMMUNITY_EFFECT, SPELL_EFFECT_INTERRUPT_CAST, true);
- me->StopMoving();
- me->GetMotionMaster()->Clear();
- me->GetMotionMaster()->MoveIdle();
- GravityLapseTimer = 0;
- GravityLapsePhase = 0;
- Phase = 1;
- }
-
- DoMeleeAttackIfReady();
- }
+ case SPELL_GRAVITY_LAPSE_INITIAL:
+ DoCast(target, gravityLapseTeleportSpells[_gravityLapseTargetCount], true);
+ target->m_Events.AddEventAtOffset(new GravityElapseKnockupEvent(target, SPELL_GRAVITY_LAPSE_DAMAGE), 400ms);
+ _gravityLapseTargetCount++;
break;
-
- case 1:
- {
- if (GravityLapseTimer <= diff)
- {
- switch (GravityLapsePhase)
- {
- case 0:
- if (FirstGravityLapse) // Different yells at 50%, and at every following Gravity Lapse
- {
- Talk(SAY_GRAVITY_LAPSE);
- FirstGravityLapse = false;
-
- instance->SetData(DATA_KAELTHAS_STATUES, 1);
- }
- else
- Talk(SAY_RECAST_GRAVITY);
-
- DoCast(me, SPELL_GRAVITY_LAPSE_INITIAL);
- GravityLapseTimer = 2000 + diff;// Don't interrupt the visual spell
- GravityLapsePhase = 1;
- break;
-
- case 1:
- TeleportPlayersToSelf();
- GravityLapseTimer = 1000;
- GravityLapsePhase = 2;
- break;
-
- case 2:
- CastGravityLapseKnockUp();
- GravityLapseTimer = 1000;
- GravityLapsePhase = 3;
- break;
-
- case 3:
- CastGravityLapseFly();
- GravityLapseTimer = 30000;
- GravityLapsePhase = 4;
-
- for (uint8 i = 0; i < 3; ++i)
- {
- Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0);
-
- Creature* Orb = DoSpawnCreature(CREATURE_ARCANE_SPHERE, 5, 5, 0, 0, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 30000);
- if (Orb && target)
- {
- Orb->SetSpeedRate(MOVE_RUN, 0.5f);
- AddThreat(target, 1000000.0f, Orb);
- Orb->AI()->AttackStart(target);
- }
- }
-
- DoCast(me, SPELL_GRAVITY_LAPSE_CHANNEL);
- break;
-
- case 4:
- me->InterruptNonMeleeSpells(false);
- Talk(SAY_TIRED);
- DoCast(me, SPELL_POWER_FEEDBACK);
- RemoveGravityLapse();
- GravityLapseTimer = 10000;
- GravityLapsePhase = 0;
- break;
- }
- } else GravityLapseTimer -= diff;
- }
+ case SPELL_CLEAR_FLIGHT:
+ target->RemoveAurasDueToSpell(SPELL_GRAVITY_LAPSE_FLY);
+ target->RemoveAurasDueToSpell(SPELL_GRAVITY_LAPSE_DAMAGE);
+ break;
+ default:
break;
- }
}
- };
-};
-
-class npc_felkael_flamestrike : public CreatureScript
-{
-public:
- npc_felkael_flamestrike() : CreatureScript("npc_felkael_flamestrike") { }
-
- CreatureAI* GetAI(Creature* c) const override
- {
- return GetMagistersTerraceAI<npc_felkael_flamestrikeAI>(c);
}
- struct npc_felkael_flamestrikeAI : public ScriptedAI
+ void JustSummoned(Creature* summon) override
{
- npc_felkael_flamestrikeAI(Creature* creature) : ScriptedAI(creature)
- {
- Initialize();
- }
+ summons.Summon(summon);
- void Initialize()
+ switch (summon->GetEntry())
{
- FlameStrikeTimer = 5000;
+ case NPC_ARCANE_SPHERE:
+ if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 70.0f, true, true))
+ summon->GetMotionMaster()->MoveFollow(target, 0.0f, 0.0f);
+ break;
+ case NPC_FLAME_STRIKE:
+ summon->CastSpell(summon, SPELL_FLAME_STRIKE_DUMMY);
+ summon->DespawnOrUnsummon(15s);
+ break;
+ default:
+ break;
}
+ }
- uint32 FlameStrikeTimer;
-
- void Reset() override
- {
- Initialize();
-
- me->AddUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
- me->SetFaction(FACTION_MONSTER);
+ void UpdateAI(uint32 diff) override
+ {
+ if (!UpdateVictim() && !events.IsInPhase(PHASE_INTRO))
+ return;
- DoCast(me, SPELL_FLAMESTRIKE2, true);
- }
+ events.Update(diff);
- void JustEngagedWith(Unit* /*who*/) override { }
- void MoveInLineOfSight(Unit* /*who*/) override { }
+ if (me->HasUnitState(UNIT_STATE_CASTING))
+ return;
- void UpdateAI(uint32 diff) override
+ while (uint32 eventId = events.ExecuteEvent())
{
- if (FlameStrikeTimer <= diff)
+ switch (eventId)
{
- DoCast(me, SPELL_FLAMESTRIKE1_NORMAL, true);
- me->KillSelf();
- } else FlameStrikeTimer -= diff;
+ case EVENT_TALK_INTRO_1:
+ Talk(SAY_INTRO_1);
+ me->SetEmoteState(EMOTE_STATE_TALK);
+ events.ScheduleEvent(EVENT_TALK_INTRO_2, 20s + 600ms, 0, PHASE_INTRO);
+ events.ScheduleEvent(EVENT_LAUGH_EMOTE, 15s + 600ms, 0, PHASE_INTRO);
+ break;
+ case EVENT_TALK_INTRO_2:
+ Talk(SAY_INTRO_2);
+ events.ScheduleEvent(EVENT_FINISH_INTRO, 15s + 500ms, 0, PHASE_INTRO);
+ break;
+ case EVENT_LAUGH_EMOTE:
+ me->HandleEmoteCommand(EMOTE_ONESHOT_LAUGH_NO_SHEATHE);
+ break;
+ case EVENT_FINISH_INTRO:
+ me->SetEmoteState(EMOTE_ONESHOT_NONE);
+ me->SetImmuneToPC(false);
+ break;
+ case EVENT_FIREBALL:
+ DoCastVictim(SPELL_FIREBALL);
+ events.Repeat(2s + 500ms);
+ break;
+ case EVENT_FLAME_STRIKE:
+ Talk(SAY_FLAME_STRIKE);
+ if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 40.0f, true, 0))
+ DoCast(target, SPELL_FLAME_STRIKE);
+ events.Repeat(44s);
+ break;
+ case EVENT_SHOCK_BARRIER:
+ Talk(SAY_ANNOUNCE_PYROBLAST);
+ DoCastSelf(SPELL_SHOCK_BARRIER);
+ events.RescheduleEvent(EVENT_FIREBALL, 2s + 500ms, 0, PHASE_ONE);
+ events.ScheduleEvent(EVENT_PYROBLAST, 2s, 0, PHASE_ONE);
+ events.Repeat(1min);
+ break;
+ case EVENT_PYROBLAST:
+ if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 40.0f, true, 0))
+ DoCast(target, SPELL_PYROBLAST);
+ break;
+ case EVENT_PHOENIX:
+ Talk(SAY_SUMMON_PHOENIX);
+ DoCastSelf(SPELL_PHOENIX);
+ events.Repeat(45s);
+ break;
+ case EVENT_PREPARE_GRAVITY_LAPSE:
+ Talk(_firstGravityLapse ? SAY_GRAVITY_LAPSE_1 : SAY_GRAVITY_LAPSE_2);
+ _firstGravityLapse = false;
+ me->SetReactState(REACT_PASSIVE);
+ me->AttackStop();
+ me->GetMotionMaster()->Clear();
+ events.ScheduleEvent(EVENT_GRAVITY_LAPSE_CENTER_TELEPORT, 1s, 0, PHASE_TWO);
+ break;
+ case EVENT_GRAVITY_LAPSE_CENTER_TELEPORT:
+ DoCastSelf(SPELL_GRAVITY_LAPSE_CENTER_TELEPORT);
+ events.ScheduleEvent(EVENT_GRAVITY_LAPSE, 1s, 0, PHASE_TWO);
+ break;
+ case EVENT_GRAVITY_LAPSE:
+ _gravityLapseTargetCount = 0;
+ DoCastAOE(SPELL_GRAVITY_LAPSE_INITIAL);
+ events.ScheduleEvent(EVENT_SUMMON_ARCANE_SPHERE, 4s, 0, PHASE_TWO);
+ events.ScheduleEvent(EVENT_GRAVITY_LAPSE_BEAM_VISUAL_PERIODIC, 5s, 0, PHASE_TWO);
+ events.ScheduleEvent(EVENT_POWER_FEEDBACK, 35s, 0, PHASE_TWO);
+ break;
+ case EVENT_GRAVITY_LAPSE_BEAM_VISUAL_PERIODIC:
+ DoCastAOE(SPELL_GRAVITY_LAPSE_BEAM_VISUAL_PERIODIC);
+ break;
+ case EVENT_SUMMON_ARCANE_SPHERE:
+ for (uint8 i = 0; i < 3; i++)
+ DoCastSelf(SPELL_SUMMON_ARCANE_SPHERE, true);
+ break;
+ case EVENT_POWER_FEEDBACK:
+ Talk(SAY_POWER_FEEDBACK);
+ DoCastAOE(SPELL_CLEAR_FLIGHT);
+ DoCastSelf(SPELL_POWER_FEEDBACK);
+ summons.DespawnEntry(NPC_ARCANE_SPHERE);
+ events.ScheduleEvent(EVENT_PREPARE_GRAVITY_LAPSE, 11s, 0, PHASE_TWO);
+ break;
+ case EVENT_EMOTE_TALK_EXCLAMATION:
+ DoCastSelf(SPELL_EMOTE_TALK_EXCLAMATION);
+ break;
+ case EVENT_EMOTE_POINT:
+ DoCastSelf(SPELL_EMOTE_POINT);
+ break;
+ case EVENT_EMOTE_ROAR:
+ DoCastSelf(SPELL_EMOTE_ROAR);
+ break;
+ case EVENT_QUITE_SUICIDE:
+ DoCastSelf(SPELL_QUITE_SUICIDE);
+ break;
+ default:
+ break;
+ }
}
- };
+ }
+
+private:
+ uint8 _gravityLapseTargetCount;
+ bool _firstGravityLapse;
};
-class npc_felkael_phoenix : public CreatureScript
+struct npc_felblood_kaelthas_phoenix : public ScriptedAI
{
-public:
- npc_felkael_phoenix() : CreatureScript("npc_felkael_phoenix") { }
-
- CreatureAI* GetAI(Creature* c) const override
+ npc_felblood_kaelthas_phoenix(Creature* creature) : ScriptedAI(creature), _instance(creature->GetInstanceScript())
{
- return GetMagistersTerraceAI<npc_felkael_phoenixAI>(c);
+ Initialize();
}
- struct npc_felkael_phoenixAI : public ScriptedAI
+ void Initialize()
{
- npc_felkael_phoenixAI(Creature* creature) : ScriptedAI(creature)
- {
- Initialize();
- instance = creature->GetInstanceScript();
- }
-
- void Initialize()
- {
- BurnTimer = 2000;
- Death_Timer = 3000;
- Rebirth = false;
- FakeDeath = false;
- }
-
- InstanceScript* instance;
- uint32 BurnTimer;
- uint32 Death_Timer;
- bool Rebirth;
- bool FakeDeath;
+ me->SetReactState(REACT_PASSIVE);
+ _isInEgg = false;
+ }
- void Reset() override
- {
- me->RemoveUnitFlag(UnitFlags(UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_NON_ATTACKABLE));
- me->SetDisableGravity(true);
- DoCast(me, SPELL_PHOENIX_BURN, true);
- Initialize();
- }
+ void IsSummonedBy(Unit* /*summoner*/) override
+ {
+ DoZoneInCombat();
+ DoCastSelf(SPELL_BURN);
+ DoCastSelf(SPELL_REBIRTH);
+ _events.ScheduleEvent(EVENT_ATTACK_PLAYERS, 2s);
+ }
- void JustEngagedWith(Unit* /*who*/) override { }
+ void JustEngagedWith(Unit* /*who*/) override { }
- void DamageTaken(Unit* /*killer*/, uint32 &damage) override
+ void DamageTaken(Unit* /*attacker*/, uint32 &damage) override
+ {
+ if (damage >= me->GetHealth())
{
- if (damage < me->GetHealth())
- return;
-
- //Prevent glitch if in fake death
- if (FakeDeath)
- {
- damage = 0;
- return;
- }
- //Don't really die in all phases of Kael'Thas
- if (instance->GetBossState(DATA_KAELTHAS) == 0)
+ if (!_isInEgg)
{
- //prevent death
- damage = 0;
- FakeDeath = true;
-
- me->InterruptNonMeleeSpells(false);
- me->SetHealth(0);
- me->StopMoving();
- me->RemoveAllAurasOnDeath();
- me->ModifyAuraState(AURA_STATE_WOUNDED_20_PERCENT, false);
- me->ModifyAuraState(AURA_STATE_WOUNDED_25_PERCENT, false);
- me->ModifyAuraState(AURA_STATE_WOUNDED_35_PERCENT, false);
- me->ModifyAuraState(AURA_STATE_WOUND_HEALTH_20_80, false);
+ me->AttackStop();
+ me->SetReactState(REACT_PASSIVE);
+ me->RemoveAllAuras();
me->AddUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
- me->ClearAllReactives();
- me->SetTarget(ObjectGuid::Empty);
- me->GetMotionMaster()->Clear();
- me->GetMotionMaster()->MoveIdle();
- me->SetStandState(UNIT_STAND_STATE_DEAD);
- }
- }
-
- void JustDied(Unit* /*killer*/) override
- {
- me->SummonCreature(CREATURE_PHOENIX_EGG, 0.0f, 0.0f, 0.0f, 0.0f, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 45000);
- }
-
- void UpdateAI(uint32 diff) override
- {
- //If we are fake death, we cast revbirth and after that we kill the phoenix to spawn the egg.
- if (FakeDeath)
- {
- if (!Rebirth)
+ DoCastSelf(SPELL_EMBER_BLAST);
+ // DoCastSelf(SPELL_SUMMON_PHOENIX_EGG); -- We do a manual summon for now. Feel free to move it to spelleffect_dbc
+ if (Creature* egg = DoSummon(NPC_PHOENIX_EGG, me->GetPosition(), 0))
{
- DoCast(me, SPELL_REBIRTH_DMG);
- Rebirth = true;
+ if (Creature* kaelthas = _instance->GetCreature(DATA_KAELTHAS_SUNSTRIDER))
+ {
+ kaelthas->AI()->JustSummoned(egg);
+ _eggGUID = egg->GetGUID();
+ }
}
- if (Death_Timer <= diff)
- {
- me->SummonCreature(CREATURE_PHOENIX_EGG, 0.0f, 0.0f, 0.0f, 0.0f, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 45000);
- me->DisappearAndDie();
- Rebirth = false;
- } else Death_Timer -= diff;
+ _events.ScheduleEvent(EVENT_HATCH_FROM_EGG, 15s);
+ _isInEgg = true;
}
-
- if (!UpdateVictim())
- return;
-
- if (BurnTimer <= diff)
- {
- //spell Burn should possible do this, but it doesn't, so do this for now.
- uint16 dmg = urand(1650, 2050);
- Unit::DealDamage(me, me, dmg, nullptr, DOT, SPELL_SCHOOL_MASK_FIRE, nullptr, false);
- BurnTimer += 2000;
- } BurnTimer -= diff;
-
- DoMeleeAttackIfReady();
+ damage = me->GetHealth() - 1;
}
- };
-};
-class npc_felkael_phoenix_egg : public CreatureScript
-{
-public:
- npc_felkael_phoenix_egg() : CreatureScript("npc_felkael_phoenix_egg") { }
+ }
- CreatureAI* GetAI(Creature* c) const override
+ void SummonedCreatureDies(Creature* /*summon*/, Unit* /*killer*/) override
{
- return GetMagistersTerraceAI<npc_felkael_phoenix_eggAI>(c);
+ // Egg has been destroyed within 15 seconds so we lose the phoenix.
+ me->DespawnOrUnsummon();
}
- struct npc_felkael_phoenix_eggAI : public ScriptedAI
+ void UpdateAI(uint32 diff) override
{
- npc_felkael_phoenix_eggAI(Creature* creature) : ScriptedAI(creature)
- {
- Initialize();
- }
-
- void Initialize()
- {
- HatchTimer = 10000;
- }
-
- uint32 HatchTimer;
+ if (!UpdateVictim())
+ return;
- void Reset() override
- {
- Initialize();
- }
-
- void JustEngagedWith(Unit* /*who*/) override { }
- void MoveInLineOfSight(Unit* /*who*/) override { }
+ _events.Update(diff);
+ if (me->HasUnitState(UNIT_STATE_CASTING))
+ return;
- void UpdateAI(uint32 diff) override
+ while (uint32 eventId = _events.ExecuteEvent())
{
- if (HatchTimer <= diff)
+ switch (eventId)
{
- me->SummonCreature(CREATURE_PHOENIX, 0.0f, 0.0f, 0.0f, 0.0f, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 60000);
- me->KillSelf();
- } else HatchTimer -= diff;
+ case EVENT_ATTACK_PLAYERS:
+ me->SetReactState(REACT_AGGRESSIVE);
+ break;
+ case EVENT_HATCH_FROM_EGG:
+ if (Creature* egg = ObjectAccessor::GetCreature(*me, _eggGUID))
+ egg->DespawnOrUnsummon();
+ me->RemoveAllAuras();
+ _events.ScheduleEvent(EVENT_REBIRTH, 2s);
+ break;
+ case EVENT_REBIRTH:
+ DoCastSelf(SPELL_REBIRTH);
+ _events.ScheduleEvent(EVENT_PREPARE_REENGAGE, 2s);
+ break;
+ case EVENT_PREPARE_REENGAGE:
+ _isInEgg = false;
+ DoCastSelf(SPELL_FULL_HEAL);
+ DoCastSelf(SPELL_BURN);
+ me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
+ _events.ScheduleEvent(EVENT_ATTACK_PLAYERS, 2s);
+ break;
+ default:
+ break;
+ }
}
- };
+
+ DoMeleeAttackIfReady();
+ }
+private:
+ InstanceScript* _instance;
+ EventMap _events;
+ bool _isInEgg;
+ ObjectGuid _eggGUID;
};
-class npc_arcane_sphere : public CreatureScript
+class spell_felblood_kaelthas_flame_strike : public AuraScript
{
-public:
- npc_arcane_sphere() : CreatureScript("npc_arcane_sphere") { }
+ PrepareAuraScript(spell_felblood_kaelthas_flame_strike);
- CreatureAI* GetAI(Creature* c) const override
+ bool Validate(SpellInfo const* /*spellInfo*/) override
{
- return GetMagistersTerraceAI<npc_arcane_sphereAI>(c);
+ return ValidateSpellInfo({ SPELL_FLAME_STRIKE_DAMAGE });
}
- struct npc_arcane_sphereAI : public ScriptedAI
+ void AfterRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
{
- npc_arcane_sphereAI(Creature* creature) : ScriptedAI(creature) { Reset(); }
-
- uint32 DespawnTimer;
- uint32 ChangeTargetTimer;
-
- void Reset() override
- {
- DespawnTimer = 30000;
- ChangeTargetTimer = urand(6000, 12000);
-
- me->AddUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
- me->SetDisableGravity(true);
- me->SetFaction(FACTION_MONSTER);
- DoCast(me, SPELL_ARCANE_SPHERE_PASSIVE, true);
- }
-
- void JustEngagedWith(Unit* /*who*/) override { }
-
- void UpdateAI(uint32 diff) override
- {
- if (DespawnTimer <= diff)
- me->KillSelf();
- else
- DespawnTimer -= diff;
-
- //Return since we have no target
- if (!UpdateVictim())
- return;
-
- if (ChangeTargetTimer <= diff)
- {
- if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true))
- {
- ResetThreatList();
- AddThreat(target, 1000000.0f);
- AttackStart(target);
- }
+ if (Unit* target = GetTarget())
+ target->CastSpell(target, SPELL_FLAME_STRIKE_DAMAGE);
+ }
- ChangeTargetTimer = urand(5000, 15000);
- } else ChangeTargetTimer -= diff;
- }
- };
+ void Register() override
+ {
+ AfterEffectRemove += AuraEffectRemoveFn(spell_felblood_kaelthas_flame_strike::AfterRemove, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL);
+ }
};
void AddSC_boss_felblood_kaelthas()
{
- new boss_felblood_kaelthas();
- new npc_arcane_sphere();
- new npc_felkael_phoenix();
- new npc_felkael_phoenix_egg();
- new npc_felkael_flamestrike();
+ RegisterMagistersTerraceCreatureAI(boss_felblood_kaelthas);
+ RegisterMagistersTerraceCreatureAI(npc_felblood_kaelthas_phoenix);
+ RegisterAuraScript(spell_felblood_kaelthas_flame_strike);
}
diff --git a/src/server/scripts/EasternKingdoms/MagistersTerrace/instance_magisters_terrace.cpp b/src/server/scripts/EasternKingdoms/MagistersTerrace/instance_magisters_terrace.cpp
index 314d2d8fbd7..bcd8bff620c 100644
--- a/src/server/scripts/EasternKingdoms/MagistersTerrace/instance_magisters_terrace.cpp
+++ b/src/server/scripts/EasternKingdoms/MagistersTerrace/instance_magisters_terrace.cpp
@@ -16,14 +16,16 @@
*/
#include "ScriptMgr.h"
+#include "CreatureAI.h"
#include "EventMap.h"
#include "GameObject.h"
#include "InstanceScript.h"
#include "magisters_terrace.h"
#include "Map.h"
#include "MotionMaster.h"
-#include "ScriptedCreature.h"
+#include "ObjectAccessor.h"
#include "TemporarySummon.h"
+#include <sstream>
/*
0 - Selin Fireheart
@@ -32,17 +34,24 @@
3 - Kael'thas Sunstrider
*/
+ObjectData const creatureData[] =
+{
+ { BOSS_KAELTHAS_SUNSTRIDER, DATA_KAELTHAS_SUNSTRIDER },
+ { 0, 0 } // END
+};
+
DoorData const doorData[] =
{
- { GO_SELIN_DOOR, DATA_SELIN, DOOR_TYPE_PASSAGE },
- { GO_SELIN_ENCOUNTER_DOOR, DATA_SELIN, DOOR_TYPE_ROOM },
- { GO_VEXALLUS_DOOR, DATA_VEXALLUS, DOOR_TYPE_PASSAGE },
- { GO_DELRISSA_DOOR, DATA_DELRISSA, DOOR_TYPE_PASSAGE },
- { GO_KAEL_DOOR, DATA_KAELTHAS, DOOR_TYPE_ROOM },
- { 0, 0, DOOR_TYPE_ROOM } // END
+ { GO_SELIN_DOOR, DATA_SELIN, DOOR_TYPE_PASSAGE },
+ { GO_SELIN_ENCOUNTER_DOOR, DATA_SELIN, DOOR_TYPE_ROOM },
+ { GO_VEXALLUS_DOOR, DATA_VEXALLUS, DOOR_TYPE_PASSAGE },
+ { GO_DELRISSA_DOOR, DATA_DELRISSA, DOOR_TYPE_PASSAGE },
+ { GO_ASYLUM_DOOR, DATA_KAELTHAS_SUNSTRIDER, DOOR_TYPE_ROOM },
+ { 0, 0, DOOR_TYPE_ROOM } // END
};
Position const KalecgosSpawnPos = { 164.3747f, -397.1197f, 2.151798f, 1.66219f };
+Position const KaelthasTrashGroupDistanceComparisonPos = { 150.0f, 141.0f, -14.4f };
class instance_magisters_terrace : public InstanceMapScript
{
@@ -55,9 +64,15 @@ class instance_magisters_terrace : public InstanceMapScript
{
SetHeaders(DataHeader);
SetBossNumber(EncounterCount);
+ LoadObjectData(creatureData, nullptr);
LoadDoorData(doorData);
+ Initialize();
+ }
- DelrissaDeathCount = 0;
+ void Initialize() override
+ {
+ _delrissaDeathCount = 0;
+ _kaelthasIntroState = 0;
}
uint32 GetData(uint32 type) const override
@@ -65,7 +80,9 @@ class instance_magisters_terrace : public InstanceMapScript
switch (type)
{
case DATA_DELRISSA_DEATH_COUNT:
- return DelrissaDeathCount;
+ return _delrissaDeathCount;
+ case DATA_KAELTHAS_INTRO_STATE:
+ return _kaelthasIntroState;
default:
break;
}
@@ -78,13 +95,13 @@ class instance_magisters_terrace : public InstanceMapScript
{
case DATA_DELRISSA_DEATH_COUNT:
if (data == SPECIAL)
- ++DelrissaDeathCount;
+ _delrissaDeathCount++;
else
- DelrissaDeathCount = 0;
+ _delrissaDeathCount = 0;
break;
- case DATA_KAELTHAS_STATUES:
- HandleGameObject(KaelStatue[0], data != 0);
- HandleGameObject(KaelStatue[1], data != 0);
+ case DATA_KAELTHAS_INTRO_STATE:
+ _kaelthasIntroState = data;
+ SaveToDB();
break;
default:
break;
@@ -93,6 +110,8 @@ class instance_magisters_terrace : public InstanceMapScript
void OnCreatureCreate(Creature* creature) override
{
+ InstanceScript::OnCreatureCreate(creature);
+
switch (creature->GetEntry())
{
case NPC_SELIN:
@@ -105,57 +124,70 @@ class instance_magisters_terrace : public InstanceMapScript
case NPC_HUMAN_KALECGOS:
KalecgosGUID = creature->GetGUID();
break;
+ case NPC_COILSKAR_WITCH:
+ case NPC_SUNBLADE_WARLOCK:
+ case NPC_SUNBLADE_MAGE_GUARD:
+ case NPC_SISTER_OF_TORMENT:
+ case NPC_ETHEREUM_SMUGGLER:
+ case NPC_SUNBLADE_BLOOD_KNIGHT:
+ if (creature->GetDistance(KaelthasTrashGroupDistanceComparisonPos) < 10.0f)
+ _kaelthasPreTrashGUIDs.insert(creature->GetGUID());
default:
break;
}
}
- void OnGameObjectCreate(GameObject* go) override
+ void OnUnitDeath(Unit* unit) override
{
- switch (go->GetEntry())
+ if (unit->GetTypeId() != TYPEID_UNIT)
+ return;
+
+ switch (unit->GetEntry())
{
- case GO_VEXALLUS_DOOR:
- case GO_SELIN_DOOR:
- case GO_SELIN_ENCOUNTER_DOOR:
- case GO_DELRISSA_DOOR:
- case GO_KAEL_DOOR:
- AddDoor(go, true);
- break;
- case GO_KAEL_STATUE_1:
- KaelStatue[0] = go->GetGUID();
- break;
- case GO_KAEL_STATUE_2:
- KaelStatue[1] = go->GetGUID();
- break;
- case GO_ESCAPE_ORB:
- EscapeOrbGUID = go->GetGUID();
+ case NPC_COILSKAR_WITCH:
+ case NPC_SUNBLADE_WARLOCK:
+ case NPC_SUNBLADE_MAGE_GUARD:
+ case NPC_SISTER_OF_TORMENT:
+ case NPC_ETHEREUM_SMUGGLER:
+ case NPC_SUNBLADE_BLOOD_KNIGHT:
+ if (_kaelthasPreTrashGUIDs.find(unit->GetGUID()) != _kaelthasPreTrashGUIDs.end())
+ {
+ _kaelthasPreTrashGUIDs.erase(unit->GetGUID());
+ if (_kaelthasPreTrashGUIDs.size() == 0)
+ {
+ if (Creature* kaelthas = GetCreature(DATA_KAELTHAS_SUNSTRIDER))
+ {
+ kaelthas->AI()->SetData(DATA_KAELTHAS_INTRO, IN_PROGRESS);
+ SetData(DATA_KAELTHAS_INTRO_STATE, DONE);
+ }
+ }
+ }
break;
default:
break;
}
}
- void OnGameObjectRemove(GameObject* go) override
+ void OnGameObjectCreate(GameObject* go) override
{
+ InstanceScript::OnGameObjectCreate(go);
+
switch (go->GetEntry())
{
- case GO_VEXALLUS_DOOR:
- case GO_SELIN_DOOR:
- case GO_SELIN_ENCOUNTER_DOOR:
- case GO_DELRISSA_DOOR:
- case GO_KAEL_DOOR:
- AddDoor(go, false);
+ case GO_KAEL_STATUE_1:
+ case GO_KAEL_STATUE_2:
+ _statueGUIDs.push_back(go->GetGUID());
break;
default:
break;
}
}
- void ProcessEvent(WorldObject* /*obj*/, uint32 eventId) override
+ void ProcessEvent(WorldObject* obj, uint32 eventId) override
{
if (eventId == EVENT_SPAWN_KALECGOS)
- if (!instance->GetCreature(KalecgosGUID) && Events.Empty())
- Events.ScheduleEvent(EVENT_SPAWN_KALECGOS, 1min);
+ if (!ObjectAccessor::GetCreature(*obj, KalecgosGUID) && Events.Empty())
+ Events.ScheduleEvent(EVENT_SPAWN_KALECGOS, Minutes(1));
}
void Update(uint32 diff) override
@@ -163,13 +195,11 @@ class instance_magisters_terrace : public InstanceMapScript
Events.Update(diff);
if (Events.ExecuteEvent() == EVENT_SPAWN_KALECGOS)
- {
if (Creature* kalecgos = instance->SummonCreature(NPC_KALECGOS, KalecgosSpawnPos))
{
kalecgos->GetMotionMaster()->MovePath(PATH_KALECGOS_FLIGHT, false);
kalecgos->AI()->Talk(SAY_KALECGOS_SPAWN);
}
- }
}
bool SetBossState(uint32 type, EncounterState state) override
@@ -181,7 +211,14 @@ class instance_magisters_terrace : public InstanceMapScript
{
case DATA_DELRISSA:
if (state == IN_PROGRESS)
- DelrissaDeathCount = 0;
+ _delrissaDeathCount = 0;
+ break;
+ case DATA_KAELTHAS_SUNSTRIDER:
+ if (state == NOT_STARTED)
+ {
+ for (ObjectGuid guid : _statueGUIDs)
+ HandleGameObject(guid, false);
+ }
break;
default:
break;
@@ -197,10 +234,6 @@ class instance_magisters_terrace : public InstanceMapScript
return SelinGUID;
case DATA_DELRISSA:
return DelrissaGUID;
- case DATA_KAEL_STATUE_LEFT:
- return KaelStatue[0];
- case DATA_KAEL_STATUE_RIGHT:
- return KaelStatue[1];
case DATA_ESCAPE_ORB:
return EscapeOrbGUID;
default:
@@ -209,14 +242,26 @@ class instance_magisters_terrace : public InstanceMapScript
return ObjectGuid::Empty;
}
+ void WriteSaveDataMore(std::ostringstream& data) override
+ {
+ data << _kaelthasIntroState;
+ }
+
+ void ReadSaveDataMore(std::istringstream& data) override
+ {
+ data >> _kaelthasIntroState;
+ }
+
protected:
EventMap Events;
ObjectGuid SelinGUID;
ObjectGuid DelrissaGUID;
- ObjectGuid KaelStatue[2];
ObjectGuid EscapeOrbGUID;
ObjectGuid KalecgosGUID;
- uint32 DelrissaDeathCount;
+ GuidVector _statueGUIDs;
+ GuidSet _kaelthasPreTrashGUIDs;
+ uint8 _delrissaDeathCount;
+ uint8 _kaelthasIntroState;
};
InstanceScript* GetInstanceScript(InstanceMap* map) const override
diff --git a/src/server/scripts/EasternKingdoms/MagistersTerrace/magisters_terrace.h b/src/server/scripts/EasternKingdoms/MagistersTerrace/magisters_terrace.h
index 2a0b8217635..9bfada78af2 100644
--- a/src/server/scripts/EasternKingdoms/MagistersTerrace/magisters_terrace.h
+++ b/src/server/scripts/EasternKingdoms/MagistersTerrace/magisters_terrace.h
@@ -27,26 +27,47 @@ uint32 const EncounterCount = 4;
enum MTDataTypes
{
+ // Encounter states
DATA_SELIN,
DATA_VEXALLUS,
DATA_DELRISSA,
- DATA_KAELTHAS,
-
- DATA_KAEL_STATUE_LEFT,
- DATA_KAEL_STATUE_RIGHT,
+ DATA_KAELTHAS_SUNSTRIDER,
+ // Encounter related
+ DATA_KAELTHAS_INTRO,
DATA_DELRISSA_DEATH_COUNT,
- DATA_KAELTHAS_STATUES,
+
+ // Additional data
+ DATA_KAELTHAS_INTRO_STATE,
+
DATA_ESCAPE_ORB
};
enum MTCreatureIds
{
- NPC_SELIN = 24723,
- NPC_DELRISSA = 24560,
- NPC_FEL_CRYSTAL = 24722,
- NPC_KALECGOS = 24844,
- NPC_HUMAN_KALECGOS = 24848
+ // Bosses
+ BOSS_KAELTHAS_SUNSTRIDER = 24664,
+
+ // Encounter related
+ /*Kael'thas Sunstrider*/
+ NPC_ARCANE_SPHERE = 24708,
+ NPC_FLAME_STRIKE = 24666,
+ NPC_PHOENIX = 24674,
+ NPC_PHOENIX_EGG = 24675,
+
+ NPC_SELIN = 24723,
+ NPC_DELRISSA = 24560,
+ NPC_FEL_CRYSTAL = 24722,
+ NPC_KALECGOS = 24844,
+
+ // Event related
+ NPC_HUMAN_KALECGOS = 24848,
+ NPC_COILSKAR_WITCH = 24696,
+ NPC_SUNBLADE_WARLOCK = 24686,
+ NPC_SUNBLADE_MAGE_GUARD = 24683,
+ NPC_SISTER_OF_TORMENT = 24697,
+ NPC_ETHEREUM_SMUGGLER = 24698,
+ NPC_SUNBLADE_BLOOD_KNIGHT = 24684,
};
enum MTGameObjectIds
@@ -55,7 +76,7 @@ enum MTGameObjectIds
GO_SELIN_DOOR = 187979,
GO_SELIN_ENCOUNTER_DOOR = 188065,
GO_DELRISSA_DOOR = 187770,
- GO_KAEL_DOOR = 188064,
+ GO_ASYLUM_DOOR = 188064,
GO_KAEL_STATUE_1 = 188165,
GO_KAEL_STATUE_2 = 188166,
GO_ESCAPE_ORB = 188173
@@ -82,4 +103,6 @@ inline AI* GetMagistersTerraceAI(T* obj)
return GetInstanceAI<AI>(obj, MGTScriptName);
}
+#define RegisterMagistersTerraceCreatureAI(ai_name) RegisterCreatureAIWithFactory(ai_name, GetMagistersTerraceAI)
+
#endif