diff --git a/data/sql/updates/pending_db_world/rev_1740880295787400500.sql b/data/sql/updates/pending_db_world/rev_1740880295787400500.sql new file mode 100644 index 000000000..b2c1af887 --- /dev/null +++ b/data/sql/updates/pending_db_world/rev_1740880295787400500.sql @@ -0,0 +1,2 @@ +-- +UPDATE `creature_text` SET `Type` = 41, `BroadcastTextId` = 24548 WHERE `CreatureId` = 25038 AND `GroupId` = 6; diff --git a/src/server/scripts/EasternKingdoms/SunwellPlateau/boss_felmyst.cpp b/src/server/scripts/EasternKingdoms/SunwellPlateau/boss_felmyst.cpp index ed1b5408c..2c29cce45 100644 --- a/src/server/scripts/EasternKingdoms/SunwellPlateau/boss_felmyst.cpp +++ b/src/server/scripts/EasternKingdoms/SunwellPlateau/boss_felmyst.cpp @@ -66,12 +66,14 @@ enum Misc // Misc ACTION_START_EVENT = 1, POINT_GROUND = 1, - POINT_AIR = 2, - POINT_AIR_BREATH_START1 = 3, - POINT_AIR_BREATH_END1 = 4, - POINT_AIR_BREATH_START2 = 5, - POINT_AIR_BREATH_END2 = 6, - POINT_MISC = 7, + POINT_TAKEOFF = 2, + POINT_AIR = 3, + POINT_AIR_UP = 4, + POINT_LANE = 5, + POINT_AIR_BREATH_START1 = 6, + POINT_AIR_BREATH_END = 7, + POINT_AIR_BREATH_START2 = 8, + POINT_MISC = 9, POINT_KALECGOS = 1, @@ -79,9 +81,28 @@ enum Misc GROUP_BREATH = 1, NPC_FOG_TRIGGER = 23472, - NPC_KALECGOS_FELMYST = 24844 // Same as Magister's Terrace + NPC_KALECGOS_FELMYST = 24844, // Same as Magister's Terrace + NPC_WORLD_TRIGGER_RIGHT = 25358 }; +const Position LeftSideLanes[3] = +{ + { 1494.745f, 704.0001f, 50.084652f, 4.7472f }, // top + { 1469.923f, 703.23914f, 50.08592f, 4.7472f }, // middle + { 1446.5154f, 701.5184f, 50.085438f, 4.7472f } // bottom +}; + +const Position RightSideLanes[3] = +{ + { 1492.82f, 515.668f, 50.0833f, 1.4486f }, // top + { 1466.7322f, 515.5953f, 50.571518f, 1.4486f }, // middle + { 1441.64f, 520.52f, 50.0833f, 1.4486f } // bottom +}; + +const Position RightSide = { 1458.5555f, 502.1995f, 59.899513f, 1.605702f }; +const Position LeftSide = { 1469.0642f, 729.5854f, 59.823853f, 4.6774f }; +const Position LandingPos = { 1476.77f, 665.094f, 20.6423f }; + class CorruptTriggers : public BasicEvent { public: @@ -103,7 +124,7 @@ private: struct boss_felmyst : public BossAI { - boss_felmyst(Creature* creature) : BossAI(creature, DATA_FELMYST) { } + boss_felmyst(Creature* creature) : BossAI(creature, DATA_FELMYST), _currentLane(0), _strafeCount(0) { } void InitializeAI() override { @@ -127,25 +148,24 @@ struct boss_felmyst : public BossAI void Reset() override { BossAI::Reset(); - me->m_Events.KillAllEvents(false); instance->DoRemoveAurasDueToSpellOnPlayers(SPELL_FOG_OF_CORRUPTION_CHARM); + _currentLane = 0; + _strafeCount = 0; + me->SetCombatMovement(false); } void JustEngagedWith(Unit* who) override { BossAI::JustEngagedWith(who); - me->m_Events.AddEventAtOffset([&] { - Talk(YELL_BERSERK); - DoCastSelf(SPELL_BERSERK, true); - }, 10min); + ScheduleEnrageTimer(SPELL_BERSERK, 10min, YELL_BERSERK); me->GetMotionMaster()->Clear(); Position landPos = who->GetPosition(); me->m_Events.AddEventAtOffset([&, landPos] { me->GetMotionMaster()->MoveLand(POINT_GROUND, landPos); - }, 2s); + }, 1s); } void KilledUnit(Unit* victim) override @@ -166,153 +186,139 @@ struct boss_felmyst : public BossAI kalec->GetMotionMaster()->MovePoint(POINT_KALECGOS, 1474.2347f, 624.0703f, 29.32589f, false, true); } + void ScheduleGroundAbilities() + { + ScheduleTimedEvent(7500ms, [&] { + DoCastVictim(SPELL_CLEAVE); + }, 7500ms); + + ScheduleTimedEvent(12s, [&] { + DoCastVictim(SPELL_CORROSION); + }, 20s); + + ScheduleTimedEvent(18s, [&] { + Talk(YELL_BREATH); + DoCastSelf(SPELL_GAS_NOVA); + }, 20s); + + ScheduleTimedEvent(25s, [&] { + DoCastRandomTarget(SPELL_ENCAPSULATE_CHANNEL, 0, 50.0f); + }, 25s); + + me->m_Events.AddEventAtOffset([&] { + Talk(YELL_TAKEOFF); + scheduler.CancelAll(); + me->SetReactState(REACT_PASSIVE); + me->SetTarget(); + me->AttackStop(); + me->SetCombatMovement(false); + me->GetMotionMaster()->Clear(); + me->GetMotionMaster()->MoveIdle(); + me->SetCanFly(true); + me->SetDisableGravity(true); + me->SendMovementFlagUpdate(); + SetInvincibility(true); + me->HandleEmoteCommand(EMOTE_ONESHOT_LIFTOFF); + me->GetMotionMaster()->MovePoint(POINT_TAKEOFF, me->GetPositionX(), me->GetPositionY(), me->GetPositionZ() + 20.0f); + }, 1min); + } + void MovementInform(uint32 type, uint32 point) override { if (type != EFFECT_MOTION_TYPE && type != POINT_MOTION_TYPE) return; - if (point == POINT_GROUND) + switch (point) { - if (!me->HasAura(SPELL_NOXIOUS_FUMES)) - DoCastSelf(SPELL_NOXIOUS_FUMES, true); + case POINT_GROUND: - me->HandleEmoteCommand(EMOTE_ONESHOT_LAND); - me->SetCanFly(false); - me->SetDisableGravity(false); - me->SendMovementFlagUpdate(); - SetInvincibility(false); + if (!me->HasAura(SPELL_NOXIOUS_FUMES)) + DoCastSelf(SPELL_NOXIOUS_FUMES, true); - me->m_Events.AddEventAtOffset([&] { - me->SetReactState(REACT_AGGRESSIVE); - - if (me->GetVictim()) - me->SetTarget(me->GetVictim()->GetGUID()); - - me->ResumeChasingVictim(); - }, 2s); - - ScheduleTimedEvent(7500ms, [&] { - DoCastVictim(SPELL_CLEAVE); - }, 7500ms); - - ScheduleTimedEvent(12s, [&] { - DoCastVictim(SPELL_CORROSION); - }, 20s); - - ScheduleTimedEvent(18s, [&] { - DoCastSelf(SPELL_GAS_NOVA); - }, 20s); - - ScheduleTimedEvent(25s, [&] { - DoCastRandomTarget(SPELL_ENCAPSULATE_CHANNEL, 0, 50.0f); - }, 25s); - - me->m_Events.AddEventAtOffset([&] { - scheduler.CancelAll(); - me->SetReactState(REACT_PASSIVE); - me->StopMoving(); - me->GetMotionMaster()->Clear(); + me->GetMotionMaster()->MoveIdle(); + me->HandleEmoteCommand(EMOTE_ONESHOT_LAND); + me->SetCanFly(false); + me->SetDisableGravity(false); + me->SendMovementFlagUpdate(); + SetInvincibility(false); me->m_Events.AddEventAtOffset([&] { - ScheduleFlightSequence(); - }, 1s); - }, 1min); - } - else if (point == POINT_AIR_BREATH_START1) - { - me->SetTarget(); - me->SetFacingTo(4.71f); - ScheduleFlightAbilities(point); - } - else if (point == POINT_AIR_BREATH_END1) - { - me->RemoveAurasDueToSpell(SPELL_FELMYST_SPEED_BURST); - me->SetFacingTo(1.57f); - if (!scheduler.IsGroupScheduled(GROUP_BREATH)) - { + me->SetReactState(REACT_AGGRESSIVE); + + if (me->GetVictim()) + me->SetTarget(me->GetVictim()->GetGUID()); + + me->ResumeChasingVictim(); + me->SetCombatMovement(true); + }, 5s); + + ScheduleGroundAbilities(); + break; + case POINT_TAKEOFF: me->m_Events.AddEventAtOffset([&] { - Position pos = { 1447.0f + urand(0, 2) * 25.0f, 515.0f, 50.0f, 1.57f }; - me->GetMotionMaster()->MovePoint(POINT_AIR_BREATH_START2, pos, false, true); + me->CastCustomSpell(SPELL_SUMMON_DEMONIC_VAPOR, SPELLVALUE_MAX_TARGETS, 1, me, true); + }, 5s); + + me->m_Events.AddEventAtOffset([&] { + me->CastCustomSpell(SPELL_SUMMON_DEMONIC_VAPOR, SPELLVALUE_MAX_TARGETS, 1, me, true); + }, 17s); + + scheduler.Schedule(27s, GROUP_BREATH, [this](TaskContext) + { + me->GetMotionMaster()->MovePoint(POINT_AIR_UP, RightSide); + }); + break; + case POINT_AIR_UP: + me->m_Events.AddEventAtOffset([&] { + if (_strafeCount >= 3) + { + _strafeCount = 0; + me->GetMotionMaster()->MoveLand(POINT_GROUND, LandingPos); + return; + } + + ++_strafeCount; + _currentLane = urand(0, 2); + if (me->FindNearestCreature(NPC_WORLD_TRIGGER_RIGHT, 30.0f)) + me->GetMotionMaster()->MovePoint(POINT_LANE, RightSideLanes[_currentLane], false); + else + me->GetMotionMaster()->MovePoint(POINT_LANE, LeftSideLanes[_currentLane], false); }, 2s); - } + break; + case POINT_LANE: + Talk(EMOTE_BREATH); + me->m_Events.AddEventAtOffset([&] { + me->m_Events.AddEvent(new CorruptTriggers(me), me->m_Events.CalculateTime(0)); + me->m_Events.AddEvent(new CorruptTriggers(me), me->m_Events.CalculateTime(500)); + me->m_Events.AddEvent(new CorruptTriggers(me), me->m_Events.CalculateTime(1000)); + me->m_Events.AddEvent(new CorruptTriggers(me), me->m_Events.CalculateTime(1500)); + me->m_Events.AddEvent(new CorruptTriggers(me), me->m_Events.CalculateTime(2000)); + me->m_Events.AddEvent(new CorruptTriggers(me), me->m_Events.CalculateTime(2500)); + me->m_Events.AddEvent(new CorruptTriggers(me), me->m_Events.CalculateTime(3000)); + me->m_Events.AddEvent(new CorruptTriggers(me), me->m_Events.CalculateTime(3500)); + me->m_Events.AddEvent(new CorruptTriggers(me), me->m_Events.CalculateTime(4000)); + }, 5s); + + me->m_Events.AddEventAtOffset([&] { + DoCastSelf(SPELL_FELMYST_SPEED_BURST, true); + + if (me->FindNearestCreature(NPC_WORLD_TRIGGER_RIGHT, 30.0f)) + me->GetMotionMaster()->MovePoint(POINT_AIR_BREATH_END, LeftSideLanes[_currentLane], false); + else + me->GetMotionMaster()->MovePoint(POINT_AIR_BREATH_END, RightSideLanes[_currentLane], false); + }, 5s); + break; + case POINT_AIR_BREATH_END: + me->RemoveAurasDueToSpell(SPELL_FELMYST_SPEED_BURST); + + me->m_Events.AddEventAtOffset([&] { + if (me->FindNearestCreature(NPC_WORLD_TRIGGER_RIGHT, 30.0f)) + me->GetMotionMaster()->MovePoint(POINT_AIR_UP, RightSide, false); + else + me->GetMotionMaster()->MovePoint(POINT_AIR_UP, LeftSide, false); + }, 2s); + break; } - else if (point == POINT_AIR_BREATH_START2) - { - me->SetTarget(); - me->SetFacingTo(1.57f); - ScheduleFlightAbilities(point); - } - else if (point == POINT_AIR_BREATH_END2) - { - me->RemoveAurasDueToSpell(SPELL_FELMYST_SPEED_BURST); - me->SetFacingTo(4.71f); - } - } - - void ScheduleFlightSequence() - { - Talk(YELL_TAKEOFF); - me->SetTarget(); - me->HandleEmoteCommand(EMOTE_ONESHOT_LIFTOFF); - me->SetDisableGravity(true); - me->SendMovementFlagUpdate(); - SetInvincibility(true); - - me->m_Events.AddEventAtOffset([&] { - me->GetMotionMaster()->MovePoint(POINT_AIR, me->GetPositionX(), me->GetPositionY(), me->GetPositionZ() + 15.0f, false, true); - }, 2s); - - me->m_Events.AddEventAtOffset([&] { - me->CastCustomSpell(SPELL_SUMMON_DEMONIC_VAPOR, SPELLVALUE_MAX_TARGETS, 1, me, true); - }, 8s); - - me->m_Events.AddEventAtOffset([&] { - me->CastCustomSpell(SPELL_SUMMON_DEMONIC_VAPOR, SPELLVALUE_MAX_TARGETS, 1, me, true); - }, 21s); - - scheduler.Schedule(35s, GROUP_BREATH, [this](TaskContext) - { - Position pos = { 1447.0f + urand(0, 2) * 25.0f, 705.0f, 50.0f, 4.71f }; - me->GetMotionMaster()->MovePoint(POINT_AIR_BREATH_START1, pos, false, true); - }); - - scheduler.Schedule(72s, GROUP_BREATH, [this](TaskContext) - { - Position pos = { 1447.0f + urand(0, 2) * 25.0f, 705.0f, 50.0f, 4.71f }; - me->GetMotionMaster()->MovePoint(POINT_AIR_BREATH_START1, pos, false, true); - }); - - me->m_Events.AddEventAtOffset([&] { - me->GetMotionMaster()->MovePoint(POINT_GROUND, 1500.0f, 552.8f, 26.52f, false, true); - }, 86s); - } - - void ScheduleFlightAbilities(uint8 point) - { - me->m_Events.AddEventAtOffset([&] { - Talk(EMOTE_BREATH); - }, 2s); - - me->m_Events.AddEventAtOffset([&] { - Talk(YELL_BREATH); - me->m_Events.AddEvent(new CorruptTriggers(me), me->m_Events.CalculateTime(0)); - me->m_Events.AddEvent(new CorruptTriggers(me), me->m_Events.CalculateTime(500)); - me->m_Events.AddEvent(new CorruptTriggers(me), me->m_Events.CalculateTime(1000)); - me->m_Events.AddEvent(new CorruptTriggers(me), me->m_Events.CalculateTime(1500)); - me->m_Events.AddEvent(new CorruptTriggers(me), me->m_Events.CalculateTime(2000)); - me->m_Events.AddEvent(new CorruptTriggers(me), me->m_Events.CalculateTime(2500)); - me->m_Events.AddEvent(new CorruptTriggers(me), me->m_Events.CalculateTime(3000)); - me->m_Events.AddEvent(new CorruptTriggers(me), me->m_Events.CalculateTime(3500)); - me->m_Events.AddEvent(new CorruptTriggers(me), me->m_Events.CalculateTime(4000)); - }, 5s); - - me->m_Events.AddEventAtOffset([this, point] { - DoCastSelf(SPELL_FELMYST_SPEED_BURST, true); - if (point == POINT_AIR_BREATH_START1) - me->GetMotionMaster()->MovePoint(POINT_AIR_BREATH_END1, me->GetPositionX(), me->GetPositionY() - 200.0f, me->GetPositionZ() + 5.0f, false, true); - else if (point == POINT_AIR_BREATH_START2) - me->GetMotionMaster()->MovePoint(POINT_AIR_BREATH_END2, me->GetPositionX(), me->GetPositionY() + 200.0f, me->GetPositionZ() + 5.0f, false, true); - }, 5s); } void StartIntro() @@ -346,6 +352,10 @@ struct boss_felmyst : public BossAI if (!me->HasUnitMovementFlag(MOVEMENTFLAG_DISABLE_GRAVITY)) DoMeleeAttackIfReady(); } + + private: + uint8 _currentLane = 0; + uint8 _strafeCount = 0; }; struct npc_demonic_vapor : public NullCreatureAI