/* * 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 . */ #include "Player.h" #include "ScriptedCreature.h" #include "ScriptMgr.h" #include "SpellInfo.h" #include "sunwell_plateau.h" enum Spells { SPELL_ENRAGE = 26662, SPELL_NEGATIVE_ENERGY = 46009, SPELL_SUMMON_BLOOD_ELVES_PERIODIC = 46041, SPELL_OPEN_PORTAL_PERIODIC = 45994, SPELL_DARKNESS_PERIODIC = 45998, SPELL_SUMMON_BERSERKER1 = 46037, SPELL_SUMMON_FURY_MAGE1 = 46038, SPELL_SUMMON_FURY_MAGE2 = 46039, SPELL_SUMMON_BERSERKER2 = 46040, SPELL_SUMMON_DARK_FIEND = 46000, // till 46007 SPELL_OPEN_ALL_PORTALS = 46177, SPELL_SUMMON_ENTROPIUS = 46217, // Entropius's spells SPELL_ENTROPIUS_COSMETIC_SPAWN = 46223, SPELL_NEGATIVE_ENERGY_PERIODIC = 46284, SPELL_NEGATIVE_ENERGY_CHAIN = 46285, SPELL_BLACK_HOLE = 46282, SPELL_DARKNESS = 46268, SPELL_SUMMON_DARK_FIEND_ENTROPIUS = 46263, //Black Hole Spells SPELL_BLACK_HOLE_SUMMON_VISUAL = 46242, SPELL_BLACK_HOLE_SUMMON_VISUAL2 = 46248, SPELL_BLACK_HOLE_VISUAL2 = 46235, SPELL_BLACK_HOLE_PASSIVE = 46228, SPELL_BLACK_HOLE_EFFECT = 46230 }; enum Misc { EVENT_SPELL_ENRAGE = 1, EVENT_SUMMON_ENTROPIUS = 2, EVENT_SET_INVISIBLE = 3, EVENT_SPAWN_BLACK_HOLE = 4, EVENT_SPAWN_DARKNESS = 5, EVENT_START_BLACK_HOLE = 6, EVENT_SWITCH_BLACK_HOLE_TARGET = 7, EVENT_ENTROPIUS_AURAS = 8, EVENT_ENTROPIUS_COMBAT = 9, EVENT_SINGULARITY_DEATH = 10, DATA_ENRAGE_TIMER = 1, DATA_NEGATIVE_ENERGY_TARGETS = 2 }; class boss_muru : public CreatureScript { public: boss_muru() : CreatureScript("boss_muru") { } struct boss_muruAI : public BossAI { boss_muruAI(Creature* creature) : BossAI(creature, DATA_MURU) { } void Reset() override { BossAI::Reset(); me->SetReactState(REACT_AGGRESSIVE); me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); me->SetVisible(true); } void EnterCombat(Unit* who) override { BossAI::EnterCombat(who); me->CastSpell(me, SPELL_NEGATIVE_ENERGY, true); me->CastSpell(me, SPELL_SUMMON_BLOOD_ELVES_PERIODIC, true); me->CastSpell(me, SPELL_OPEN_PORTAL_PERIODIC, true); me->CastSpell(me, SPELL_DARKNESS_PERIODIC, true); events.ScheduleEvent(EVENT_SPELL_ENRAGE, 600000); } void DamageTaken(Unit*, uint32& damage, DamageEffectType, SpellSchoolMask) override { if (damage >= me->GetHealth()) { damage = 0; if (!me->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE)) { me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); me->RemoveAllAuras(); me->CastSpell(me, SPELL_OPEN_ALL_PORTALS, true); events.ScheduleEvent(EVENT_SUMMON_ENTROPIUS, 7000); } } } void JustSummoned(Creature* summon) override { if (summon->GetEntry() == NPC_ENTROPIUS) summon->AI()->SetData(DATA_ENRAGE_TIMER, events.GetNextEventTime(EVENT_SPELL_ENRAGE)); else { if (!summon->IsTrigger()) summon->SetInCombatWithZone(); summons.Summon(summon); } } void UpdateAI(uint32 diff) override { if (!UpdateVictim()) return; events.Update(diff); if (me->HasUnitState(UNIT_STATE_CASTING)) return; switch (events.ExecuteEvent()) { case EVENT_SPELL_ENRAGE: me->CastSpell(me, SPELL_ENRAGE, true); break; case EVENT_SUMMON_ENTROPIUS: me->CastSpell(me, SPELL_SUMMON_ENTROPIUS, false); events.ScheduleEvent(EVENT_SET_INVISIBLE, 1000); break; case EVENT_SET_INVISIBLE: me->SetVisible(false); break; } } }; CreatureAI* GetAI(Creature* creature) const override { return GetSunwellPlateauAI(creature); } }; class boss_entropius : public CreatureScript { public: boss_entropius() : CreatureScript("boss_entropius") { } struct boss_entropiusAI : public ScriptedAI { boss_entropiusAI(Creature* creature) : ScriptedAI(creature) { } EventMap events; EventMap events2; void Reset() override { events.Reset(); events2.Reset(); events2.ScheduleEvent(EVENT_ENTROPIUS_AURAS, 0); events2.ScheduleEvent(EVENT_ENTROPIUS_COMBAT, 3000); me->SetReactState(REACT_PASSIVE); } void EnterEvadeMode() override { if (InstanceScript* instance = me->GetInstanceScript()) if (Creature* muru = ObjectAccessor::GetCreature(*me, instance->GetGuidData(NPC_MURU))) if (!muru->IsInEvadeMode()) muru->AI()->EnterEvadeMode(); me->DespawnOrUnsummon(); } void EnterCombat(Unit* /*who*/) override { events.ScheduleEvent(EVENT_SPAWN_BLACK_HOLE, 15000); events.ScheduleEvent(EVENT_SPAWN_DARKNESS, 10000); } void SetData(uint32 type, uint32 data) override { if (type == DATA_ENRAGE_TIMER) events.ScheduleEvent(EVENT_SPELL_ENRAGE, data); } uint32 GetData(uint32 type) const override { if (type == DATA_NEGATIVE_ENERGY_TARGETS) return 1 + uint32(events.GetTimer() / 12000); return 0; } void JustDied(Unit* /*killer*/) override { if (InstanceScript* instance = me->GetInstanceScript()) if (Creature* muru = ObjectAccessor::GetCreature(*me, instance->GetGuidData(NPC_MURU))) Unit::Kill(muru, muru); } void UpdateAI(uint32 diff) override { events2.Update(diff); switch (events2.ExecuteEvent()) { case EVENT_ENTROPIUS_AURAS: me->CastSpell(me, SPELL_ENTROPIUS_COSMETIC_SPAWN, false); me->CastSpell(me, SPELL_NEGATIVE_ENERGY_PERIODIC, true); break; case EVENT_ENTROPIUS_COMBAT: me->SetReactState(REACT_AGGRESSIVE); me->SetInCombatWithZone(); AttackStart(SelectTargetFromPlayerList(50.0f)); break; } if (!events2.Empty()) return; if (!UpdateVictim()) return; events.Update(diff); if (me->HasUnitState(UNIT_STATE_CASTING)) return; switch (events.ExecuteEvent()) { case EVENT_SPELL_ENRAGE: me->CastSpell(me, SPELL_ENRAGE, true); break; case EVENT_SPAWN_DARKNESS: if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 50.0f, true)) me->CastSpell(target, SPELL_DARKNESS, true); events.ScheduleEvent(EVENT_SPAWN_DARKNESS, 15000); break; case EVENT_SPAWN_BLACK_HOLE: if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 50.0f, true)) me->CastSpell(target, SPELL_BLACK_HOLE, true); events.ScheduleEvent(EVENT_SPAWN_BLACK_HOLE, 15000); break; } DoMeleeAttackIfReady(); } }; CreatureAI* GetAI(Creature* creature) const override { return GetSunwellPlateauAI(creature); } }; class npc_singularity : public CreatureScript { public: npc_singularity() : CreatureScript("npc_singularity") { } CreatureAI* GetAI(Creature* creature) const override { return GetSunwellPlateauAI(creature); } struct npc_singularityAI : public NullCreatureAI { npc_singularityAI(Creature* creature) : NullCreatureAI(creature) { } EventMap events; void Reset() override { me->DespawnOrUnsummon(18000); me->CastSpell(me, SPELL_BLACK_HOLE_SUMMON_VISUAL, true); me->CastSpell(me, SPELL_BLACK_HOLE_SUMMON_VISUAL2, true); events.ScheduleEvent(EVENT_START_BLACK_HOLE, 3500); events.ScheduleEvent(EVENT_SWITCH_BLACK_HOLE_TARGET, 5000); events.ScheduleEvent(EVENT_SINGULARITY_DEATH, 17000); } void UpdateAI(uint32 diff) override { events.Update(diff); switch (events.ExecuteEvent()) { case EVENT_SINGULARITY_DEATH: Unit::Kill(me, me); break; case EVENT_START_BLACK_HOLE: me->RemoveAurasDueToSpell(SPELL_BLACK_HOLE_SUMMON_VISUAL2); me->CastSpell(me, SPELL_BLACK_HOLE_VISUAL2, true); me->CastSpell(me, SPELL_BLACK_HOLE_PASSIVE, true); break; case EVENT_SWITCH_BLACK_HOLE_TARGET: { Map::PlayerList const& players = me->GetMap()->GetPlayers(); for (Map::PlayerList::const_iterator itr = players.begin(); itr != players.end(); ++itr) if (Player* player = itr->GetSource()) if (me->GetDistance2d(player) < 15.0f && player->GetPositionZ() < 72.0f && player->IsAlive() && !player->HasAura(SPELL_BLACK_HOLE_EFFECT)) { me->GetMotionMaster()->MovePoint(0, player->GetPositionX(), player->GetPositionY(), player->GetPositionZ(), false, true); events.ScheduleEvent(EVENT_SWITCH_BLACK_HOLE_TARGET, 5000); return; } events.ScheduleEvent(EVENT_SWITCH_BLACK_HOLE_TARGET, 500); break; } } } }; }; class spell_muru_summon_blood_elves_periodic : public SpellScriptLoader { public: spell_muru_summon_blood_elves_periodic() : SpellScriptLoader("spell_muru_summon_blood_elves_periodic") { } class spell_muru_summon_blood_elves_periodic_AuraScript : public AuraScript { PrepareAuraScript(spell_muru_summon_blood_elves_periodic_AuraScript); void HandleApply(AuraEffect const* aurEff, AuraEffectHandleModes /*mode*/) { // first tick after 10 seconds GetAura()->GetEffect(aurEff->GetEffIndex())->SetPeriodicTimer(10000); } void OnPeriodic(AuraEffect const* /*aurEff*/) { GetUnitOwner()->CastSpell(GetUnitOwner(), SPELL_SUMMON_FURY_MAGE1, true); GetUnitOwner()->CastSpell(GetUnitOwner(), SPELL_SUMMON_FURY_MAGE2, true); GetUnitOwner()->CastSpell(GetUnitOwner(), SPELL_SUMMON_BERSERKER1, true); GetUnitOwner()->CastSpell(GetUnitOwner(), SPELL_SUMMON_BERSERKER2, true); GetUnitOwner()->CastSpell(GetUnitOwner(), SPELL_SUMMON_BERSERKER1, true); GetUnitOwner()->CastSpell(GetUnitOwner(), SPELL_SUMMON_BERSERKER2, true); } void Register() override { OnEffectApply += AuraEffectApplyFn(spell_muru_summon_blood_elves_periodic_AuraScript::HandleApply, EFFECT_0, SPELL_AURA_PERIODIC_DUMMY, AURA_EFFECT_HANDLE_REAL); OnEffectPeriodic += AuraEffectPeriodicFn(spell_muru_summon_blood_elves_periodic_AuraScript::OnPeriodic, EFFECT_0, SPELL_AURA_PERIODIC_DUMMY); } }; AuraScript* GetAuraScript() const override { return new spell_muru_summon_blood_elves_periodic_AuraScript(); } }; class spell_muru_darkness : public SpellScriptLoader { public: spell_muru_darkness() : SpellScriptLoader("spell_muru_darkness") { } class spell_muru_darkness_AuraScript : public AuraScript { PrepareAuraScript(spell_muru_darkness_AuraScript); void OnPeriodic(AuraEffect const* aurEff) { if (aurEff->GetTickNumber() == 3) for (uint8 i = 0; i < 8; ++i) GetUnitOwner()->CastSpell(GetUnitOwner(), SPELL_SUMMON_DARK_FIEND + i, true); } void Register() override { OnEffectPeriodic += AuraEffectPeriodicFn(spell_muru_darkness_AuraScript::OnPeriodic, EFFECT_2, SPELL_AURA_PERIODIC_DUMMY); } }; AuraScript* GetAuraScript() const override { return new spell_muru_darkness_AuraScript(); } }; class spell_entropius_negative_energy : public SpellScriptLoader { public: spell_entropius_negative_energy() : SpellScriptLoader("spell_entropius_negative_energy") { } class spell_entropius_negative_energy_SpellScript : public SpellScript { PrepareSpellScript(spell_entropius_negative_energy_SpellScript); bool Load() override { return GetCaster()->GetTypeId() == TYPEID_UNIT; } void FilterTargets(std::list& targets) { Acore::Containers::RandomResize(targets, GetCaster()->GetAI()->GetData(DATA_NEGATIVE_ENERGY_TARGETS)); } void HandleScriptEffect(SpellEffIndex effIndex) { PreventHitDefaultEffect(effIndex); if (Unit* target = GetHitUnit()) GetCaster()->CastSpell(target, SPELL_NEGATIVE_ENERGY_CHAIN, true); } void Register() override { OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_entropius_negative_energy_SpellScript::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY); OnEffectHitTarget += SpellEffectFn(spell_entropius_negative_energy_SpellScript::HandleScriptEffect, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT); } }; SpellScript* GetSpellScript() const override { return new spell_entropius_negative_energy_SpellScript(); } }; class spell_entropius_void_zone_visual : public SpellScriptLoader { public: spell_entropius_void_zone_visual() : SpellScriptLoader("spell_entropius_void_zone_visual") { } class spell_entropius_void_zone_visual_AuraScript : public AuraScript { PrepareAuraScript(spell_entropius_void_zone_visual_AuraScript); void HandleApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) { SetDuration(3000); } void HandleRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) { GetUnitOwner()->CastSpell(GetUnitOwner(), SPELL_SUMMON_DARK_FIEND_ENTROPIUS, true); } void Register() override { OnEffectApply += AuraEffectApplyFn(spell_entropius_void_zone_visual_AuraScript::HandleApply, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL); OnEffectRemove += AuraEffectRemoveFn(spell_entropius_void_zone_visual_AuraScript::HandleApply, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL); } }; AuraScript* GetAuraScript() const override { return new spell_entropius_void_zone_visual_AuraScript(); } }; class spell_entropius_black_hole_effect : public SpellScriptLoader { public: spell_entropius_black_hole_effect() : SpellScriptLoader("spell_entropius_black_hole_effect") { } class spell_entropius_black_hole_effect_SpellScript : public SpellScript { PrepareSpellScript(spell_entropius_black_hole_effect_SpellScript); void HandlePull(SpellEffIndex effIndex) { PreventHitDefaultEffect(effIndex); Unit* target = GetHitUnit(); if (!target) return; Position pos; if (target->GetDistance(GetCaster()) < 5.0f) { float o = frand(0, 2 * M_PI); pos.Relocate(GetCaster()->GetPositionX() + 4.0f * cos(o), GetCaster()->GetPositionY() + 4.0f * sin(o), GetCaster()->GetPositionZ() + frand(10.0f, 15.0f)); } else pos.Relocate(GetCaster()->GetPositionX(), GetCaster()->GetPositionY(), GetCaster()->GetPositionZ() + 1.0f); float speedXY = float(GetSpellInfo()->Effects[effIndex].MiscValue) * 0.1f; float speedZ = target->GetDistance(pos) / speedXY * 0.5f * Movement::gravity; target->GetMotionMaster()->MoveJump(pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ(), speedXY, speedZ); } void Register() override { OnEffectHitTarget += SpellEffectFn(spell_entropius_black_hole_effect_SpellScript::HandlePull, EFFECT_0, SPELL_EFFECT_PULL_TOWARDS_DEST); } }; SpellScript* GetSpellScript() const override { return new spell_entropius_black_hole_effect_SpellScript(); } }; void AddSC_boss_muru() { new boss_muru(); new boss_entropius(); new npc_singularity(); new spell_muru_summon_blood_elves_periodic(); new spell_muru_darkness(); new spell_entropius_negative_energy(); new spell_entropius_void_zone_visual(); new spell_entropius_black_hole_effect(); }