diff --git a/src/server/game/AI/CreatureAI.h b/src/server/game/AI/CreatureAI.h index 94478d15e..a354b603b 100644 --- a/src/server/game/AI/CreatureAI.h +++ b/src/server/game/AI/CreatureAI.h @@ -220,6 +220,9 @@ public: virtual bool OnTeleportUnreacheablePlayer(Player* /*player*/) { return false; } + // Called when an aura is removed or expires. + virtual void OnAuraRemove(AuraApplication* /*aurApp*/, AuraRemoveMode /*mode*/) { } + protected: virtual void MoveInLineOfSight(Unit* /*who*/); diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp index 25be63539..ec64f1bba 100644 --- a/src/server/game/Entities/Unit/Unit.cpp +++ b/src/server/game/Entities/Unit/Unit.cpp @@ -4603,6 +4603,9 @@ void Unit::_UnapplyAura(AuraApplicationMap::iterator& i, AuraRemoveMode removeMo i = m_appliedAuras.begin(); sScriptMgr->OnAuraRemove(this, aurApp, removeMode); + + if (this->ToCreature() && this->ToCreature()->IsAIEnabled) + this->ToCreature()->AI()->OnAuraRemove(aurApp, removeMode); } void Unit::_UnapplyAura(AuraApplication* aurApp, AuraRemoveMode removeMode) diff --git a/src/server/scripts/Outland/BlackTemple/boss_illidari_council.cpp b/src/server/scripts/Outland/BlackTemple/boss_illidari_council.cpp index 14f159da2..807bc0d73 100644 --- a/src/server/scripts/Outland/BlackTemple/boss_illidari_council.cpp +++ b/src/server/scripts/Outland/BlackTemple/boss_illidari_council.cpp @@ -88,12 +88,6 @@ enum Misc EVENT_SPELL_JUDGEMENT = 5, EVENT_SPELL_CONSECRATION = 6, - EVENT_SPELL_FLAMESTRIKE = 10, - EVENT_SPELL_BLIZZARD = 11, - EVENT_SPELL_ARCANE_BOLT = 12, - EVENT_SPELL_DAMPEN_MAGIC = 13, - EVENT_SPELL_ARCANE_EXPLOSION = 14, - EVENT_SPELL_REFLECTIVE_SHIELD = 20, EVENT_SPELL_CIRCLE_OF_HEALING = 21, EVENT_SPELL_DIVINE_WRATH = 22, @@ -378,22 +372,67 @@ private: struct boss_high_nethermancer_zerevor : public boss_illidari_council_memberAI { - boss_high_nethermancer_zerevor(Creature* creature) : boss_illidari_council_memberAI(creature) { } + boss_high_nethermancer_zerevor(Creature* creature) : boss_illidari_council_memberAI(creature), _canCastDampenMagic(true) { } + + void Reset() override + { + scheduler.CancelAll(); + _canCastDampenMagic = true; + boss_illidari_council_memberAI::Reset(); + CastDampenMagicIfPossible(); + } void AttackStart(Unit* who) override { - if (who && me->Attack(who, true)) - me->GetMotionMaster()->MoveChase(who, 20.0f); + AttackStartCaster(who, 20.0f); } void JustEngagedWith(Unit* who) override { boss_illidari_council_memberAI::JustEngagedWith(who); - events.ScheduleEvent(EVENT_SPELL_FLAMESTRIKE, 25000); - events.ScheduleEvent(EVENT_SPELL_BLIZZARD, 5000); - events.ScheduleEvent(EVENT_SPELL_ARCANE_BOLT, 15000); - events.ScheduleEvent(EVENT_SPELL_DAMPEN_MAGIC, 0); - events.ScheduleEvent(EVENT_SPELL_ARCANE_EXPLOSION, 10000); + + ScheduleTimedEvent(25s, [&] + { + if (roll_chance_i(50)) + Talk(SAY_COUNCIL_SPECIAL); + DoCastRandomTarget(SPELL_FLAMESTRIKE, 0, 100.0f); + }, 40s); + + ScheduleTimedEvent(15s, [&] + { + DoCastVictim(SPELL_ARCANE_BOLT); + }, 3s); + + ScheduleTimedEvent(5s, [&] + { + DoCastRandomTarget(SPELL_BLIZZARD, 0, 100.0f); + }, 40s); + + ScheduleTimedEvent(10s, [&] + { + if (SelectTarget(SelectTargetMethod::Random, 0, 10.0f)) + DoCastAOE(SPELL_ARCANE_EXPLOSION); + }, 10s); + + if (Aura* aura = me->GetAura(SPELL_DAMPEN_MAGIC)) + { + if (aura->GetDuration() <= 4 * MINUTE * IN_MILLISECONDS) + CastDampenMagicIfPossible(); + } + } + + void OnAuraRemove(AuraApplication* auraApp, AuraRemoveMode mode) override + { + if (auraApp->GetBase()->GetId() == SPELL_DAMPEN_MAGIC) + if (mode == AURA_REMOVE_BY_ENEMY_SPELL || mode == AURA_REMOVE_BY_EXPIRE) + if (!CastDampenMagicIfPossible()) + { + scheduler.Schedule(1s, [this](TaskContext context) + { + if (!CastDampenMagicIfPossible()) + context.Repeat(); + }); + } } void UpdateAI(uint32 diff) override @@ -401,41 +440,44 @@ struct boss_high_nethermancer_zerevor : public boss_illidari_council_memberAI if (!UpdateVictim()) return; - events.Update(diff); if (me->HasUnitState(UNIT_STATE_CASTING)) return; - switch (events.ExecuteEvent()) + scheduler.Update(diff, + std::bind(&BossAI::DoMeleeAttackIfReady, this)); + } + + bool CastDampenMagicIfPossible() + { + if (_canCastDampenMagic) { - case EVENT_SPELL_DAMPEN_MAGIC: - me->CastSpell(me, SPELL_DAMPEN_MAGIC, false); - events.ScheduleEvent(EVENT_SPELL_DAMPEN_MAGIC, 120000); - break; - case EVENT_SPELL_ARCANE_BOLT: - me->CastSpell(me->GetVictim(), SPELL_ARCANE_BOLT, false); - events.ScheduleEvent(EVENT_SPELL_ARCANE_BOLT, 3000); - break; - case EVENT_SPELL_FLAMESTRIKE: - if (roll_chance_i(50)) - Talk(SAY_COUNCIL_SPECIAL); - if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 100.0f)) - me->CastSpell(target, SPELL_FLAMESTRIKE, false); - events.ScheduleEvent(EVENT_SPELL_FLAMESTRIKE, 40000); - break; - case EVENT_SPELL_BLIZZARD: - if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 100.0f)) - me->CastSpell(target, SPELL_BLIZZARD, false); - events.ScheduleEvent(EVENT_SPELL_BLIZZARD, 40000); - break; - case EVENT_SPELL_ARCANE_EXPLOSION: - if (SelectTarget(SelectTargetMethod::Random, 0, 10.0f)) - me->CastSpell(me, SPELL_ARCANE_EXPLOSION, false); - events.ScheduleEvent(EVENT_SPELL_ARCANE_EXPLOSION, 10000); - break; + _canCastDampenMagic = false; + me->m_Events.AddEventAtOffset([this] { + _canCastDampenMagic = true; + }, 1min); + + if (me->IsInCombat()) + { + scheduler.Schedule(1s, [this](TaskContext /*context*/) + { + DoCastSelf(SPELL_DAMPEN_MAGIC); + }); + } + else + { + me->m_Events.AddEventAtOffset([this] { + DoCastSelf(SPELL_DAMPEN_MAGIC); + }, 1s); + } + + return true; } - DoMeleeAttackIfReady(); + return false; } + + private: + bool _canCastDampenMagic; }; struct boss_lady_malande : public boss_illidari_council_memberAI @@ -572,9 +614,7 @@ class spell_illidari_council_empyreal_balance : public SpellScript { PreventHitDefaultEffect(effIndex); if (GetHitUnit()) - { _targetCount++; - } } void HandleAfterCast() @@ -585,7 +625,7 @@ class spell_illidari_council_empyreal_balance : public SpellScript return; } - std::list const* targetsInfo = GetSpell()->GetUniqueTargetInfo(); + auto const* targetsInfo = GetSpell()->GetUniqueTargetInfo(); for (std::list::const_iterator ihit = targetsInfo->begin(); ihit != targetsInfo->end(); ++ihit) if (Creature* target = ObjectAccessor::GetCreature(*GetCaster(), ihit->targetGUID)) { @@ -619,19 +659,15 @@ class spell_illidari_council_empyreal_equivalency : public SpellScript { PreventHitDefaultEffect(effIndex); if (GetHitUnit()) - { _targetCount++; - } } void HandleAfterCast() { if (_targetCount != 4) - { return; - } - std::list const* targetsInfo = GetSpell()->GetUniqueTargetInfo(); + auto const* targetsInfo = GetSpell()->GetUniqueTargetInfo(); for (std::list::const_iterator ihit = targetsInfo->begin(); ihit != targetsInfo->end(); ++ihit) if (Creature* target = ObjectAccessor::GetCreature(*GetCaster(), ihit->targetGUID)) target->SetHealth(GetCaster()->GetHealth() / _targetCount);