diff options
author | Ovah <dreadkiller@gmx.de> | 2019-01-28 15:01:20 -0300 |
---|---|---|
committer | Shauren <shauren.trinity@gmail.com> | 2021-11-23 00:21:42 +0100 |
commit | 3847d7b2778c0799b8942f2ed70ee40771d28533 (patch) | |
tree | e89df6e38e1e72f5891a1f1d589a8622fcd645db /src | |
parent | 4af28946263be5cd2631f97f92eb2ebe86d901cb (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')
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 |