mirror of
https://github.com/ZhengPeiRu21/mod-individual-progression
synced 2025-11-29 23:44:51 +08:00
547 lines
20 KiB
C++
547 lines
20 KiB
C++
/*
|
|
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify it
|
|
* under the terms of the GNU Affero General Public License as published by the
|
|
* Free Software Foundation; either version 3 of the License, or (at your
|
|
* option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for
|
|
* more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License along
|
|
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include "Player.h"
|
|
#include "ScriptMgr.h"
|
|
#include "ScriptedCreature.h"
|
|
#include "SpellInfo.h"
|
|
#include "onyxias_lair.h"
|
|
|
|
enum Spells
|
|
{
|
|
SPELL_WINGBUFFET = 18500,
|
|
SPELL_FLAMEBREATH = 18435,
|
|
SPELL_CLEAVE = 68868,
|
|
//SPELL_TAILSWEEP = 68867,
|
|
SPELL_TAILSWEEP = 15847,
|
|
SPELL_FIREBALL = 18392,
|
|
SPELL_BELLOWINGROAR = 18431,
|
|
|
|
SPELL_SUMMON_WHELP = 90003,
|
|
SPELL_SUMMON_LAIR_GUARD = 68968,
|
|
SPELL_ERUPTION = 17731,
|
|
|
|
SPELL_OLG_BLASTNOVA = 68958,
|
|
SPELL_OLG_IGNITEWEAPON = 68959,
|
|
|
|
SPELL_BREATH_N_TO_S = 17086,
|
|
SPELL_BREATH_S_TO_N = 18351,
|
|
SPELL_BREATH_E_TO_W = 18576,
|
|
SPELL_BREATH_W_TO_E = 18609,
|
|
SPELL_BREATH_SE_TO_NW = 18564,
|
|
SPELL_BREATH_NW_TO_SE = 18584,
|
|
SPELL_BREATH_SW_TO_NE = 18596,
|
|
SPELL_BREATH_NE_TO_SW = 18617,
|
|
};
|
|
|
|
enum Events
|
|
{
|
|
EVENT_SPELL_WINGBUFFET = 1,
|
|
EVENT_SPELL_FLAMEBREATH = 2,
|
|
EVENT_SPELL_TAILSWEEP = 3,
|
|
EVENT_SPELL_CLEAVE = 4,
|
|
EVENT_START_PHASE_2 = 5,
|
|
EVENT_SPELL_FIREBALL_FIRST = 6,
|
|
EVENT_SPELL_FIREBALL_SECOND = 7,
|
|
EVENT_PHASE_2_STEP_CW = 8,
|
|
EVENT_PHASE_2_STEP_ACW = 9,
|
|
EVENT_PHASE_2_STEP_ACROSS = 10,
|
|
EVENT_SPELL_BREATH = 11,
|
|
EVENT_START_PHASE_3 = 12,
|
|
EVENT_PHASE_3_ATTACK = 13,
|
|
EVENT_SPELL_BELLOWINGROAR = 14,
|
|
EVENT_WHELP_SPAM = 15,
|
|
EVENT_SUMMON_LAIR_GUARD = 16,
|
|
EVENT_SUMMON_WHELP = 17,
|
|
EVENT_OLG_SPELL_BLASTNOVA = 18,
|
|
EVENT_OLG_SPELL_IGNITEWEAPON = 19,
|
|
EVENT_ERUPTION = 20,
|
|
|
|
EVENT_LIFTOFF = 31,
|
|
EVENT_FLY_S_TO_N = 32,
|
|
EVENT_LAND = 33,
|
|
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
|
|
{
|
|
uint8 CurrId, DestId;
|
|
uint32 spellId;
|
|
float x, y, z, o;
|
|
};
|
|
|
|
static sOnyxMove OnyxiaMoveData[] =
|
|
{
|
|
{0, 0, 0, -64.496f, -214.906f, -84.4f, 0.0f}, // south ground
|
|
{1, 5, SPELL_BREATH_S_TO_N, -64.496f, -214.906f, -60.0f, 0.0f}, // south
|
|
{2, 6, SPELL_BREATH_SW_TO_NE, -59.809f, -190.758f, -60.0f, 7 * M_PI / 4}, // south-west
|
|
{3, 7, SPELL_BREATH_W_TO_E, -29.450f, -180.600f, -60.0f, M_PI + M_PI / 2}, // west
|
|
{4, 8, SPELL_BREATH_NW_TO_SE, 6.895f, -180.246f, -60.0f, M_PI + M_PI / 4}, // north-west
|
|
{5, 1, SPELL_BREATH_N_TO_S, 22.876f, -217.152f, -60.0f, M_PI}, // north
|
|
{6, 2, SPELL_BREATH_NE_TO_SW, 10.2191f, -247.912f, -60.0f, 3 * M_PI / 4}, // north-east
|
|
{7, 3, SPELL_BREATH_E_TO_W, -31.496f, -250.123f, -60.0f, M_PI / 2}, // east
|
|
{8, 4, SPELL_BREATH_SE_TO_NW, -63.5156f, -240.096f, -60.0f, M_PI / 4}, // south-east
|
|
};
|
|
|
|
enum Yells
|
|
{
|
|
// Say
|
|
SAY_AGGRO = 0,
|
|
SAY_KILL = 1,
|
|
SAY_PHASE_2_TRANS = 2,
|
|
SAY_PHASE_3_TRANS = 3,
|
|
|
|
// Emote
|
|
EMOTE_BREATH = 4
|
|
};
|
|
|
|
class boss_onyxia_40 : public CreatureScript
|
|
{
|
|
public:
|
|
boss_onyxia_40() : CreatureScript("boss_onyxia_40") {}
|
|
|
|
struct boss_onyxiaAI_40 : public BossAI
|
|
{
|
|
public:
|
|
boss_onyxiaAI_40(Creature* pCreature) : BossAI(pCreature, DATA_ONYXIA)
|
|
{
|
|
Initialize();
|
|
}
|
|
|
|
void Initialize()
|
|
{
|
|
CurrentWP = 0;
|
|
whelpSpam = false;
|
|
whelpCount = 0;
|
|
whelpSpamTimer = 0;
|
|
bManyWhelpsAvailable = false;
|
|
|
|
// Immune to taunt in vanilla
|
|
me->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_MOD_TAUNT, true);
|
|
me->ApplySpellImmune(0, IMMUNITY_EFFECT, SPELL_EFFECT_ATTACK_ME, true);
|
|
}
|
|
|
|
void SetPhase(uint8 ph)
|
|
{
|
|
events.Reset();
|
|
Phase = ph;
|
|
switch (ph)
|
|
{
|
|
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;
|
|
}
|
|
}
|
|
|
|
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);
|
|
BossAI::Reset();
|
|
}
|
|
|
|
void DoAction(int32 param) override
|
|
{
|
|
switch (param)
|
|
{
|
|
case -1:
|
|
if (bManyWhelpsAvailable)
|
|
{
|
|
instance->SetData(DATA_WHELP_SUMMONED, 1);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
void EnterCombat(Unit* who) override
|
|
{
|
|
Talk(SAY_AGGRO);
|
|
SetPhase(PHASE_GROUNDED);
|
|
|
|
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)
|
|
{
|
|
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, SPELL_SUMMON_WHELP, true);
|
|
me->CastSpell(-32.535f + cos(angle) * dist, -170.190f + sin(angle) * dist, -89.0f, SPELL_SUMMON_WHELP, true);
|
|
whelpCount += 2;
|
|
whelpSpamTimer += 600;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
whelpSpam = false;
|
|
whelpCount = 0;
|
|
whelpSpamTimer = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
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 EVENT_SPELL_WINGBUFFET:
|
|
{
|
|
DoCast(SPELL_WINGBUFFET);
|
|
events.RepeatEvent(urand(15000, 30000));
|
|
break;
|
|
}
|
|
case EVENT_SPELL_FLAMEBREATH:
|
|
{
|
|
DoCast(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();
|
|
DoResetThreatList();
|
|
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);
|
|
DoResetThreatList();
|
|
break;
|
|
}
|
|
case EVENT_SPELL_FIREBALL_FIRST:
|
|
{
|
|
if (Unit* v = SelectTarget(SelectTargetMethod::Random, 0, 200.0f, true))
|
|
{
|
|
me->SetFacingToObject(v);
|
|
DoCast(v, SPELL_FIREBALL);
|
|
}
|
|
|
|
events.ScheduleEvent(EVENT_SPELL_FIREBALL_SECOND, 4000);
|
|
break;
|
|
}
|
|
case EVENT_SPELL_FIREBALL_SECOND:
|
|
{
|
|
if (Unit* v = SelectTarget(SelectTargetMethod::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
|
|
{
|
|
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);
|
|
DoCast(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(SelectTargetMethod::MaxThreat, 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->AI()->DoCast(trigger, 17731);
|
|
}
|
|
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, SPELL_SUMMON_WHELP, true);
|
|
me->CastSpell(-32.535f + cos(angle) * dist, -170.190f + sin(angle) * dist, -89.0f, SPELL_SUMMON_WHELP, 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
|
|
{
|
|
instance->SetData(DATA_DEEP_BREATH_FAILED, 1);
|
|
}
|
|
}
|
|
|
|
private:
|
|
uint8 Phase;
|
|
int8 CurrentWP;
|
|
|
|
bool whelpSpam;
|
|
uint8 whelpCount;
|
|
int32 whelpSpamTimer;
|
|
bool bManyWhelpsAvailable;
|
|
};
|
|
|
|
CreatureAI* GetAI(Creature* creature) const override
|
|
{
|
|
return GetOnyxiasLairAI<boss_onyxiaAI_40>(creature);
|
|
};
|
|
};
|
|
|
|
void AddSC_boss_onyxia_40()
|
|
{
|
|
new boss_onyxia_40();
|
|
}
|