diff --git a/src/server/scripts/EasternKingdoms/Karazhan/boss_midnight.cpp b/src/server/scripts/EasternKingdoms/Karazhan/boss_midnight.cpp index b64c25a28..82061fcb8 100644 --- a/src/server/scripts/EasternKingdoms/Karazhan/boss_midnight.cpp +++ b/src/server/scripts/EasternKingdoms/Karazhan/boss_midnight.cpp @@ -24,18 +24,18 @@ enum Texts { - SAY_KILL = 0, - SAY_RANDOM = 1, - SAY_DISARMED = 2, - SAY_MIDNIGHT_KILL = 3, - SAY_APPEAR = 4, - SAY_MOUNT = 5, + SAY_KILL = 0, + SAY_RANDOM = 1, + SAY_DISARMED = 2, + SAY_MIDNIGHT_KILL = 3, + SAY_APPEAR = 4, + SAY_MOUNT = 5, - SAY_DEATH = 3, + SAY_DEATH = 3, // Midnight - EMOTE_CALL_ATTUMEN = 0, - EMOTE_MOUNT_UP = 1 + EMOTE_CALL_ATTUMEN = 0, + EMOTE_MOUNT_UP = 1 }; enum Spells @@ -45,7 +45,6 @@ enum Spells SPELL_INTANGIBLE_PRESENCE = 29833, SPELL_SPAWN_SMOKE = 10389, SPELL_CHARGE = 29847, - // Midnight SPELL_KNOCKDOWN = 29711, SPELL_SUMMON_ATTUMEN = 29714, @@ -62,406 +61,357 @@ enum Phases enum Actions { - ACTION_SET_MIDNIGHT_PHASE, + ACTION_SET_MIDNIGHT_PHASE }; -class boss_attumen : public CreatureScript +struct boss_attumen : public BossAI { -public: - boss_attumen() : CreatureScript("boss_attumen") { } - - struct boss_attumenAI : public BossAI + boss_attumen(Creature* creature) : BossAI(creature, DATA_ATTUMEN) { - boss_attumenAI(Creature* creature) : BossAI(creature, DATA_ATTUMEN) - { - Initialize(); - } + Initialize(); + } - void Initialize() + void Initialize() + { + _phase = PHASE_NONE; + } + + void Reset() override + { + Initialize(); + } + + bool CanMeleeHit() + { + return me->GetVictim() && (me->GetVictim()->GetPositionZ() < 53.0f || me->GetVictim()->GetDistance(me->GetHomePosition()) < 50.0f); + } + + void EnterEvadeMode(EvadeReason why) override + { + if (Creature* midnight = instance->GetCreature(DATA_MIDNIGHT)) + { + midnight->AI()->EnterEvadeMode(why); + } + me->DespawnOrUnsummon(); + } + + void ScheduleTasks() override + { + scheduler.Schedule(15s, 25s, [this](TaskContext task) + { + DoCastVictim(SPELL_SHADOWCLEAVE); + task.Repeat(15s, 25s); + }); + scheduler.Schedule(25s, 45s, [this](TaskContext task) + { + if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0)) + { + DoCast(target, SPELL_INTANGIBLE_PRESENCE); + } + + task.Repeat(25s, 45s); + }); + scheduler.Schedule(30s, 1min, [this](TaskContext task) + { + Talk(SAY_RANDOM); + task.Repeat(30s, 1min); + }); + } + + void DamageTaken(Unit* /*attacker*/, uint32& damage, DamageEffectType /*damageType*/, SpellSchoolMask /*damageSchoolMask*/) override + { + // Attumen does not die until he mounts Midnight, let health fall to 1 and prevent further damage. + if (damage >= me->GetHealth() && _phase != PHASE_MOUNTED) + { + damage = me->GetHealth() - 1; + } + if (_phase == PHASE_ATTUMEN_ENGAGES && me->HealthBelowPctDamaged(25, damage)) { _phase = PHASE_NONE; - } - void Reset() override - { - Initialize(); - } - - bool CanMeleeHit() - { - return me->GetVictim() && (me->GetVictim()->GetPositionZ() < 53.0f || me->GetVictim()->GetDistance(me->GetHomePosition()) < 50.0f); - } - - void EnterEvadeMode(EvadeReason why) override - { if (Creature* midnight = instance->GetCreature(DATA_MIDNIGHT)) { - midnight->AI()->EnterEvadeMode(why); - } - - me->DespawnOrUnsummon(); - } - - void ScheduleTasks() override - { - scheduler.Schedule(Seconds(15), Seconds(25), [this](TaskContext task) - { - DoCastVictim(SPELL_SHADOWCLEAVE); - task.Repeat(Seconds(15), Seconds(25)); - }); - - scheduler.Schedule(Seconds(25), Seconds(45), [this](TaskContext task) - { - if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0)) - { - DoCast(target, SPELL_INTANGIBLE_PRESENCE); - } - - task.Repeat(Seconds(25), Seconds(45)); - }); - - scheduler.Schedule(Seconds(30), Seconds(60), [this](TaskContext task) - { - Talk(SAY_RANDOM); - task.Repeat(Seconds(30), Seconds(60)); - }); - } - - void DamageTaken(Unit* /*attacker*/, uint32& damage, DamageEffectType /*damageType*/, SpellSchoolMask /*damageSchoolMask*/) override - { - // Attumen does not die until he mounts Midnight, let health fall to 1 and prevent further damage. - if (damage >= me->GetHealth() && _phase != PHASE_MOUNTED) - { - damage = me->GetHealth() - 1; - } - - if (_phase == PHASE_ATTUMEN_ENGAGES && me->HealthBelowPctDamaged(25, damage)) - { - _phase = PHASE_NONE; - - if (Creature* midnight = instance->GetCreature(DATA_MIDNIGHT)) - { - midnight->AI()->DoCastAOE(SPELL_MOUNT, true); - } + midnight->AI()->DoCastAOE(SPELL_MOUNT, true); } } + } - void KilledUnit(Unit* /*victim*/) override + void KilledUnit(Unit* victim) override + { + if (victim->GetTypeId() == TYPEID_PLAYER) { Talk(SAY_KILL); } + } - void JustSummoned(Creature* summon) override + void JustSummoned(Creature* summon) override + { + if (summon->GetEntry() == NPC_ATTUMEN_THE_HUNTSMAN_MOUNTED) { - if (summon->GetEntry() == NPC_ATTUMEN_THE_HUNTSMAN_MOUNTED) - { - if (Creature* midnight = instance->GetCreature(DATA_MIDNIGHT)) - { - if (midnight->GetHealth() > me->GetHealth()) - { - summon->SetHealth(midnight->GetHealth()); - } - else - { - summon->SetHealth(me->GetHealth()); - } - - summon->AI()->DoZoneInCombat(); - } - } - - BossAI::JustSummoned(summon); - } - - void IsSummonedBy(WorldObject* summoner) override - { - if (summoner->GetEntry() == NPC_MIDNIGHT) - { - _phase = PHASE_ATTUMEN_ENGAGES; - } - - if (summoner->GetEntry() == NPC_ATTUMEN_THE_HUNTSMAN) - { - _phase = PHASE_MOUNTED; - DoCastSelf(SPELL_SPAWN_SMOKE); - - scheduler.Schedule(Seconds(10), Seconds(25), [this](TaskContext task) - { - Unit* target = nullptr; - std::vector target_list; - - for (auto* ref : me->GetThreatMgr().GetUnsortedThreatList()) - { - target = ref->GetVictim(); - if (target && !target->IsWithinDist(me, 8.00f, false) && target->IsWithinDist(me, 25.0f, false)) - target_list.push_back(target); - - target = nullptr; - } - - if (!target_list.empty()) - { - target = Acore::Containers::SelectRandomContainerElement(target_list); - } - - DoCast(target, SPELL_CHARGE); - task.Repeat(Seconds(10), Seconds(25)); - }); - - scheduler.Schedule(Seconds(25), Seconds(35), [this](TaskContext task) - { - DoCastVictim(SPELL_KNOCKDOWN); - task.Repeat(Seconds(25), Seconds(35)); - }); - } - } - - void JustDied(Unit* /*killer*/) override - { - Talk(SAY_DEATH); if (Creature* midnight = instance->GetCreature(DATA_MIDNIGHT)) { - midnight->KillSelf(); + if (midnight->GetHealth() > me->GetHealth()) + { + summon->SetHealth(midnight->GetHealth()); + } + else + { + summon->SetHealth(me->GetHealth()); + } + summon->AI()->DoZoneInCombat(); } + } + BossAI::JustSummoned(summon); + } - _JustDied(); + void IsSummonedBy(WorldObject* summoner) override + { + if (summoner->GetEntry() == NPC_MIDNIGHT) + { + _phase = PHASE_ATTUMEN_ENGAGES; + } + if (summoner->GetEntry() == NPC_ATTUMEN_THE_HUNTSMAN) + { + _phase = PHASE_MOUNTED; + DoCastSelf(SPELL_SPAWN_SMOKE); + scheduler.Schedule(10s, 25s, [this](TaskContext task) + { + Unit* target = nullptr; + std::vector target_list; + for (auto* ref : me->GetThreatMgr().GetUnsortedThreatList()) + { + target = ref->GetVictim(); + if (target && !target->IsWithinDist(me, 8.00f, false) && target->IsWithinDist(me, 25.0f, false)) + { + target_list.push_back(target); + } + target = nullptr; + } + if (!target_list.empty()) + { + target = Acore::Containers::SelectRandomContainerElement(target_list); + } + DoCast(target, SPELL_CHARGE); + task.Repeat(10s, 25s); + }); + scheduler.Schedule(25s, 35s, [this](TaskContext task) + { + DoCastVictim(SPELL_KNOCKDOWN); + task.Repeat(25s, 35s); + }); + } + } + + void JustDied(Unit* /*killer*/) override + { + Talk(SAY_DEATH); + if (Creature* midnight = instance->GetCreature(DATA_MIDNIGHT)) + { + midnight->KillSelf(); + } + _JustDied(); + } + + void UpdateAI(uint32 diff) override + { + if (_phase != PHASE_NONE) + { + if (!UpdateVictim()) + { + return; + } + } + if (!CanMeleeHit()) + { + BossAI::EnterEvadeMode(EvadeReason::EVADE_REASON_BOUNDARY); + } + scheduler.Update(diff, std::bind(&BossAI::DoMeleeAttackIfReady, this)); + } + + void SpellHit(Unit* /*caster*/, SpellInfo const* spellInfo) override + { + if (spellInfo->Mechanic == MECHANIC_DISARM) + { + Talk(SAY_DISARMED); } - void UpdateAI(uint32 diff) override + if (spellInfo->Id == SPELL_MOUNT) { - if (_phase != PHASE_NONE) + if (Creature* midnight = instance->GetCreature(DATA_MIDNIGHT)) { - if (!UpdateVictim()) + _phase = PHASE_NONE; + scheduler.CancelAll(); + midnight->AI()->DoAction(ACTION_SET_MIDNIGHT_PHASE); + midnight->AttackStop(); + midnight->RemoveAllAttackers(); + midnight->SetReactState(REACT_PASSIVE); + midnight->GetMotionMaster()->MoveFollow(me, 2.0f, 0.0f); + midnight->AI()->Talk(EMOTE_MOUNT_UP); + me->AttackStop(); + me->RemoveAllAttackers(); + me->SetReactState(REACT_PASSIVE); + me->GetMotionMaster()->MoveFollow(midnight, 2.0f, 0.0f); + Talk(SAY_MOUNT); + scheduler.Schedule(1s, [this](TaskContext task) { - return; - } + if (Creature* midnight = instance->GetCreature(DATA_MIDNIGHT)) + { + if (me->IsWithinDist2d(midnight, 5.0f)) + { + DoCastAOE(SPELL_SUMMON_ATTUMEN_MOUNTED); + me->DespawnOrUnsummon(1s, 0s); + midnight->SetVisible(false); + } + else + { + midnight->GetMotionMaster()->MoveFollow(me, 2.0f, 0.0f); + me->GetMotionMaster()->MoveFollow(midnight, 2.0f, 0.0f); + task.Repeat(); + } + } + }); } + } + } +private: + uint8 _phase; +}; + +struct boss_midnight : public BossAI +{ + boss_midnight(Creature* creature) : BossAI(creature, DATA_ATTUMEN), _phase(PHASE_NONE) { } + + void Reset() override + { + BossAI::Reset(); + me->SetVisible(true); + me->SetReactState(REACT_DEFENSIVE); + } + + bool CanMeleeHit() + { + return me->GetVictim() && (me->GetVictim()->GetPositionZ() < 53.0f || me->GetVictim()->GetDistance(me->GetHomePosition()) < 50.0f); + } + + void DamageTaken(Unit* /*attacker*/, uint32& damage, DamageEffectType /*damageType*/, SpellSchoolMask /*damageSchoolMask*/) override + { + // Midnight never dies, let health fall to 1 and prevent further damage. + if (damage >= me->GetHealth()) + { + damage = me->GetHealth() - 1; + } + + if (_phase == PHASE_NONE && me->HealthBelowPctDamaged(95, damage)) + { + _phase = PHASE_ATTUMEN_ENGAGES; + Talk(EMOTE_CALL_ATTUMEN); + DoCastAOE(SPELL_SUMMON_ATTUMEN); + } + else if (_phase == PHASE_ATTUMEN_ENGAGES && me->HealthBelowPctDamaged(25, damage)) + { + _phase = PHASE_MOUNTED; + DoCastAOE(SPELL_MOUNT, true); + } + } + + void JustSummoned(Creature* summon) override + { + if (summon->GetEntry() == NPC_ATTUMEN_THE_HUNTSMAN) + { + summon->AI()->AttackStart(me->GetVictim()); + summon->AI()->Talk(SAY_APPEAR); + } + BossAI::JustSummoned(summon); + } + + void DoAction(int32 actionId) override + { + if (actionId == ACTION_SET_MIDNIGHT_PHASE) + { + _phase = PHASE_MOUNTED; + } + } + + void JustEngagedWith(Unit* who) override + { + BossAI::JustEngagedWith(who); + scheduler.Schedule(15s, 25s, [this](TaskContext task) + { + DoCastVictim(SPELL_KNOCKDOWN); + task.Repeat(15s, 25s); + }); + } + + void EnterEvadeMode(EvadeReason /*why*/) override + { + me->DespawnOnEvade(10s); + _phase = PHASE_NONE; + } + + void KilledUnit(Unit* /*victim*/) override + { + if (_phase == PHASE_ATTUMEN_ENGAGES) + { + if (Creature* attumen = instance->GetCreature(DATA_ATTUMEN)) + { + Talk(SAY_MIDNIGHT_KILL, attumen); + } + } + } + + void UpdateAI(uint32 diff) override + { + if (_phase != PHASE_MOUNTED) + { + if (!UpdateVictim()) + { + return; + } if (!CanMeleeHit()) { BossAI::EnterEvadeMode(EvadeReason::EVADE_REASON_BOUNDARY); } - - scheduler.Update(diff, - std::bind(&BossAI::DoMeleeAttackIfReady, this)); } - - void SpellHit(Unit* /*caster*/, SpellInfo const* spellInfo) override - { - if (spellInfo->Mechanic == MECHANIC_DISARM) - { - Talk(SAY_DISARMED); - } - - if (spellInfo->Id == SPELL_MOUNT) - { - if (Creature* midnight = instance->GetCreature(DATA_MIDNIGHT)) - { - _phase = PHASE_NONE; - scheduler.CancelAll(); - - midnight->AI()->DoAction(ACTION_SET_MIDNIGHT_PHASE); - midnight->AttackStop(); - midnight->RemoveAllAttackers(); - midnight->SetReactState(REACT_PASSIVE); - midnight->GetMotionMaster()->MoveFollow(me, 2.0f, 0.0f); - midnight->AI()->Talk(EMOTE_MOUNT_UP); - - me->AttackStop(); - me->RemoveAllAttackers(); - me->SetReactState(REACT_PASSIVE); - me->GetMotionMaster()->MoveFollow(midnight, 2.0f, 0.0f); - Talk(SAY_MOUNT); - - scheduler.Schedule(Seconds(1), [this](TaskContext task) - { - if (Creature* midnight = instance->GetCreature(DATA_MIDNIGHT)) - { - if (me->IsWithinDist2d(midnight, 5.0f)) - { - DoCastAOE(SPELL_SUMMON_ATTUMEN_MOUNTED); - me->DespawnOrUnsummon(1s, 0s); - midnight->SetVisible(false); - } - else - { - midnight->GetMotionMaster()->MoveFollow(me, 2.0f, 0.0f); - me->GetMotionMaster()->MoveFollow(midnight, 2.0f, 0.0f); - task.Repeat(); - } - } - }); - } - } - } - - private: - uint8 _phase; - }; - - CreatureAI* GetAI(Creature* creature) const override - { - return GetKarazhanAI(creature); + scheduler.Update(diff, std::bind(&BossAI::DoMeleeAttackIfReady, this)); } + +private: + uint8 _phase; }; -class boss_midnight : public CreatureScript +class spell_midnight_fixate : public AuraScript { -public: - boss_midnight() : CreatureScript("boss_midnight") { } + PrepareAuraScript(spell_midnight_fixate) - struct boss_midnightAI : public BossAI + void HandleEffectApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) { - boss_midnightAI(Creature* creature) : BossAI(creature, DATA_ATTUMEN), _phase(PHASE_NONE) { } - - void Reset() override + Unit* target = GetTarget(); + if (Unit* caster = GetCaster()) { - BossAI::Reset(); - me->SetVisible(true); - me->SetReactState(REACT_DEFENSIVE); + caster->TauntApply(target); } - - bool CanMeleeHit() - { - return me->GetVictim() && (me->GetVictim()->GetPositionZ() < 53.0f || me->GetVictim()->GetDistance(me->GetHomePosition()) < 50.0f); - } - - void DamageTaken(Unit* /*attacker*/, uint32& damage, DamageEffectType /*damageType*/, SpellSchoolMask /*damageSchoolMask*/) override - { - // Midnight never dies, let health fall to 1 and prevent further damage. - if (damage >= me->GetHealth()) - { - damage = me->GetHealth() - 1; - } - - if (_phase == PHASE_NONE && me->HealthBelowPctDamaged(95, damage)) - { - _phase = PHASE_ATTUMEN_ENGAGES; - Talk(EMOTE_CALL_ATTUMEN); - DoCastAOE(SPELL_SUMMON_ATTUMEN); - } - else if (_phase == PHASE_ATTUMEN_ENGAGES && me->HealthBelowPctDamaged(25, damage)) - { - _phase = PHASE_MOUNTED; - DoCastAOE(SPELL_MOUNT, true); - } - } - - void JustSummoned(Creature* summon) override - { - if (summon->GetEntry() == NPC_ATTUMEN_THE_HUNTSMAN) - { - summon->AI()->AttackStart(me->GetVictim()); - summon->AI()->Talk(SAY_APPEAR); - } - - BossAI::JustSummoned(summon); - } - - void DoAction(int32 actionId) override - { - if (actionId == ACTION_SET_MIDNIGHT_PHASE) - { - _phase = PHASE_MOUNTED; - } - } - - void JustEngagedWith(Unit* who) override - { - BossAI::JustEngagedWith(who); - - scheduler.Schedule(Seconds(15), Seconds(25), [this](TaskContext task) - { - DoCastVictim(SPELL_KNOCKDOWN); - task.Repeat(Seconds(15), Seconds(25)); - }); - } - - void EnterEvadeMode(EvadeReason /*why*/) override - { - me->DespawnOnEvade(10s); - _phase = PHASE_NONE; - } - - void KilledUnit(Unit* /*victim*/) override - { - if (_phase == PHASE_ATTUMEN_ENGAGES) - { - if (Creature* attumen = instance->GetCreature(DATA_ATTUMEN)) - { - Talk(SAY_MIDNIGHT_KILL, attumen); - } - } - } - - void UpdateAI(uint32 diff) override - { - if (_phase != PHASE_MOUNTED) - { - if (!UpdateVictim()) - { - return; - } - - if (!CanMeleeHit()) - { - BossAI::EnterEvadeMode(EvadeReason::EVADE_REASON_BOUNDARY); - } - } - - scheduler.Update(diff, - std::bind(&BossAI::DoMeleeAttackIfReady, this)); - } - - private: - uint8 _phase; - }; - - CreatureAI* GetAI(Creature* creature) const override - { - return GetKarazhanAI(creature); } -}; -class spell_midnight_fixate : public SpellScriptLoader -{ -public: - spell_midnight_fixate() : SpellScriptLoader("spell_midnight_fixate") { } - - class spell_midnight_fixate_AuraScript : public AuraScript + void HandleEffectRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) { - PrepareAuraScript(spell_midnight_fixate_AuraScript); - - void HandleEffectApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) + Unit* target = GetTarget(); + if (Unit* caster = GetCaster()) { - Unit* target = GetTarget(); - if (Unit* caster = GetCaster()) - caster->TauntApply(target); + caster->TauntFadeOut(target); } + } - void HandleEffectRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) - { - Unit* target = GetTarget(); - if (Unit* caster = GetCaster()) - caster->TauntFadeOut(target); - } - - void Register() override - { - OnEffectApply += AuraEffectApplyFn(spell_midnight_fixate_AuraScript::HandleEffectApply, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL); - OnEffectRemove += AuraEffectRemoveFn(spell_midnight_fixate_AuraScript::HandleEffectRemove, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL); - } - }; - - AuraScript* GetAuraScript() const override + void Register() override { - return new spell_midnight_fixate_AuraScript(); + OnEffectApply += AuraEffectApplyFn(spell_midnight_fixate::HandleEffectApply, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL); + OnEffectRemove += AuraEffectRemoveFn(spell_midnight_fixate::HandleEffectRemove, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL); } }; void AddSC_boss_attumen() { - new boss_midnight(); - new boss_attumen(); - new spell_midnight_fixate(); + RegisterKarazhanCreatureAI(boss_midnight); + RegisterKarazhanCreatureAI(boss_attumen); + RegisterSpellScript(spell_midnight_fixate); }