From 08580defd0c3a1699590cbad1aa4e981f46b04c4 Mon Sep 17 00:00:00 2001 From: Skjalf <47818697+Nyeriah@users.noreply.github.com> Date: Sat, 27 Nov 2021 13:33:50 -0300 Subject: [PATCH] refactor(Scripts/Onyxia): Update Onyxia's script (#9371) --- .../rev_1637948987614040500.sql | 7 + .../Kalimdor/OnyxiasLair/boss_onyxia.cpp | 988 ++++++++---------- .../OnyxiasLair/instance_onyxias_lair.cpp | 88 +- .../Kalimdor/OnyxiasLair/onyxias_lair.h | 2 + 4 files changed, 479 insertions(+), 606 deletions(-) create mode 100644 data/sql/updates/pending_db_world/rev_1637948987614040500.sql diff --git a/data/sql/updates/pending_db_world/rev_1637948987614040500.sql b/data/sql/updates/pending_db_world/rev_1637948987614040500.sql new file mode 100644 index 000000000..3c33f9732 --- /dev/null +++ b/data/sql/updates/pending_db_world/rev_1637948987614040500.sql @@ -0,0 +1,7 @@ +INSERT INTO `version_db_world` (`sql_rev`) VALUES ('1637948987614040500'); + +UPDATE `creature_template` SET `flags_extra` = `flags_extra` |128, `ScriptName` = '' WHERE `entry` = 12758; +UPDATE `creature_template` SET `ScriptName` = '' WHERE `entry` = 11262; + +-- Remove taunt immunity +UPDATE `creature_template` SET `flags_extra` = `flags_extra` &~ 256 WHERE `entry` = 10184; diff --git a/src/server/scripts/Kalimdor/OnyxiasLair/boss_onyxia.cpp b/src/server/scripts/Kalimdor/OnyxiasLair/boss_onyxia.cpp index 32ec94a44..31c57deba 100644 --- a/src/server/scripts/Kalimdor/OnyxiasLair/boss_onyxia.cpp +++ b/src/server/scripts/Kalimdor/OnyxiasLair/boss_onyxia.cpp @@ -21,7 +21,7 @@ #include "SpellInfo.h" #include "onyxias_lair.h" -enum // Spells +enum Spells { SPELL_WINGBUFFET = 18500, SPELL_FLAMEBREATH = 18435, @@ -47,7 +47,7 @@ enum // Spells SPELL_BREATH_NE_TO_SW = 18617, }; -enum // Events +enum Events { EVENT_SPELL_WINGBUFFET = 1, EVENT_SPELL_FLAMEBREATH = 2, @@ -73,7 +73,15 @@ enum // Events EVENT_LIFTOFF = 31, EVENT_FLY_S_TO_N = 32, EVENT_LAND = 33, - EVENT_END_MANY_WHELPS_TIME, + EVENT_END_MANY_WHELPS_TIME +}; + +enum Phases +{ + PHASE_NONE, + PHASE_GROUNDED, // Phase 1 + PHASE_AIRPHASE, // Phase 2 - Airphase - 60% health + PHASE_LANDED // Phase 3 - Landed after Airphase - 40% health }; struct sOnyxMove @@ -108,600 +116,482 @@ enum Yells EMOTE_BREATH = 4 }; -class boss_onyxia : public CreatureScript +struct boss_onyxia : public BossAI { public: - boss_onyxia() : CreatureScript("boss_onyxia") { } - - CreatureAI* GetAI(Creature* pCreature) const override + boss_onyxia(Creature* pCreature) : BossAI(pCreature, DATA_ONYXIA) { - return GetOnyxiasLairAI(pCreature); + Initialize(); } - struct boss_onyxiaAI : public ScriptedAI + void Initialize() { - boss_onyxiaAI(Creature* pCreature) : ScriptedAI(pCreature) + CurrentWP = 0; + whelpSpam = false; + whelpCount = 0; + whelpSpamTimer = 0; + bManyWhelpsAvailable = false; + } + + void SetPhase(uint8 ph) + { + events.Reset(); + Phase = ph; + switch (ph) { - m_pInstance = me->GetInstanceScript(); + case PHASE_GROUNDED: + events.ScheduleEvent(EVENT_SPELL_WINGBUFFET, urand(10000, 20000)); + events.ScheduleEvent(EVENT_SPELL_FLAMEBREATH, urand(10000, 20000)); + events.ScheduleEvent(EVENT_SPELL_TAILSWEEP, urand(15000, 20000)); + events.ScheduleEvent(EVENT_SPELL_CLEAVE, urand(2000, 5000)); + break; + case PHASE_AIRPHASE: + events.ScheduleEvent(EVENT_START_PHASE_2, 0); + break; + case PHASE_LANDED: + events.ScheduleEvent(EVENT_START_PHASE_3, 5000); + break; } + } - EventMap events; + void Reset() override + { + Initialize(); + SetPhase(PHASE_NONE); + me->SetReactState(REACT_AGGRESSIVE); + me->SetCanFly(false); + me->SetDisableGravity(false); + me->SetSpeed(MOVE_RUN, me->GetCreatureTemplate()->speed_run, false); + instance->DoStopTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, ACHIEV_TIMED_START_EVENT); + BossAI::Reset(); + } - InstanceScript* m_pInstance; - uint8 Phase; - int8 CurrentWP; - - bool whelpSpam; - uint8 whelpCount; - int32 whelpSpamTimer; - bool bManyWhelpsAvailable; - - void SetPhase(uint8 ph) + void DoAction(int32 param) override + { + switch (param) { - events.Reset(); - Phase = ph; - switch (ph) - { - case 0: - break; - case 1: - events.ScheduleEvent(EVENT_SPELL_WINGBUFFET, urand(10000, 20000)); - events.ScheduleEvent(EVENT_SPELL_FLAMEBREATH, urand(10000, 20000)); - events.ScheduleEvent(EVENT_SPELL_TAILSWEEP, urand(15000, 20000)); - events.ScheduleEvent(EVENT_SPELL_CLEAVE, urand(2000, 5000)); - break; - case 2: - events.ScheduleEvent(EVENT_START_PHASE_2, 0); - break; - case 3: - events.ScheduleEvent(EVENT_START_PHASE_3, 5000); - break; - } - } - - void Reset() override - { - CurrentWP = 0; - SetPhase(0); - me->SetReactState(REACT_AGGRESSIVE); - me->SetCanFly(false); - me->SetDisableGravity(false); - me->SetSpeed(MOVE_RUN, me->GetCreatureTemplate()->speed_run, false); - - whelpSpam = false; - whelpCount = 0; - whelpSpamTimer = 0; - bManyWhelpsAvailable = false; - - if (m_pInstance) - { - m_pInstance->SetData(DATA_ONYXIA, NOT_STARTED); - m_pInstance->DoStopTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, ACHIEV_TIMED_START_EVENT); - } - } - - void JustDied(Unit* /*killer*/) override - { - m_pInstance->SetData(DATA_ONYXIA, DONE); - } - - void MoveInLineOfSight(Unit* who) override - { - if (me->GetVictim() || me->GetDistance(who) > 30.0f) - { - return; - } - - if (who->GetTypeId() == TYPEID_PLAYER) - { - AttackStart(who); - } - } - - void DoAction(int32 param) override - { - switch (param) - { - case -1: - if (bManyWhelpsAvailable && m_pInstance) - { - m_pInstance->SetData(DATA_WHELP_SUMMONED, 1); - } - break; - } - } - - void BindPlayers() - { - me->GetMap()->ToInstanceMap()->PermBindAllPlayers(); - } - - void EnterCombat(Unit* /*who*/) override - { - Talk(SAY_AGGRO); - DoZoneInCombat(); - SetPhase(1); - - if (m_pInstance) - { - m_pInstance->SetData(DATA_ONYXIA, IN_PROGRESS); - m_pInstance->DoStopTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, ACHIEV_TIMED_START_EVENT); // just in case at reset some players already left the instance - m_pInstance->DoStartTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, ACHIEV_TIMED_START_EVENT); - } - BindPlayers(); - } - - void DamageTaken(Unit*, uint32& /*damage*/, DamageEffectType, SpellSchoolMask) override - { - switch (Phase) - { - case 1: - if (me->GetHealth() * 100 / me->GetMaxHealth() <= 65) - { - SetPhase(2); - } - break; - case 2: - if (me->GetHealth() * 100 / me->GetMaxHealth() <= 40) - { - me->InterruptNonMeleeSpells(false); - SetPhase(3); - } - break; - } - } - - void JustSummoned(Creature* pSummoned) override - { - if (pSummoned->GetEntry() != NPC_ONYXIAN_WHELP && pSummoned->GetEntry() != NPC_ONYXIAN_LAIR_GUARD) - { - return; - } - - if (Unit* target = pSummoned->SelectNearestTarget(300.0f)) - { - pSummoned->AI()->AttackStart(target); - DoZoneInCombat(pSummoned); - } - } - - void MovementInform(uint32 type, uint32 id) override - { - if (type != POINT_MOTION_TYPE && type != EFFECT_MOTION_TYPE) - { - return; - } - - if (id < 9) - { - if (id > 0 && Phase == 2) + case -1: + if (bManyWhelpsAvailable) { - me->SetFacingTo(OnyxiaMoveData[id].o); - me->SetSpeed(MOVE_RUN, 1.6f, false); - CurrentWP = id; - events.ScheduleEvent(EVENT_SPELL_FIREBALL_FIRST, 1000); + instance->SetData(DATA_WHELP_SUMMONED, 1); + } + break; + } + } + + void EnterCombat(Unit* who) override + { + Talk(SAY_AGGRO); + SetPhase(PHASE_GROUNDED); + + instance->DoStopTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, ACHIEV_TIMED_START_EVENT); // just in case at reset some players already left the instance + instance->DoStartTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, ACHIEV_TIMED_START_EVENT); + BossAI::EnterCombat(who); + } + + void DamageTaken(Unit*, uint32& damage, DamageEffectType, SpellSchoolMask) override + { + if (me->HealthBelowPctDamaged(65, damage) && Phase == PHASE_GROUNDED) + { + SetPhase(PHASE_AIRPHASE); + } + else if (me->HealthBelowPctDamaged(40, damage) && Phase == PHASE_AIRPHASE) + { + me->InterruptNonMeleeSpells(false); + SetPhase(PHASE_LANDED); + } + } + + void JustSummoned(Creature* summon) override + { + if (summon->GetEntry() != NPC_ONYXIAN_WHELP && summon->GetEntry() != NPC_ONYXIAN_LAIR_GUARD) + { + return; + } + + if (Unit* target = summon->SelectNearestTarget(300.0f)) + { + summon->AI()->AttackStart(target); + DoZoneInCombat(summon); + } + + summons.Summon(summon); + } + + void MovementInform(uint32 type, uint32 id) override + { + if (type != POINT_MOTION_TYPE && type != EFFECT_MOTION_TYPE) + { + return; + } + + if (id < 9) + { + if (id > 0 && Phase == PHASE_AIRPHASE) + { + me->SetFacingTo(OnyxiaMoveData[id].o); + me->SetSpeed(MOVE_RUN, 1.6f, false); + CurrentWP = id; + events.ScheduleEvent(EVENT_SPELL_FIREBALL_FIRST, 1000); + } + } + else + { + switch (id) + { + case 10: + me->SetFacingTo(OnyxiaMoveData[0].o); + events.ScheduleEvent(EVENT_LIFTOFF, 0); + break; + case 11: + me->SetFacingTo(OnyxiaMoveData[1].o); + events.ScheduleEvent(EVENT_FLY_S_TO_N, 0); + break; + case 12: + me->SetFacingTo(OnyxiaMoveData[1].o); + events.ScheduleEvent(EVENT_LAND, 0); + break; + case 13: + me->SetCanFly(false); + me->SetDisableGravity(false); + me->SetSpeed(MOVE_RUN, me->GetCreatureTemplate()->speed_run, false); + events.ScheduleEvent(EVENT_PHASE_3_ATTACK, 0); + break; + } + } + } + + void HandleWhelpSpam(const uint32 diff) + { + if (whelpSpam) + { + if (whelpCount < 40) + { + whelpSpamTimer -= diff; + if (whelpSpamTimer <= 0) + { + float angle = rand_norm() * 2 * M_PI; + float dist = rand_norm() * 4.0f; + me->CastSpell(-33.18f + cos(angle) * dist, -258.80f + sin(angle) * dist, -89.0f, 17646, true); + me->CastSpell(-32.535f + cos(angle) * dist, -170.190f + sin(angle) * dist, -89.0f, 17646, true); + whelpCount += 2; + whelpSpamTimer += 600; } } else { - switch (id) - { - case 10: - me->SetFacingTo(OnyxiaMoveData[0].o); - events.ScheduleEvent(EVENT_LIFTOFF, 0); - break; - case 11: - me->SetFacingTo(OnyxiaMoveData[1].o); - events.ScheduleEvent(EVENT_FLY_S_TO_N, 0); - break; - case 12: - me->SetFacingTo(OnyxiaMoveData[1].o); - events.ScheduleEvent(EVENT_LAND, 0); - break; - case 13: - me->SetCanFly(false); - me->SetDisableGravity(false); - me->SetSpeed(MOVE_RUN, me->GetCreatureTemplate()->speed_run, false); - events.ScheduleEvent(EVENT_PHASE_3_ATTACK, 0); - break; - } + whelpSpam = false; + whelpCount = 0; + whelpSpamTimer = 0; } } + } - void HandleWhelpSpam(const uint32 diff) + void UpdateAI(uint32 diff) override + { + if (!UpdateVictim()) { - if (whelpSpam) + return; + } + + events.Update(diff); + HandleWhelpSpam(diff); + + if (me->HasUnitState(UNIT_STATE_CASTING)) + { + return; + } + + DoMeleeAttackIfReady(); + + switch (events.ExecuteEvent()) + { + case EVENT_SPELL_WINGBUFFET: { - if (whelpCount < 40) + DoCastAOE(SPELL_WINGBUFFET); + events.RepeatEvent(urand(15000, 30000)); + break; + } + case EVENT_SPELL_FLAMEBREATH: + { + DoCastAOE(SPELL_FLAMEBREATH); + events.RepeatEvent(urand(10000, 20000)); + break; + } + case EVENT_SPELL_TAILSWEEP: + { + DoCastAOE(SPELL_TAILSWEEP); + events.RepeatEvent(urand(15000, 20000)); + break; + } + case EVENT_SPELL_CLEAVE: + { + DoCastVictim(SPELL_CLEAVE); + events.RepeatEvent(urand(2000, 5000)); + break; + } + case EVENT_START_PHASE_2: + { + me->AttackStop(); + me->SetReactState(REACT_PASSIVE); + me->StopMoving(); + DoResetThreat(); + me->GetMotionMaster()->MovePoint(10, OnyxiaMoveData[0].x, OnyxiaMoveData[0].y, OnyxiaMoveData[0].z); + break; + } + case EVENT_LIFTOFF: + { + Talk(SAY_PHASE_2_TRANS); + me->SendMeleeAttackStop(me->GetVictim()); + me->GetMotionMaster()->MoveIdle(); + me->DisableSpline(); + me->SetCanFly(true); + me->SetDisableGravity(true); + me->SetOrientation(OnyxiaMoveData[0].o); + me->SendMovementFlagUpdate(); + me->GetMotionMaster()->MoveTakeoff(11, OnyxiaMoveData[1].x + 1.0f, OnyxiaMoveData[1].y, OnyxiaMoveData[1].z, 12.0f); + bManyWhelpsAvailable = true; + + events.RescheduleEvent(EVENT_END_MANY_WHELPS_TIME, 10000); + break; + } + case EVENT_END_MANY_WHELPS_TIME: + bManyWhelpsAvailable = false; + break; + case EVENT_FLY_S_TO_N: + { + me->SetSpeed(MOVE_RUN, 2.95f, false); + me->GetMotionMaster()->MovePoint(5, OnyxiaMoveData[5].x, OnyxiaMoveData[5].y, OnyxiaMoveData[5].z); + + whelpSpam = true; + events.ScheduleEvent(EVENT_WHELP_SPAM, 90000); + events.ScheduleEvent(EVENT_SUMMON_LAIR_GUARD, 30000); + break; + } + case EVENT_SUMMON_LAIR_GUARD: + { + me->CastSpell(-101.654f, -214.491f, -80.70f, SPELL_SUMMON_LAIR_GUARD, true); + events.RepeatEvent(30000); + break; + } + case EVENT_WHELP_SPAM: + { + whelpSpam = true; + events.RepeatEvent(90000); + break; + } + case EVENT_LAND: + { + Talk(SAY_PHASE_3_TRANS); + me->SendMeleeAttackStop(me->GetVictim()); + me->GetMotionMaster()->MoveLand(13, OnyxiaMoveData[0].x + 1.0f, OnyxiaMoveData[0].y, OnyxiaMoveData[0].z, 12.0f); + DoResetThreat(); + break; + } + case EVENT_SPELL_FIREBALL_FIRST: + { + if (Unit* v = SelectTarget(SELECT_TARGET_RANDOM, 0, 200.0f, true)) { - whelpSpamTimer -= diff; - if (whelpSpamTimer <= 0) - { - float angle = rand_norm() * 2 * M_PI; - float dist = rand_norm() * 4.0f; - me->CastSpell(-33.18f + cos(angle)*dist, -258.80f + sin(angle)*dist, -89.0f, 17646, true); - me->CastSpell(-32.535f + cos(angle)*dist, -170.190f + sin(angle)*dist, -89.0f, 17646, true); - whelpCount += 2; - whelpSpamTimer += 600; - } + me->SetFacingToObject(v); + DoCast(v, SPELL_FIREBALL); + } + + events.ScheduleEvent(EVENT_SPELL_FIREBALL_SECOND, 4000); + break; + } + case EVENT_SPELL_FIREBALL_SECOND: + { + if (Unit* v = SelectTarget(SELECT_TARGET_RANDOM, 0, 200.0f, true)) + { + me->SetFacingToObject(v); + DoCast(v, SPELL_FIREBALL); + } + + uint8 rand = urand(0, 99); + if (rand < 33) + { + events.ScheduleEvent(EVENT_PHASE_2_STEP_CW, 4000); + } + else if (rand < 66) + { + events.ScheduleEvent(EVENT_PHASE_2_STEP_ACW, 4000); } else { - whelpSpam = false; - whelpCount = 0; - whelpSpamTimer = 0; + events.ScheduleEvent(EVENT_PHASE_2_STEP_ACROSS, 4000); } + break; + } + case EVENT_PHASE_2_STEP_CW: + { + uint8 newWP = CurrentWP + 1; + if (newWP > 8) + { + newWP = 1; + } + me->GetMotionMaster()->MovePoint(newWP, OnyxiaMoveData[newWP].x, OnyxiaMoveData[newWP].y, OnyxiaMoveData[newWP].z); + break; + } + case EVENT_PHASE_2_STEP_ACW: + { + uint8 newWP = CurrentWP - 1; + if (newWP < 1) + { + newWP = 8; + } + me->GetMotionMaster()->MovePoint(newWP, OnyxiaMoveData[newWP].x, OnyxiaMoveData[newWP].y, OnyxiaMoveData[newWP].z); + break; + } + case EVENT_PHASE_2_STEP_ACROSS: + { + Talk(EMOTE_BREATH); + me->SetFacingTo(OnyxiaMoveData[CurrentWP].o); + DoCastAOE(OnyxiaMoveData[CurrentWP].spellId); + events.ScheduleEvent(EVENT_SPELL_BREATH, 8250); + break; + } + case EVENT_SPELL_BREATH: + { + uint8 newWP = OnyxiaMoveData[CurrentWP].DestId; + me->SetSpeed(MOVE_RUN, 2.95f, false); + me->GetMotionMaster()->MovePoint(newWP, OnyxiaMoveData[newWP].x, OnyxiaMoveData[newWP].y, OnyxiaMoveData[newWP].z); + break; + } + case EVENT_START_PHASE_3: + { + me->SetSpeed(MOVE_RUN, 2.95f, false); + me->GetMotionMaster()->MovePoint(12, OnyxiaMoveData[1].x, OnyxiaMoveData[1].y, OnyxiaMoveData[1].z); + break; + } + case EVENT_PHASE_3_ATTACK: + { + me->SetReactState(REACT_AGGRESSIVE); + + if (Unit* target = SelectTarget(SELECT_TARGET_TOPAGGRO, 0, 0, false)) + { + AttackStart(target); + } + + DoCastAOE(SPELL_BELLOWINGROAR); + + events.ScheduleEvent(EVENT_ERUPTION, 0); + events.ScheduleEvent(EVENT_SPELL_WINGBUFFET, urand(10000, 20000)); + events.ScheduleEvent(EVENT_SPELL_FLAMEBREATH, urand(10000, 20000)); + events.ScheduleEvent(EVENT_SPELL_TAILSWEEP, urand(15000, 20000)); + events.ScheduleEvent(EVENT_SPELL_CLEAVE, urand(2000, 5000)); + events.ScheduleEvent(EVENT_SPELL_BELLOWINGROAR, 15000); + events.ScheduleEvent(EVENT_SUMMON_WHELP, 10000); + break; + } + case EVENT_SPELL_BELLOWINGROAR: + { + DoCastAOE(SPELL_BELLOWINGROAR); + events.RepeatEvent(22000); + events.ScheduleEvent(EVENT_ERUPTION, 0); + break; + } + case EVENT_ERUPTION: + { + if (Creature* trigger = me->SummonCreature(12758, *me, TEMPSUMMON_TIMED_DESPAWN, 1000)) + { + trigger->CastSpell(trigger, 17731, false); + } + break; + } + case EVENT_SUMMON_WHELP: + { + float angle = rand_norm() * 2 * M_PI; + float dist = rand_norm() * 4.0f; + me->CastSpell(-33.18f + cos(angle) * dist, -258.80f + sin(angle) * dist, -89.0f, 17646, true); + me->CastSpell(-32.535f + cos(angle) * dist, -170.190f + sin(angle) * dist, -89.0f, 17646, true); + events.RepeatEvent(30000); + break; } } - - void UpdateAI(uint32 diff) override - { - if (!UpdateVictim()) - { - return; - } - - events.Update(diff); - HandleWhelpSpam(diff); - - if (me->HasUnitState(UNIT_STATE_CASTING)) - { - return; - } - - DoMeleeAttackIfReady(); - - switch (events.ExecuteEvent()) - { - case 0: - break; - case EVENT_SPELL_WINGBUFFET: - { - me->CastSpell(me, SPELL_WINGBUFFET, false); - events.RepeatEvent(urand(15000, 30000)); - } - break; - case EVENT_SPELL_FLAMEBREATH: - { - me->CastSpell(me, SPELL_FLAMEBREATH, false); - events.RepeatEvent(urand(10000, 20000)); - } - break; - case EVENT_SPELL_TAILSWEEP: - { - me->CastSpell(me, SPELL_TAILSWEEP, false); - events.RepeatEvent(urand(15000, 20000)); - } - break; - case EVENT_SPELL_CLEAVE: - { - me->CastSpell(me->GetVictim(), SPELL_CLEAVE, false); - events.RepeatEvent(urand(2000, 5000)); - } - break; - case EVENT_START_PHASE_2: - { - me->AttackStop(); - me->SetReactState(REACT_PASSIVE); - me->StopMoving(); - DoResetThreat(); - me->GetMotionMaster()->MovePoint(10, OnyxiaMoveData[0].x, OnyxiaMoveData[0].y, OnyxiaMoveData[0].z); - } - break; - case EVENT_LIFTOFF: - { - Talk(SAY_PHASE_2_TRANS); - me->SendMeleeAttackStop(me->GetVictim()); - me->GetMotionMaster()->MoveIdle(); - me->DisableSpline(); - me->SetCanFly(true); - me->SetDisableGravity(true); - me->SetOrientation(OnyxiaMoveData[0].o); - me->SendMovementFlagUpdate(); - me->GetMotionMaster()->MoveTakeoff(11, OnyxiaMoveData[1].x + 1.0f, OnyxiaMoveData[1].y, OnyxiaMoveData[1].z, 12.0f); - bManyWhelpsAvailable = true; - - events.RescheduleEvent(EVENT_END_MANY_WHELPS_TIME, 10000); - } - break; - case EVENT_END_MANY_WHELPS_TIME: - bManyWhelpsAvailable = false; - break; - case EVENT_FLY_S_TO_N: - { - me->SetSpeed(MOVE_RUN, 2.95f, false); - me->GetMotionMaster()->MovePoint(5, OnyxiaMoveData[5].x, OnyxiaMoveData[5].y, OnyxiaMoveData[5].z); - - whelpSpam = true; - events.ScheduleEvent(EVENT_WHELP_SPAM, 90000); - events.ScheduleEvent(EVENT_SUMMON_LAIR_GUARD, 30000); - } - break; - case EVENT_SUMMON_LAIR_GUARD: - { - me->CastSpell(-101.654f, -214.491f, -80.70f, SPELL_SUMMON_LAIR_GUARD, true); - events.RepeatEvent(30000); - } - break; - case EVENT_WHELP_SPAM: - { - whelpSpam = true; - events.RepeatEvent(90000); - } - break; - case EVENT_LAND: - { - Talk(SAY_PHASE_3_TRANS); - me->SendMeleeAttackStop(me->GetVictim()); - me->GetMotionMaster()->MoveLand(13, OnyxiaMoveData[0].x + 1.0f, OnyxiaMoveData[0].y, OnyxiaMoveData[0].z, 12.0f); - DoResetThreat(); - } - break; - case EVENT_SPELL_FIREBALL_FIRST: - { - if (Unit* v = SelectTarget(SELECT_TARGET_RANDOM, 0, 200.0f, true)) - { - me->SetFacingToObject(v); - me->CastSpell(v, SPELL_FIREBALL, false); - } - - events.ScheduleEvent(EVENT_SPELL_FIREBALL_SECOND, 4000); - } - break; - case EVENT_SPELL_FIREBALL_SECOND: - { - if (Unit* v = SelectTarget(SELECT_TARGET_RANDOM, 0, 200.0f, true)) - { - me->SetFacingToObject(v); - me->CastSpell(v, SPELL_FIREBALL, false); - } - - uint8 rand = urand(0, 99); - if (rand < 33) - { - events.ScheduleEvent(EVENT_PHASE_2_STEP_CW, 4000); - } - else if (rand < 66) - { - events.ScheduleEvent(EVENT_PHASE_2_STEP_ACW, 4000); - } - else - { - events.ScheduleEvent(EVENT_PHASE_2_STEP_ACROSS, 4000); - } - } - break; - case EVENT_PHASE_2_STEP_CW: - { - uint8 newWP = CurrentWP + 1; - if (newWP > 8) - { - newWP = 1; - } - me->GetMotionMaster()->MovePoint(newWP, OnyxiaMoveData[newWP].x, OnyxiaMoveData[newWP].y, OnyxiaMoveData[newWP].z); - } - break; - case EVENT_PHASE_2_STEP_ACW: - { - uint8 newWP = CurrentWP - 1; - if (newWP < 1) - { - newWP = 8; - } - me->GetMotionMaster()->MovePoint(newWP, OnyxiaMoveData[newWP].x, OnyxiaMoveData[newWP].y, OnyxiaMoveData[newWP].z); - } - break; - case EVENT_PHASE_2_STEP_ACROSS: - { - me->SetFacingTo(OnyxiaMoveData[CurrentWP].o); - me->TextEmote("Onyxia takes in a deep breath...", nullptr, true); - me->CastSpell(me, OnyxiaMoveData[CurrentWP].spellId, false); - - events.ScheduleEvent(EVENT_SPELL_BREATH, 8250); - } - break; - case EVENT_SPELL_BREATH: - { - uint8 newWP = OnyxiaMoveData[CurrentWP].DestId; - me->SetSpeed(MOVE_RUN, 2.95f, false); - me->GetMotionMaster()->MovePoint(newWP, OnyxiaMoveData[newWP].x, OnyxiaMoveData[newWP].y, OnyxiaMoveData[newWP].z); - } - break; - case EVENT_START_PHASE_3: - { - me->SetSpeed(MOVE_RUN, 2.95f, false); - me->GetMotionMaster()->MovePoint(12, OnyxiaMoveData[1].x, OnyxiaMoveData[1].y, OnyxiaMoveData[1].z); - } - break; - case EVENT_PHASE_3_ATTACK: - { - me->SetReactState(REACT_AGGRESSIVE); - AttackStart(SelectTarget(SELECT_TARGET_TOPAGGRO, 0, 0, false)); - me->CastSpell(me, SPELL_BELLOWINGROAR, false); - - events.ScheduleEvent(EVENT_ERUPTION, 0); - events.ScheduleEvent(EVENT_SPELL_WINGBUFFET, urand(10000, 20000)); - events.ScheduleEvent(EVENT_SPELL_FLAMEBREATH, urand(10000, 20000)); - events.ScheduleEvent(EVENT_SPELL_TAILSWEEP, urand(15000, 20000)); - events.ScheduleEvent(EVENT_SPELL_CLEAVE, urand(2000, 5000)); - events.ScheduleEvent(EVENT_SPELL_BELLOWINGROAR, 15000); - events.ScheduleEvent(EVENT_SUMMON_WHELP, 10000); - } - break; - case EVENT_SPELL_BELLOWINGROAR: - { - me->CastSpell(me, SPELL_BELLOWINGROAR, false); - events.RepeatEvent(22000); - events.ScheduleEvent(EVENT_ERUPTION, 0); - } - break; - case EVENT_ERUPTION: - { - if (Creature* trigger = me->SummonCreature(12758, *me, TEMPSUMMON_TIMED_DESPAWN, 1000)) - { - trigger->CastSpell(trigger, 17731, false); - } - } - break; - case EVENT_SUMMON_WHELP: - { - float angle = rand_norm() * 2 * M_PI; - float dist = rand_norm() * 4.0f; - me->CastSpell(-33.18f + cos(angle)*dist, -258.80f + sin(angle)*dist, -89.0f, 17646, true); - me->CastSpell(-32.535f + cos(angle)*dist, -170.190f + sin(angle)*dist, -89.0f, 17646, true); - events.RepeatEvent(30000); - } - break; - } - } - - void SpellHitTarget(Unit* target, const SpellInfo* spell) override - { - if (target->IsPlayer() && spell->DurationEntry && spell->DurationEntry->ID == 328 && spell->Effects[EFFECT_1].TargetA.GetTarget() == 1 && (spell->Effects[EFFECT_1].Amplitude == 50 || spell->Effects[EFFECT_1].Amplitude == 215)) // Deep Breath - { - m_pInstance->SetData(DATA_DEEP_BREATH_FAILED, 1); - } - } - }; -}; - -class npc_onyxian_lair_guard : public CreatureScript -{ -public: - npc_onyxian_lair_guard() : CreatureScript("npc_onyxian_lair_guard") { } - - CreatureAI* GetAI(Creature* pCreature) const override - { - return GetOnyxiasLairAI(pCreature); } - struct npc_onyxian_lair_guardAI : public ScriptedAI + void SpellHitTarget(Unit* target, const SpellInfo* spell) override { - npc_onyxian_lair_guardAI(Creature* pCreature) : ScriptedAI(pCreature) + if (target->IsPlayer() && spell->DurationEntry && spell->DurationEntry->ID == 328 && spell->Effects[EFFECT_1].TargetA.GetTarget() == 1 && (spell->Effects[EFFECT_1].Amplitude == 50 || spell->Effects[EFFECT_1].Amplitude == 215)) // Deep Breath { - events.Reset(); - events.ScheduleEvent(EVENT_OLG_SPELL_BLASTNOVA, 15000); - events.ScheduleEvent(EVENT_OLG_SPELL_IGNITEWEAPON, 10000); + instance->SetData(DATA_DEEP_BREATH_FAILED, 1); + } + } + +private: + uint8 Phase; + int8 CurrentWP; + + bool whelpSpam; + uint8 whelpCount; + int32 whelpSpamTimer; + bool bManyWhelpsAvailable; +}; + +struct npc_onyxian_lair_guard : public ScriptedAI +{ +public: + npc_onyxian_lair_guard(Creature* creature) : ScriptedAI(creature) {} + + EventMap events; + + void EnterCombat(Unit* /*who*/) override + { + events.Reset(); + events.ScheduleEvent(EVENT_OLG_SPELL_BLASTNOVA, 15000); + events.ScheduleEvent(EVENT_OLG_SPELL_IGNITEWEAPON, 10000); + } + + void UpdateAI(uint32 diff) override + { + if (!UpdateVictim()) + { + return; } - EventMap events; + events.Update(diff); - void MoveInLineOfSight(Unit* who) override + if (me->HasUnitState(UNIT_STATE_CASTING)) { - if (me->GetVictim() || me->GetDistance(who) > 20.0f) - { - return; - } - - if (who->GetTypeId() == TYPEID_PLAYER) - { - AttackStart(who); - } + return; } - void UpdateAI(uint32 diff) override + switch (events.ExecuteEvent()) { - if (!UpdateVictim()) - { - return; - } - - events.Update(diff); - - if (me->HasUnitState(UNIT_STATE_CASTING)) - { - return; - } - - switch (events.ExecuteEvent()) - { - case 0: - break; - case EVENT_OLG_SPELL_BLASTNOVA: - me->CastSpell(me, SPELL_OLG_BLASTNOVA, false); - events.RepeatEvent(15000); - break; - case EVENT_OLG_SPELL_IGNITEWEAPON: - if (me->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_DISARMED)) - { - events.RepeatEvent(5000); - } - else - { - me->CastSpell(me, SPELL_OLG_IGNITEWEAPON, false); - events.RepeatEvent(urand(18000, 21000)); - } - break; - } - - if (!me->HasUnitState(UNIT_STATE_CASTING) && me->isAttackReady()) - { + case EVENT_OLG_SPELL_BLASTNOVA: + DoCastAOE(SPELL_OLG_BLASTNOVA); + events.RepeatEvent(15000); + break; + case EVENT_OLG_SPELL_IGNITEWEAPON: if (me->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_DISARMED)) { - if (me->HasAura(SPELL_OLG_IGNITEWEAPON)) - { - me->RemoveAura(SPELL_OLG_IGNITEWEAPON); - } + events.RepeatEvent(5000); + } + else + { + DoCastSelf(SPELL_OLG_IGNITEWEAPON); + events.RepeatEvent(urand(18000, 21000)); + } + break; + } + + if (!me->HasUnitState(UNIT_STATE_CASTING) && me->isAttackReady()) + { + if (me->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_DISARMED)) + { + if (me->HasAura(SPELL_OLG_IGNITEWEAPON)) + { + me->RemoveAura(SPELL_OLG_IGNITEWEAPON); } } - - DoMeleeAttackIfReady(); } - }; -}; -class npc_onyxia_whelp : public CreatureScript -{ -public: - npc_onyxia_whelp() : CreatureScript("npc_onyxia_whelp") { } - - CreatureAI* GetAI(Creature* pCreature) const override - { - return GetOnyxiasLairAI(pCreature); + DoMeleeAttackIfReady(); } - - struct npc_onyxia_whelpAI : public ScriptedAI - { - npc_onyxia_whelpAI(Creature* pCreature) : ScriptedAI(pCreature) {} - - void MoveInLineOfSight(Unit* who) override - { - if (me->GetVictim() || me->GetDistance(who) > 20.0f) - { - return; - } - - if (who->GetTypeId() == TYPEID_PLAYER) - { - AttackStart(who); - } - } - }; -}; - -class npc_onyxia_trigger : public CreatureScript -{ -public: - npc_onyxia_trigger() : CreatureScript("npc_onyxia_trigger") { } - - CreatureAI* GetAI(Creature* pCreature) const override - { - return GetOnyxiasLairAI(pCreature); - } - - struct npc_onyxia_triggerAI : public ScriptedAI - { - npc_onyxia_triggerAI(Creature* pCreature) : ScriptedAI(pCreature) {} - - void MoveInLineOfSight(Unit* /*who*/) override {} - void UpdateAI(uint32 /*diff*/) override {} - }; }; void AddSC_boss_onyxia() { - new boss_onyxia(); - new npc_onyxian_lair_guard(); - new npc_onyxia_whelp(); - new npc_onyxia_trigger(); + RegisterOnyxiasLairCreatureAI(boss_onyxia); + RegisterOnyxiasLairCreatureAI(npc_onyxian_lair_guard); } diff --git a/src/server/scripts/Kalimdor/OnyxiasLair/instance_onyxias_lair.cpp b/src/server/scripts/Kalimdor/OnyxiasLair/instance_onyxias_lair.cpp index f5e3d012c..25af7297d 100644 --- a/src/server/scripts/Kalimdor/OnyxiasLair/instance_onyxias_lair.cpp +++ b/src/server/scripts/Kalimdor/OnyxiasLair/instance_onyxias_lair.cpp @@ -38,33 +38,18 @@ public: { instance_onyxias_lair_InstanceMapScript(Map* pMap) : InstanceScript(pMap) {Initialize();}; - uint32 m_auiEncounter[MAX_ENCOUNTER]; std::string str_data; uint16 ManyWhelpsCounter; - GuidVector minions; bool bDeepBreath; void Initialize() override { - memset(&m_auiEncounter, 0, sizeof(m_auiEncounter)); + SetBossNumber(MAX_ENCOUNTER); ManyWhelpsCounter = 0; bDeepBreath = true; LoadObjectData(creatureData, nullptr); } - void OnCreatureCreate(Creature* creature) override - { - switch (creature->GetEntry()) - { - case NPC_ONYXIAN_WHELP: - case NPC_ONYXIAN_LAIR_GUARD: - minions.push_back(creature->GetGUID()); - break; - } - - InstanceScript::OnCreatureCreate(creature); - } - void OnGameObjectCreate(GameObject* go) override { switch (go->GetEntry()) @@ -79,26 +64,26 @@ public: } } - void SetData(uint32 uiType, uint32 uiData) override + bool SetBossState(uint32 type, EncounterState state) override + { + if (!InstanceScript::SetBossState(type, state)) + { + return false; + } + + if (type == DATA_ONYXIA && state == NOT_STARTED) + { + ManyWhelpsCounter = 0; + bDeepBreath = true; + } + + return true; + } + + void SetData(uint32 uiType, uint32 /*uiData*/) override { switch (uiType) { - case DATA_ONYXIA: - m_auiEncounter[0] = uiData; - ManyWhelpsCounter = 0; - bDeepBreath = true; - if(uiData == NOT_STARTED) - { - for (ObjectGuid const& guid : minions) - { - if (Creature* c = instance->GetCreature(guid)) - { - c->DespawnOrUnsummon(); - } - } - minions.clear(); - } - break; case DATA_WHELP_SUMMONED: ++ManyWhelpsCounter; break; @@ -106,29 +91,13 @@ public: bDeepBreath = false; break; } - - if (uiType < MAX_ENCOUNTER && uiData == DONE) - { - SaveToDB(); - } - } - - uint32 GetData(uint32 uiType) const override - { - switch (uiType) - { - case DATA_ONYXIA: - return m_auiEncounter[0]; - } - - return 0; } std::string GetSaveData() override { OUT_SAVE_INST_DATA; std::ostringstream saveStream; - saveStream << "O L " << m_auiEncounter[0]; + saveStream << "O L " << GetBossSaveData(); str_data = saveStream.str(); OUT_SAVE_INST_DATA_COMPLETE; return str_data; @@ -136,7 +105,7 @@ public: void Load(const char* in) override { - if( !in ) + if (!in) { OUT_LOAD_INST_DATA_FAIL; return; @@ -149,13 +118,18 @@ public: std::istringstream loadStream(in); loadStream >> dataHead1 >> dataHead2 >> data0; - if( dataHead1 == 'O' && dataHead2 == 'L' ) + if (dataHead1 == 'O' && dataHead2 == 'L') { - m_auiEncounter[0] = data0; - - for( uint8 i = 0; i < MAX_ENCOUNTER; ++i ) - if( m_auiEncounter[i] == IN_PROGRESS ) - m_auiEncounter[i] = NOT_STARTED; + for (uint32 i = 0; i < MAX_ENCOUNTER; ++i) + { + uint32 tmpState; + loadStream >> tmpState; + if (tmpState == IN_PROGRESS || tmpState == FAIL || tmpState > SPECIAL) + { + tmpState = NOT_STARTED; + } + SetBossState(i, EncounterState(tmpState)); + } } else OUT_LOAD_INST_DATA_FAIL; diff --git a/src/server/scripts/Kalimdor/OnyxiasLair/onyxias_lair.h b/src/server/scripts/Kalimdor/OnyxiasLair/onyxias_lair.h index c96b762df..7d78bc694 100644 --- a/src/server/scripts/Kalimdor/OnyxiasLair/onyxias_lair.h +++ b/src/server/scripts/Kalimdor/OnyxiasLair/onyxias_lair.h @@ -58,4 +58,6 @@ inline AI* GetOnyxiasLairAI(T* obj) return GetInstanceAI(obj, OnyxiasLairScriptName); } +#define RegisterOnyxiasLairCreatureAI(ai_name) RegisterCreatureAIWithFactory(ai_name, GetOnyxiasLairAI) + #endif