diff options
author | Shauren <shauren.trinity@gmail.com> | 2022-09-23 16:43:41 +0200 |
---|---|---|
committer | Shauren <shauren.trinity@gmail.com> | 2022-09-30 20:17:34 +0200 |
commit | 88060425b562927b9cf2277bae8b2087978bb4cc (patch) | |
tree | 5917ad7b13020a002a4750312e1e55615f188839 | |
parent | 8cadc10dd56609750a573f417c51a2d9eb2197cd (diff) |
Scripts/The Sunwell: Move Brutallus and Felmyst to BossAI
(cherry picked from commit 8962d802249f002f8fe408004945d5736a118175)
-rw-r--r-- | src/server/scripts/EasternKingdoms/SunwellPlateau/boss_brutallus.cpp | 446 | ||||
-rw-r--r-- | src/server/scripts/EasternKingdoms/SunwellPlateau/boss_felmyst.cpp | 717 |
2 files changed, 551 insertions, 612 deletions
diff --git a/src/server/scripts/EasternKingdoms/SunwellPlateau/boss_brutallus.cpp b/src/server/scripts/EasternKingdoms/SunwellPlateau/boss_brutallus.cpp index 09aff3b741f..33a133b37cf 100644 --- a/src/server/scripts/EasternKingdoms/SunwellPlateau/boss_brutallus.cpp +++ b/src/server/scripts/EasternKingdoms/SunwellPlateau/boss_brutallus.cpp @@ -64,284 +64,268 @@ enum Spells SPELL_INTRO_ENCAPSULATE_CHANELLING = 45661 }; -class boss_brutallus : public CreatureScript +struct boss_brutallus : public BossAI { -public: - boss_brutallus() : CreatureScript("boss_brutallus") { } + boss_brutallus(Creature* creature) : BossAI(creature, DATA_BRUTALLUS) + { + Initialize(); + Intro = true; + } - struct boss_brutallusAI : public ScriptedAI + void Initialize() { - boss_brutallusAI(Creature* creature) : ScriptedAI(creature) - { - Initialize(); - instance = creature->GetInstanceScript(); - Intro = true; - } + SlashTimer = 11000; + StompTimer = 30000; + BurnTimer = 60000; + BerserkTimer = 360000; - void Initialize() - { - SlashTimer = 11000; - StompTimer = 30000; - BurnTimer = 60000; - BerserkTimer = 360000; + IntroPhase = 0; + IntroPhaseTimer = 0; + IntroFrostBoltTimer = 0; - IntroPhase = 0; - IntroPhaseTimer = 0; - IntroFrostBoltTimer = 0; + IsIntro = false; + Enraged = false; + } - IsIntro = false; - Enraged = false; - } + uint32 SlashTimer; + uint32 BurnTimer; + uint32 StompTimer; + uint32 BerserkTimer; - InstanceScript* instance; + uint32 IntroPhase; + uint32 IntroPhaseTimer; + uint32 IntroFrostBoltTimer; - uint32 SlashTimer; - uint32 BurnTimer; - uint32 StompTimer; - uint32 BerserkTimer; + bool Intro; + bool IsIntro; + bool Enraged; - uint32 IntroPhase; - uint32 IntroPhaseTimer; - uint32 IntroFrostBoltTimer; + void Reset() override + { + Initialize(); - bool Intro; - bool IsIntro; - bool Enraged; + DoCast(me, SPELL_DUAL_WIELD, true); - void Reset() override - { - Initialize(); + BossAI::Reset(); + } - DoCast(me, SPELL_DUAL_WIELD, true); + void JustEngagedWith(Unit* who) override + { + Talk(YELL_AGGRO); - instance->SetBossState(DATA_BRUTALLUS, NOT_STARTED); - } + BossAI::JustEngagedWith(who); + } - void JustEngagedWith(Unit* /*who*/) override - { - Talk(YELL_AGGRO); + void KilledUnit(Unit* /*victim*/) override + { + Talk(YELL_KILL); + } - instance->SetBossState(DATA_BRUTALLUS, IN_PROGRESS); - } + void JustDied(Unit* killer) override + { + Talk(YELL_DEATH); - void KilledUnit(Unit* /*victim*/) override - { - Talk(YELL_KILL); - } + instance->SetBossState(DATA_FELMYST, SPECIAL); + BossAI::JustDied(killer); + } - void JustDied(Unit* /*killer*/) override - { - Talk(YELL_DEATH); + void EnterEvadeMode(EvadeReason why) override + { + if (!Intro) + BossAI::EnterEvadeMode(why); + } - instance->SetBossState(DATA_BRUTALLUS, DONE); - float x, y, z; - me->GetPosition(x, y, z); - me->SummonCreature(NPC_FELMYST, x, y, z + 30, me->GetOrientation(), TEMPSUMMON_MANUAL_DESPAWN); - } + void StartIntro() + { + if (!Intro || IsIntro) + return; - void EnterEvadeMode(EvadeReason why) override + if (Creature* Madrigosa = instance->GetCreature(DATA_MADRIGOSA)) { - if (!Intro) - ScriptedAI::EnterEvadeMode(why); + Madrigosa->Respawn(); + Madrigosa->setActive(true); + Madrigosa->SetFarVisible(true); + IsIntro = true; + Madrigosa->SetMaxHealth(me->GetMaxHealth()); + Madrigosa->SetHealth(me->GetMaxHealth()); + me->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE); + me->Attack(Madrigosa, true); + Madrigosa->Attack(me, true); } - - void StartIntro() + else { - if (!Intro || IsIntro) - return; - - if (Creature* Madrigosa = instance->GetCreature(DATA_MADRIGOSA)) - { - Madrigosa->Respawn(); - Madrigosa->setActive(true); - Madrigosa->SetFarVisible(true); - IsIntro = true; - Madrigosa->SetMaxHealth(me->GetMaxHealth()); - Madrigosa->SetHealth(me->GetMaxHealth()); - me->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE); - me->Attack(Madrigosa, true); - Madrigosa->Attack(me, true); - } - else - { - // Madrigosa not found, end intro - TC_LOG_ERROR("scripts", "Madrigosa was not found"); - EndIntro(); - } + // Madrigosa not found, end intro + TC_LOG_ERROR("scripts", "Madrigosa was not found"); + EndIntro(); } + } - void EndIntro() - { - me->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE); - Intro = false; - IsIntro = false; - } + void EndIntro() + { + me->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE); + Intro = false; + IsIntro = false; + } - void AttackStart(Unit* who) override - { - if (!who || Intro || IsIntro) - return; - ScriptedAI::AttackStart(who); - } + void AttackStart(Unit* who) override + { + if (!who || Intro || IsIntro) + return; + BossAI::AttackStart(who); + } - void DoIntro() - { - Creature* Madrigosa = instance->GetCreature(DATA_MADRIGOSA); - if (!Madrigosa) - return; + void DoIntro() + { + Creature* Madrigosa = instance->GetCreature(DATA_MADRIGOSA); + if (!Madrigosa) + return; - switch (IntroPhase) - { - case 0: - Madrigosa->AI()->Talk(YELL_MADR_ICE_BARRIER); - IntroPhaseTimer = 7000; - ++IntroPhase; - break; - case 1: - me->SetFacingToObject(Madrigosa); - Madrigosa->SetFacingToObject(me); - Madrigosa->AI()->Talk(YELL_MADR_INTRO, me); - IntroPhaseTimer = 9000; - ++IntroPhase; - break; - case 2: - Talk(YELL_INTRO, Madrigosa); - IntroPhaseTimer = 13000; - ++IntroPhase; - break; - case 3: - DoCast(me, SPELL_INTRO_FROST_BLAST); - Madrigosa->SetDisableGravity(true); - me->AttackStop(); - Madrigosa->AttackStop(); - IntroFrostBoltTimer = 3000; - IntroPhaseTimer = 28000; - ++IntroPhase; - break; - case 4: - Talk(YELL_INTRO_BREAK_ICE); - IntroPhaseTimer = 6000; - ++IntroPhase; - break; - case 5: - Madrigosa->CastSpell(me, SPELL_INTRO_ENCAPSULATE_CHANELLING, false); - Madrigosa->AI()->Talk(YELL_MADR_TRAP); - DoCast(me, SPELL_INTRO_ENCAPSULATE); - IntroPhaseTimer = 11000; - ++IntroPhase; - break; - case 6: - Talk(YELL_INTRO_CHARGE); - IntroPhaseTimer = 5000; - ++IntroPhase; - break; - case 7: - Unit::Kill(me, Madrigosa); - Madrigosa->AI()->Talk(YELL_MADR_DEATH); - me->SetFullHealth(); - me->AttackStop(); - IntroPhaseTimer = 4000; - ++IntroPhase; - break; - case 8: - Talk(YELL_INTRO_KILL_MADRIGOSA); - me->SetOrientation(0.14f); - me->StopMoving(); - Madrigosa->setDeathState(CORPSE); - IntroPhaseTimer = 8000; - ++IntroPhase; - break; - case 9: - Talk(YELL_INTRO_TAUNT); - IntroPhaseTimer = 5000; - ++IntroPhase; - break; - case 10: - EndIntro(); - break; - } + switch (IntroPhase) + { + case 0: + Madrigosa->AI()->Talk(YELL_MADR_ICE_BARRIER); + IntroPhaseTimer = 7000; + ++IntroPhase; + break; + case 1: + me->SetFacingToObject(Madrigosa); + Madrigosa->SetFacingToObject(me); + Madrigosa->AI()->Talk(YELL_MADR_INTRO, me); + IntroPhaseTimer = 9000; + ++IntroPhase; + break; + case 2: + Talk(YELL_INTRO, Madrigosa); + IntroPhaseTimer = 13000; + ++IntroPhase; + break; + case 3: + DoCast(me, SPELL_INTRO_FROST_BLAST); + Madrigosa->SetDisableGravity(true); + me->AttackStop(); + Madrigosa->AttackStop(); + IntroFrostBoltTimer = 3000; + IntroPhaseTimer = 28000; + ++IntroPhase; + break; + case 4: + Talk(YELL_INTRO_BREAK_ICE); + IntroPhaseTimer = 6000; + ++IntroPhase; + break; + case 5: + Madrigosa->CastSpell(me, SPELL_INTRO_ENCAPSULATE_CHANELLING, false); + Madrigosa->AI()->Talk(YELL_MADR_TRAP); + DoCast(me, SPELL_INTRO_ENCAPSULATE); + IntroPhaseTimer = 11000; + ++IntroPhase; + break; + case 6: + Talk(YELL_INTRO_CHARGE); + IntroPhaseTimer = 5000; + ++IntroPhase; + break; + case 7: + Unit::Kill(me, Madrigosa); + Madrigosa->AI()->Talk(YELL_MADR_DEATH); + me->SetFullHealth(); + me->AttackStop(); + IntroPhaseTimer = 4000; + ++IntroPhase; + break; + case 8: + Talk(YELL_INTRO_KILL_MADRIGOSA); + me->SetOrientation(0.14f); + me->StopMoving(); + Madrigosa->setDeathState(CORPSE); + IntroPhaseTimer = 8000; + ++IntroPhase; + break; + case 9: + Talk(YELL_INTRO_TAUNT); + IntroPhaseTimer = 5000; + ++IntroPhase; + break; + case 10: + EndIntro(); + break; } + } - void MoveInLineOfSight(Unit* who) override - { - if (!me->IsValidAttackTarget(who)) - return; + void MoveInLineOfSight(Unit* who) override + { + if (!me->IsValidAttackTarget(who)) + return; - if (Intro) - instance->SetBossState(DATA_BRUTALLUS, SPECIAL); + if (Intro) + instance->SetBossState(DATA_BRUTALLUS, SPECIAL); - if (Intro && !IsIntro) - StartIntro(); + if (Intro && !IsIntro) + StartIntro(); - if (!Intro) - ScriptedAI::MoveInLineOfSight(who); - } + if (!Intro) + BossAI::MoveInLineOfSight(who); + } - void UpdateAI(uint32 diff) override + void UpdateAI(uint32 diff) override + { + if (IsIntro) { - if (IsIntro) - { - if (IntroPhaseTimer <= diff) - DoIntro(); - else IntroPhaseTimer -= diff; + if (IntroPhaseTimer <= diff) + DoIntro(); + else IntroPhaseTimer -= diff; - if (IntroPhase == 3 + 1) + if (IntroPhase == 3 + 1) + { + if (IntroFrostBoltTimer <= diff) { - if (IntroFrostBoltTimer <= diff) + if (Creature* Madrigosa = instance->GetCreature(DATA_MADRIGOSA)) { - if (Creature* Madrigosa = instance->GetCreature(DATA_MADRIGOSA)) - { - Madrigosa->CastSpell(me, SPELL_INTRO_FROSTBOLT, true); - IntroFrostBoltTimer = 2000; - } + Madrigosa->CastSpell(me, SPELL_INTRO_FROSTBOLT, true); + IntroFrostBoltTimer = 2000; } - else - IntroFrostBoltTimer -= diff; } - - if (!UpdateVictim()) - return; - - DoMeleeAttackIfReady(); + else + IntroFrostBoltTimer -= diff; } - if (!UpdateVictim() || IsIntro) + if (!UpdateVictim()) return; - if (SlashTimer <= diff) - { - DoCastVictim(SPELL_METEOR_SLASH); - SlashTimer = 11000; - } else SlashTimer -= diff; + DoMeleeAttackIfReady(); + } - if (StompTimer <= diff) - { - Talk(YELL_LOVE); - DoCastVictim(SPELL_STOMP); - StompTimer = 30000; - } else StompTimer -= diff; + if (!UpdateVictim() || IsIntro) + return; - if (BurnTimer <= diff) - { - if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 100.0f, true, true, -SPELL_BURN)) - target->CastSpell(target, SPELL_BURN, true); - BurnTimer = urand(60000, 180000); - } else BurnTimer -= diff; + if (SlashTimer <= diff) + { + DoCastVictim(SPELL_METEOR_SLASH); + SlashTimer = 11000; + } else SlashTimer -= diff; - if (BerserkTimer < diff && !Enraged) - { - Talk(YELL_BERSERK); - DoCast(me, SPELL_BERSERK); - Enraged = true; - } else BerserkTimer -= diff; + if (StompTimer <= diff) + { + Talk(YELL_LOVE); + DoCastVictim(SPELL_STOMP); + StompTimer = 30000; + } else StompTimer -= diff; - DoMeleeAttackIfReady(); - } - }; + if (BurnTimer <= diff) + { + if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 100.0f, true, true, -SPELL_BURN)) + target->CastSpell(target, SPELL_BURN, true); + BurnTimer = urand(60000, 180000); + } else BurnTimer -= diff; - CreatureAI* GetAI(Creature* creature) const override - { - return GetSunwellPlateauAI<boss_brutallusAI>(creature); + if (BerserkTimer < diff && !Enraged) + { + Talk(YELL_BERSERK); + DoCast(me, SPELL_BERSERK); + Enraged = true; + } else BerserkTimer -= diff; + + DoMeleeAttackIfReady(); } }; @@ -385,7 +369,7 @@ class spell_brutallus_stomp : public SpellScript void AddSC_boss_brutallus() { - new boss_brutallus(); + RegisterSunwellPlateauCreatureAI(boss_brutallus); RegisterSpellScript(spell_brutallus_burn); RegisterSpellScript(spell_brutallus_stomp); } diff --git a/src/server/scripts/EasternKingdoms/SunwellPlateau/boss_felmyst.cpp b/src/server/scripts/EasternKingdoms/SunwellPlateau/boss_felmyst.cpp index ebaf536ccdb..90f959b4667 100644 --- a/src/server/scripts/EasternKingdoms/SunwellPlateau/boss_felmyst.cpp +++ b/src/server/scripts/EasternKingdoms/SunwellPlateau/boss_felmyst.cpp @@ -22,12 +22,11 @@ SDComment: EndScriptData */ #include "ScriptMgr.h" -#include "CellImpl.h" -#include "GridNotifiersImpl.h" #include "InstanceScript.h" #include "MotionMaster.h" #include "ObjectAccessor.h" #include "ScriptedCreature.h" +#include "SpellInfo.h" #include "sunwell_plateau.h" #include "TemporarySummon.h" @@ -109,472 +108,428 @@ enum EventFelmyst EVENT_SUMMON_FOG }; -class boss_felmyst : public CreatureScript +struct boss_felmyst : public BossAI { -public: - boss_felmyst() : CreatureScript("boss_felmyst") { } + boss_felmyst(Creature* creature) : BossAI(creature, DATA_FELMYST) + { + Initialize(); + uiBreathCount = 0; + breathX = 0.f; + breathY = 0.f; + } - struct boss_felmystAI : public ScriptedAI + void Initialize() { - boss_felmystAI(Creature* creature) : ScriptedAI(creature) - { - Initialize(); - instance = creature->GetInstanceScript(); - uiBreathCount = 0; - breathX = 0.f; - breathY = 0.f; - } + phase = PHASE_NONE; + uiFlightCount = 0; + } - void Initialize() - { - phase = PHASE_NONE; - uiFlightCount = 0; - } + PhaseFelmyst phase; - InstanceScript* instance; - PhaseFelmyst phase; - EventMap events; + uint32 uiFlightCount; + uint32 uiBreathCount; - uint32 uiFlightCount; - uint32 uiBreathCount; + float breathX, breathY; - float breathX, breathY; + void Reset() override + { + Initialize(); - void Reset() override - { - Initialize(); + BossAI::Reset(); - events.Reset(); + me->SetDisableGravity(true); + me->SetBoundingRadius(10); + me->SetCombatReach(10); + } - me->SetDisableGravity(true); - me->SetBoundingRadius(10); - me->SetCombatReach(10); + void JustEngagedWith(Unit* who) override + { + BossAI::JustEngagedWith(who); - DespawnSummons(NPC_VAPOR_TRAIL); - me->setActive(false); + events.ScheduleEvent(EVENT_BERSERK, 10min); - instance->SetBossState(DATA_FELMYST, NOT_STARTED); - } + DoCast(me, AURA_SUNWELL_RADIANCE, true); + DoCast(me, AURA_NOXIOUS_FUMES, true); + EnterPhase(PHASE_GROUND); + } - void JustEngagedWith(Unit* /*who*/) override - { - events.ScheduleEvent(EVENT_BERSERK, 10min); + void AttackStart(Unit* who) override + { + if (phase != PHASE_FLIGHT) + BossAI::AttackStart(who); + } - me->setActive(true); - DoZoneInCombat(); - DoCast(me, AURA_SUNWELL_RADIANCE, true); - DoCast(me, AURA_NOXIOUS_FUMES, true); - EnterPhase(PHASE_GROUND); + void MoveInLineOfSight(Unit* who) override + { + if (phase != PHASE_FLIGHT) + BossAI::MoveInLineOfSight(who); + } - instance->SetBossState(DATA_FELMYST, IN_PROGRESS); - } + void KilledUnit(Unit* /*victim*/) override + { + Talk(YELL_KILL); + } - void AttackStart(Unit* who) override - { - if (phase != PHASE_FLIGHT) - ScriptedAI::AttackStart(who); - } + void JustAppeared() override + { + Talk(YELL_BIRTH); + } - void MoveInLineOfSight(Unit* who) override - { - if (phase != PHASE_FLIGHT) - ScriptedAI::MoveInLineOfSight(who); - } + void JustDied(Unit* killer) override + { + Talk(YELL_DEATH); - void KilledUnit(Unit* /*victim*/) override - { - Talk(YELL_KILL); - } + BossAI::JustDied(killer); + } - void JustAppeared() override - { - Talk(YELL_BIRTH); - } + void SpellHit(WorldObject* caster, SpellInfo const* spellInfo) override + { + Unit* unitCaster = caster->ToUnit(); + if (!unitCaster) + return; - void JustDied(Unit* /*killer*/) override + // workaround for linked aura + /*if (spell->Id == SPELL_VAPOR_FORCE) { - Talk(YELL_DEATH); - - instance->SetBossState(DATA_FELMYST, DONE); - } - - void SpellHit(WorldObject* caster, SpellInfo const* spellInfo) override + caster->CastSpell(caster, SPELL_VAPOR_TRIGGER, true); + }*/ + // workaround for mind control + if (spellInfo->Id == SPELL_FOG_INFORM) { - Unit* unitCaster = caster->ToUnit(); - if (!unitCaster) - return; - - // workaround for linked aura - /*if (spell->Id == SPELL_VAPOR_FORCE) - { - caster->CastSpell(caster, SPELL_VAPOR_TRIGGER, true); - }*/ - // workaround for mind control - if (spellInfo->Id == SPELL_FOG_INFORM) + float x, y, z; + unitCaster->GetPosition(x, y, z); + if (Unit* summon = me->SummonCreature(NPC_DEAD, x, y, z, 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 5s)) { - float x, y, z; - unitCaster->GetPosition(x, y, z); - if (Unit* summon = me->SummonCreature(NPC_DEAD, x, y, z, 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 5s)) - { - summon->SetMaxHealth(unitCaster->GetMaxHealth()); - summon->SetHealth(unitCaster->GetMaxHealth()); - summon->CastSpell(summon, SPELL_FOG_CHARM, true); - summon->CastSpell(summon, SPELL_FOG_CHARM2, true); - } - Unit::DealDamage(me, unitCaster, unitCaster->GetHealth(), nullptr, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, nullptr, false); + summon->SetMaxHealth(unitCaster->GetMaxHealth()); + summon->SetHealth(unitCaster->GetMaxHealth()); + summon->CastSpell(summon, SPELL_FOG_CHARM, true); + summon->CastSpell(summon, SPELL_FOG_CHARM2, true); } + Unit::DealDamage(me, unitCaster, unitCaster->GetHealth(), nullptr, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, nullptr, false); } + } - void JustSummoned(Creature* summon) override + void JustSummoned(Creature* summon) override + { + if (summon->GetEntry() == NPC_DEAD) { - if (summon->GetEntry() == NPC_DEAD) - { - summon->AI()->AttackStart(SelectTarget(SelectTargetMethod::Random)); - DoZoneInCombat(summon); - summon->CastSpell(summon, SPELL_DEAD_PASSIVE, true); - } + summon->AI()->AttackStart(SelectTarget(SelectTargetMethod::Random)); + DoZoneInCombat(summon); + summon->CastSpell(summon, SPELL_DEAD_PASSIVE, true); } - void MovementInform(uint32, uint32) override - { - if (phase == PHASE_FLIGHT) - events.ScheduleEvent(EVENT_FLIGHT_SEQUENCE, 1ms); - } + BossAI::JustSummoned(summon); + } - void DamageTaken(Unit*, uint32& damage, DamageEffectType /*damageType*/, SpellInfo const* /*spellInfo = nullptr*/) override + void MovementInform(uint32, uint32) override + { + if (phase == PHASE_FLIGHT) + events.ScheduleEvent(EVENT_FLIGHT_SEQUENCE, 1ms); + } + + void DamageTaken(Unit*, uint32& damage, DamageEffectType /*damageType*/, SpellInfo const* /*spellInfo = nullptr*/) override + { + if (phase != PHASE_GROUND && damage >= me->GetHealth()) + damage = 0; + } + + void EnterPhase(PhaseFelmyst NextPhase) + { + switch (NextPhase) { - if (phase != PHASE_GROUND && damage >= me->GetHealth()) - damage = 0; + case PHASE_GROUND: + me->CastStop(SPELL_FOG_BREATH); + me->RemoveAurasDueToSpell(SPELL_FOG_BREATH); + me->StopMoving(); + me->SetSpeedRate(MOVE_RUN, 2.0f); + + events.ScheduleEvent(EVENT_CLEAVE, 5s, 10s); + events.ScheduleEvent(EVENT_CORROSION, 10s, 20s); + events.ScheduleEvent(EVENT_GAS_NOVA, 15s, 20s); + events.ScheduleEvent(EVENT_ENCAPSULATE, 20s, 25s); + events.ScheduleEvent(EVENT_FLIGHT, 1min); + break; + case PHASE_FLIGHT: + me->SetDisableGravity(true); + events.ScheduleEvent(EVENT_FLIGHT_SEQUENCE, 1s); + uiFlightCount = 0; + uiBreathCount = 0; + break; + default: + break; } + phase = NextPhase; + } - void EnterPhase(PhaseFelmyst NextPhase) + void HandleFlightSequence() + { + switch (uiFlightCount) { - switch (NextPhase) + case 0: + //me->AttackStop(); + me->GetMotionMaster()->Clear(); + me->HandleEmoteCommand(EMOTE_ONESHOT_LIFTOFF); + me->StopMoving(); + Talk(YELL_TAKEOFF); + events.ScheduleEvent(EVENT_FLIGHT_SEQUENCE, 2s); + break; + case 1: + me->GetMotionMaster()->MovePoint(0, me->GetPositionX()+1, me->GetPositionY(), me->GetPositionZ()+10); + break; + case 2: { - case PHASE_GROUND: - me->CastStop(SPELL_FOG_BREATH); - me->RemoveAurasDueToSpell(SPELL_FOG_BREATH); - me->StopMoving(); - me->SetSpeedRate(MOVE_RUN, 2.0f); + Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 150, true); + if (!target) + target = ObjectAccessor::GetUnit(*me, instance->GetGuidData(DATA_PLAYER_GUID)); - events.ScheduleEvent(EVENT_CLEAVE, 5s, 10s); - events.ScheduleEvent(EVENT_CORROSION, 10s, 20s); - events.ScheduleEvent(EVENT_GAS_NOVA, 15s, 20s); - events.ScheduleEvent(EVENT_ENCAPSULATE, 20s, 25s); - events.ScheduleEvent(EVENT_FLIGHT, 1min); - break; - case PHASE_FLIGHT: - me->SetDisableGravity(true); - events.ScheduleEvent(EVENT_FLIGHT_SEQUENCE, 1s); - uiFlightCount = 0; - uiBreathCount = 0; - break; - default: - break; - } - phase = NextPhase; - } + if (!target) + { + EnterEvadeMode(); + return; + } - void HandleFlightSequence() - { - switch (uiFlightCount) - { - case 0: - //me->AttackStop(); - me->GetMotionMaster()->Clear(); - me->HandleEmoteCommand(EMOTE_ONESHOT_LIFTOFF); - me->StopMoving(); - Talk(YELL_TAKEOFF); - events.ScheduleEvent(EVENT_FLIGHT_SEQUENCE, 2s); - break; - case 1: - me->GetMotionMaster()->MovePoint(0, me->GetPositionX()+1, me->GetPositionY(), me->GetPositionZ()+10); - break; - case 2: + if (Creature* Vapor = me->SummonCreature(NPC_VAPOR, target->GetPositionX() - 5 + rand32() % 10, target->GetPositionY() - 5 + rand32() % 10, target->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN, 9s)) { - Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 150, true); - if (!target) - target = ObjectAccessor::GetUnit(*me, instance->GetGuidData(DATA_PLAYER_GUID)); + Vapor->AI()->AttackStart(target); + me->InterruptNonMeleeSpells(false); + DoCast(Vapor, SPELL_VAPOR_CHANNEL, false); // core bug + Vapor->CastSpell(Vapor, SPELL_VAPOR_TRIGGER, true); + } - if (!target) - { - EnterEvadeMode(); - return; - } + events.ScheduleEvent(EVENT_FLIGHT_SEQUENCE, 10s); + break; + } + case 3: + { + DespawnSummons(NPC_VAPOR_TRAIL); + //DoCast(me, SPELL_VAPOR_SELECT); need core support - if (Creature* Vapor = me->SummonCreature(NPC_VAPOR, target->GetPositionX() - 5 + rand32() % 10, target->GetPositionY() - 5 + rand32() % 10, target->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN, 9s)) - { - Vapor->AI()->AttackStart(target); - me->InterruptNonMeleeSpells(false); - DoCast(Vapor, SPELL_VAPOR_CHANNEL, false); // core bug - Vapor->CastSpell(Vapor, SPELL_VAPOR_TRIGGER, true); - } + Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 150, true); + if (!target) + target = ObjectAccessor::GetUnit(*me, instance->GetGuidData(DATA_PLAYER_GUID)); - events.ScheduleEvent(EVENT_FLIGHT_SEQUENCE, 10s); - break; - } - case 3: + if (!target) { - DespawnSummons(NPC_VAPOR_TRAIL); - //DoCast(me, SPELL_VAPOR_SELECT); need core support - - Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 150, true); - if (!target) - target = ObjectAccessor::GetUnit(*me, instance->GetGuidData(DATA_PLAYER_GUID)); + EnterEvadeMode(); + return; + } - if (!target) - { - EnterEvadeMode(); - return; - } + //target->CastSpell(target, SPELL_VAPOR_SUMMON, true); need core support + if (Creature* pVapor = me->SummonCreature(NPC_VAPOR, target->GetPositionX() - 5 + rand32() % 10, target->GetPositionY() - 5 + rand32() % 10, target->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN, 9s)) + { + if (pVapor->AI()) + pVapor->AI()->AttackStart(target); + me->InterruptNonMeleeSpells(false); + DoCast(pVapor, SPELL_VAPOR_CHANNEL, false); // core bug + pVapor->CastSpell(pVapor, SPELL_VAPOR_TRIGGER, true); + } - //target->CastSpell(target, SPELL_VAPOR_SUMMON, true); need core support - if (Creature* pVapor = me->SummonCreature(NPC_VAPOR, target->GetPositionX() - 5 + rand32() % 10, target->GetPositionY() - 5 + rand32() % 10, target->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN, 9s)) - { - if (pVapor->AI()) - pVapor->AI()->AttackStart(target); - me->InterruptNonMeleeSpells(false); - DoCast(pVapor, SPELL_VAPOR_CHANNEL, false); // core bug - pVapor->CastSpell(pVapor, SPELL_VAPOR_TRIGGER, true); - } + events.ScheduleEvent(EVENT_FLIGHT_SEQUENCE, 10s); + break; + } + case 4: + DespawnSummons(NPC_VAPOR_TRAIL); + events.ScheduleEvent(EVENT_FLIGHT_SEQUENCE, 1ms); + break; + case 5: + { + Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 150, true); + if (!target) + target = ObjectAccessor::GetUnit(*me, instance->GetGuidData(DATA_PLAYER_GUID)); - events.ScheduleEvent(EVENT_FLIGHT_SEQUENCE, 10s); - break; + if (!target) + { + EnterEvadeMode(); + return; } - case 4: - DespawnSummons(NPC_VAPOR_TRAIL); - events.ScheduleEvent(EVENT_FLIGHT_SEQUENCE, 1ms); - break; - case 5: + + breathX = target->GetPositionX(); + breathY = target->GetPositionY(); + float x, y, z; + target->GetContactPoint(me, x, y, z, 70); + me->GetMotionMaster()->MovePoint(0, x, y, z+10); + break; + } + case 6: + me->SetFacingTo(me->GetAbsoluteAngle(breathX, breathY)); + //DoTextEmote("takes a deep breath.", nullptr); + events.ScheduleEvent(EVENT_FLIGHT_SEQUENCE, 10s); + break; + case 7: + { + DoCast(me, SPELL_FOG_BREATH, true); + float x, y, z; + me->GetPosition(x, y, z); + x = 2 * breathX - x; + y = 2 * breathY - y; + me->GetMotionMaster()->MovePoint(0, x, y, z); + events.ScheduleEvent(EVENT_SUMMON_FOG, 1ms); + break; + } + case 8: + me->CastStop(SPELL_FOG_BREATH); + me->RemoveAurasDueToSpell(SPELL_FOG_BREATH); + ++uiBreathCount; + events.ScheduleEvent(EVENT_FLIGHT_SEQUENCE, 1ms); + if (uiBreathCount < 3) + uiFlightCount = 4; + break; + case 9: + if (Unit* target = SelectTarget(SelectTargetMethod::MaxThreat)) + DoStartMovement(target); + else { - Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 150, true); - if (!target) - target = ObjectAccessor::GetUnit(*me, instance->GetGuidData(DATA_PLAYER_GUID)); + EnterEvadeMode(); + return; + } + break; + case 10: + me->SetDisableGravity(false); + me->HandleEmoteCommand(EMOTE_ONESHOT_LAND); + EnterPhase(PHASE_GROUND); + AttackStart(SelectTarget(SelectTargetMethod::MaxThreat)); + break; + } + ++uiFlightCount; + } - if (!target) - { - EnterEvadeMode(); - return; - } + void UpdateAI(uint32 diff) override + { + if (!UpdateVictim()) + { + if (phase == PHASE_FLIGHT && !me->IsInEvadeMode()) + EnterEvadeMode(); + return; + } + + events.Update(diff); - breathX = target->GetPositionX(); - breathY = target->GetPositionY(); - float x, y, z; - target->GetContactPoint(me, x, y, z, 70); - me->GetMotionMaster()->MovePoint(0, x, y, z+10); + if (me->IsNonMeleeSpellCast(false)) + return; + + if (phase == PHASE_GROUND) + { + switch (events.ExecuteEvent()) + { + case EVENT_BERSERK: + Talk(YELL_BERSERK); + DoCast(me, SPELL_BERSERK, true); + events.ScheduleEvent(EVENT_BERSERK, 10s); break; - } - case 6: - me->SetFacingTo(me->GetAbsoluteAngle(breathX, breathY)); - //DoTextEmote("takes a deep breath.", nullptr); - events.ScheduleEvent(EVENT_FLIGHT_SEQUENCE, 10s); + case EVENT_CLEAVE: + DoCastVictim(SPELL_CLEAVE, false); + events.ScheduleEvent(EVENT_CLEAVE, 5s, 10s); break; - case 7: - { - DoCast(me, SPELL_FOG_BREATH, true); - float x, y, z; - me->GetPosition(x, y, z); - x = 2 * breathX - x; - y = 2 * breathY - y; - me->GetMotionMaster()->MovePoint(0, x, y, z); - events.ScheduleEvent(EVENT_SUMMON_FOG, 1ms); + case EVENT_CORROSION: + DoCastVictim(SPELL_CORROSION, false); + events.ScheduleEvent(EVENT_CORROSION, 20s, 30s); break; - } - case 8: - me->CastStop(SPELL_FOG_BREATH); - me->RemoveAurasDueToSpell(SPELL_FOG_BREATH); - ++uiBreathCount; - events.ScheduleEvent(EVENT_FLIGHT_SEQUENCE, 1ms); - if (uiBreathCount < 3) - uiFlightCount = 4; + case EVENT_GAS_NOVA: + DoCast(me, SPELL_GAS_NOVA, false); + events.ScheduleEvent(EVENT_GAS_NOVA, 20s, 25s); break; - case 9: - if (Unit* target = SelectTarget(SelectTargetMethod::MaxThreat)) - DoStartMovement(target); - else - { - EnterEvadeMode(); - return; - } + case EVENT_ENCAPSULATE: + if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 150, true)) + DoCast(target, SPELL_ENCAPSULATE_CHANNEL, false); + events.ScheduleEvent(EVENT_ENCAPSULATE, 25s, 30s); break; - case 10: - me->SetDisableGravity(false); - me->HandleEmoteCommand(EMOTE_ONESHOT_LAND); - EnterPhase(PHASE_GROUND); - AttackStart(SelectTarget(SelectTargetMethod::MaxThreat)); + case EVENT_FLIGHT: + EnterPhase(PHASE_FLIGHT); + break; + default: + DoMeleeAttackIfReady(); break; } - ++uiFlightCount; } - void UpdateAI(uint32 diff) override + if (phase == PHASE_FLIGHT) { - if (!UpdateVictim()) + switch (events.ExecuteEvent()) { - if (phase == PHASE_FLIGHT && !me->IsInEvadeMode()) - EnterEvadeMode(); - return; - } - - events.Update(diff); - - if (me->IsNonMeleeSpellCast(false)) - return; - - if (phase == PHASE_GROUND) - { - switch (events.ExecuteEvent()) - { - case EVENT_BERSERK: - Talk(YELL_BERSERK); - DoCast(me, SPELL_BERSERK, true); - events.ScheduleEvent(EVENT_BERSERK, 10s); - break; - case EVENT_CLEAVE: - DoCastVictim(SPELL_CLEAVE, false); - events.ScheduleEvent(EVENT_CLEAVE, 5s, 10s); - break; - case EVENT_CORROSION: - DoCastVictim(SPELL_CORROSION, false); - events.ScheduleEvent(EVENT_CORROSION, 20s, 30s); - break; - case EVENT_GAS_NOVA: - DoCast(me, SPELL_GAS_NOVA, false); - events.ScheduleEvent(EVENT_GAS_NOVA, 20s, 25s); - break; - case EVENT_ENCAPSULATE: - if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 150, true)) - DoCast(target, SPELL_ENCAPSULATE_CHANNEL, false); - events.ScheduleEvent(EVENT_ENCAPSULATE, 25s, 30s); - break; - case EVENT_FLIGHT: - EnterPhase(PHASE_FLIGHT); - break; - default: - DoMeleeAttackIfReady(); - break; - } - } - - if (phase == PHASE_FLIGHT) - { - switch (events.ExecuteEvent()) - { - case EVENT_BERSERK: - Talk(YELL_BERSERK); - DoCast(me, SPELL_BERSERK, true); - break; - case EVENT_FLIGHT_SEQUENCE: - HandleFlightSequence(); - break; - case EVENT_SUMMON_FOG: + case EVENT_BERSERK: + Talk(YELL_BERSERK); + DoCast(me, SPELL_BERSERK, true); + break; + case EVENT_FLIGHT_SEQUENCE: + HandleFlightSequence(); + break; + case EVENT_SUMMON_FOG: + { + float x, y, z; + me->GetPosition(x, y, z); + me->UpdateGroundPositionZ(x, y, z); + if (Creature* Fog = me->SummonCreature(NPC_VAPOR_TRAIL, x, y, z, 0, TEMPSUMMON_TIMED_DESPAWN, 10s)) { - float x, y, z; - me->GetPosition(x, y, z); - me->UpdateGroundPositionZ(x, y, z); - if (Creature* Fog = me->SummonCreature(NPC_VAPOR_TRAIL, x, y, z, 0, TEMPSUMMON_TIMED_DESPAWN, 10s)) - { - Fog->RemoveAurasDueToSpell(SPELL_TRAIL_TRIGGER); - Fog->CastSpell(Fog, SPELL_FOG_TRIGGER, true); - me->CastSpell(Fog, SPELL_FOG_FORCE, true); - } + Fog->RemoveAurasDueToSpell(SPELL_TRAIL_TRIGGER); + Fog->CastSpell(Fog, SPELL_FOG_TRIGGER, true); + me->CastSpell(Fog, SPELL_FOG_FORCE, true); } - events.ScheduleEvent(EVENT_SUMMON_FOG, 1s); - break; - } + } + events.ScheduleEvent(EVENT_SUMMON_FOG, 1s); + break; } } + } - void DespawnSummons(uint32 entry) + void DespawnSummons(uint32 entry) + { + summons.DespawnIf([&](ObjectGuid guid) { - std::list<Creature*> templist; - float x, y, z; - me->GetPosition(x, y, z); - - Trinity::AllCreaturesOfEntryInRange check(me, entry, 100); - Trinity::CreatureListSearcher<Trinity::AllCreaturesOfEntryInRange> searcher(me, templist, check); - Cell::VisitGridObjects(me, searcher, me->GetGridActivationRange()); + if (guid.GetEntry() != entry) + return false; - for (std::list<Creature*>::const_iterator i = templist.begin(); i != templist.end(); ++i) + if (guid.GetEntry() == NPC_VAPOR_TRAIL && phase == PHASE_FLIGHT) { - if (entry == NPC_VAPOR_TRAIL && phase == PHASE_FLIGHT) - { - (*i)->GetPosition(x, y, z); - me->SummonCreature(NPC_DEAD, x, y, z, 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 5s); - } - (*i)->SetVisible(false); - (*i)->DespawnOrUnsummon(); - } - } - }; + Position const* pos = ObjectAccessor::GetCreature(*me, guid); + if (!pos) + pos = me; - CreatureAI* GetAI(Creature* creature) const override - { - return GetSunwellPlateauAI<boss_felmystAI>(creature); + me->SummonCreature(NPC_DEAD, *pos, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 5s); + } + return true; + }); } }; -class npc_felmyst_vapor : public CreatureScript +struct npc_felmyst_vapor : public ScriptedAI { -public: - npc_felmyst_vapor() : CreatureScript("npc_felmyst_vapor") { } + npc_felmyst_vapor(Creature* creature) : ScriptedAI(creature) { } - CreatureAI* GetAI(Creature* creature) const override + void Reset() override { } + void JustEngagedWith(Unit* /*who*/) override { - return GetSunwellPlateauAI<npc_felmyst_vaporAI>(creature); + DoZoneInCombat(); + //DoCast(me, SPELL_VAPOR_FORCE, true); core bug } - struct npc_felmyst_vaporAI : public ScriptedAI + void UpdateAI(uint32 /*diff*/) override { - npc_felmyst_vaporAI(Creature* creature) : ScriptedAI(creature) { } - - void Reset() override { } - void JustEngagedWith(Unit* /*who*/) override - { - DoZoneInCombat(); - //DoCast(me, SPELL_VAPOR_FORCE, true); core bug - } - - void UpdateAI(uint32 /*diff*/) override - { - if (!me->GetVictim()) - if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 100, true)) - AttackStart(target); - } - }; + if (!me->GetVictim()) + if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 100, true)) + AttackStart(target); + } }; -class npc_felmyst_trail : public CreatureScript +struct npc_felmyst_trail : public ScriptedAI { -public: - npc_felmyst_trail() : CreatureScript("npc_felmyst_trail") { } - - CreatureAI* GetAI(Creature* creature) const override + npc_felmyst_trail(Creature* creature) : ScriptedAI(creature) { - return GetSunwellPlateauAI<npc_felmyst_trailAI>(creature); + DoCast(me, SPELL_TRAIL_TRIGGER, true); + me->SetTarget(me->GetGUID()); + me->SetBoundingRadius(0.01f); // core bug } - struct npc_felmyst_trailAI : public ScriptedAI - { - npc_felmyst_trailAI(Creature* creature) : ScriptedAI(creature) - { - DoCast(me, SPELL_TRAIL_TRIGGER, true); - me->SetTarget(me->GetGUID()); - me->SetBoundingRadius(0.01f); // core bug - } - - void Reset() override { } - void JustEngagedWith(Unit* /*who*/) override { } - void AttackStart(Unit* /*who*/) override { } - void MoveInLineOfSight(Unit* /*who*/) override { } + void Reset() override { } + void JustEngagedWith(Unit* /*who*/) override { } + void AttackStart(Unit* /*who*/) override { } + void MoveInLineOfSight(Unit* /*who*/) override { } - void UpdateAI(uint32 /*diff*/) override { } - }; + void UpdateAI(uint32 /*diff*/) override { } }; void AddSC_boss_felmyst() { - new boss_felmyst(); - new npc_felmyst_vapor(); - new npc_felmyst_trail(); + RegisterSunwellPlateauCreatureAI(boss_felmyst); + RegisterSunwellPlateauCreatureAI(npc_felmyst_vapor); + RegisterSunwellPlateauCreatureAI(npc_felmyst_trail); } |