/* * This file is part of the TrinityCore 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 General Public License as published by the * Free Software Foundation; either version 2 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 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 "ScriptMgr.h" #include "InstanceScript.h" #include "ObjectAccessor.h" #include "ScriptedCreature.h" #include "SpellAuraEffects.h" #include "SpellScript.h" #include "sunwell_plateau.h" enum Spells { // Muru's spells SPELL_OPEN_PORTAL_PERIODIC = 45994, SPELL_DARKNESS_PERIODIC = 45998, SPELL_NEGATIVE_ENERGY_PERIODIC = 46009, SPELL_SUMMON_VOID_SPAWN = 46071, SPELL_SUMMON_BLOOD_ELVES_SCRIPT = 46050, SPELL_SUMMON_BLOOD_ELVES_PERIODIC = 46041, SPELL_OPEN_ALL_PORTALS = 46177, SPELL_SUMMON_ENTROPIUS = 46217, SPELL_ENRAGE = 26662, SPELL_SUMMON_DARK_FIEND_0 = 46000, SPELL_SUMMON_DARK_FIEND_1 = 46001, SPELL_SUMMON_DARK_FIEND_2 = 46002, SPELL_SUMMON_DARK_FIEND_3 = 46003, SPELL_SUMMON_DARK_FIEND_4 = 46004, SPELL_SUMMON_DARK_FIEND_5 = 46005, SPELL_SUMMON_DARK_FIEND_6 = 46006, SPELL_SUMMON_DARK_FIEND_7 = 46007, SPELL_SUMMON_BERSERKER = 46037, SPELL_SUMMON_BERSERKER_2 = 46040, SPELL_SUMMON_FURY_MAGE = 46038, SPELL_SUMMON_FURY_MAGE_2 = 46039, // Entropius's spells SPELL_ENTROPIUS_COSMETIC_SPAWN = 46223, SPELL_DARKNESS_E = 46269, SPELL_NEGATIVE_ENERGY_PERIODIC_E = 46284, SPELL_BLACKHOLE = 46282, SPELL_SUMMON_DARKFIEND_E = 46263, // Myruu's Portal Target SPELL_SUMMON_VOID_SENTINEL_SUMMONER = 45978, SPELL_SUMMON_VOID_SENTINEL_SUMMONER_VISUAL = 45989, SPELL_SUMMON_VOID_SENTINEL = 45988, SPELL_TRANSFORM_VISUAL_MISSILE = 46205, TRANSFORM_VISUAL_MISSILE_1 = 46208, TRANSFORM_VISUAL_MISSILE_2 = 46178, SPELL_OPEN_PORTAL = 45977, SPELL_OPEN_PORTAL_2 = 45976, //Dark Fiend Spells SPELL_DARKFIEND_DAMAGE = 45944, SPELL_DARKFIEND_VISUAL = 45936, SPELL_DARKFIEND_SKIN = 45934, // Void Sentinel's spells SPELL_SHADOW_PULSE_PERIODIC = 46086, SPELL_VOID_BLAST = 46161, //Black Hole Spells SPELL_BLACKHOLE_SUMMON_VISUAL = 46242, SPELL_BLACKHOLE_SUMMON_VISUAL_2 = 46247, SPELL_BLACKHOLE_PASSIVE = 46228, SPELL_BLACK_HOLE_VISUAL_2 = 46235 }; enum Phases { PHASE_ONE = 1, PHASE_TWO = 2 }; enum Misc { MAX_VOID_SPAWNS = 6, MAX_SUMMON_BLOOD_ELVES = 4, MAX_SUMMON_DARK_FIEND = 8 }; uint32 const SummonDarkFiendSpells[MAX_SUMMON_DARK_FIEND] = { SPELL_SUMMON_DARK_FIEND_0, SPELL_SUMMON_DARK_FIEND_1, SPELL_SUMMON_DARK_FIEND_2, SPELL_SUMMON_DARK_FIEND_3, SPELL_SUMMON_DARK_FIEND_4, SPELL_SUMMON_DARK_FIEND_5, SPELL_SUMMON_DARK_FIEND_6, SPELL_SUMMON_DARK_FIEND_7 }; uint32 const SummonBloodElvesSpells[MAX_SUMMON_BLOOD_ELVES] = { SPELL_SUMMON_BERSERKER, SPELL_SUMMON_BERSERKER_2, SPELL_SUMMON_FURY_MAGE, SPELL_SUMMON_FURY_MAGE_2 }; class VoidSpawnSummon : public BasicEvent { public: explicit VoidSpawnSummon(Creature* owner) : _owner(owner) { } bool Execute(uint64 /*time*/, uint32 /*diff*/) { _owner->CastSpell(nullptr, SPELL_SUMMON_VOID_SENTINEL, true); return true; } private: Creature* _owner; }; struct boss_entropius : public BossAI { boss_entropius(Creature* creature) : BossAI(creature, DATA_MURU) { } void Reset() override { _Reset(); DoCast(me, SPELL_ENTROPIUS_COSMETIC_SPAWN, true); } void ScheduleTasks() override { scheduler.Schedule(Milliseconds(2000), [this](TaskContext /*context*/) { DoResetPortals(); DoCastAOE(SPELL_NEGATIVE_ENERGY_PERIODIC_E, true); }); scheduler.Schedule(Seconds(15), [this](TaskContext context) { DoCastAOE(SPELL_DARKNESS_E, true); DoCastAOE(SPELL_BLACKHOLE, true); context.Repeat(); }); } void JustSummoned(Creature* summon) override { switch (summon->GetEntry()) { case NPC_DARK_FIENDS: summon->CastSpell(summon, SPELL_DARKFIEND_VISUAL); break; case NPC_DARKNESS: summon->SetReactState(REACT_PASSIVE); summon->CastSpell(summon, SPELL_BLACKHOLE); summon->CastSpell(summon, SPELL_SUMMON_DARKFIEND_E, true); break; } summons.Summon(summon); } void EnterEvadeMode(EvadeReason /*why*/) override { if (Creature* muru = instance->GetCreature(DATA_MURU)) muru->AI()->EnterEvadeMode(); DoResetPortals(); summons.DespawnAll(); me->DespawnOrUnsummon(); } void JustDied(Unit* /*killer*/) override { _JustDied(); if (Creature* muru = instance->GetCreature(DATA_MURU)) muru->DisappearAndDie(); } void UpdateAI(uint32 diff) override { if (!UpdateVictim()) return; scheduler.Update(diff); } void DoResetPortals() { std::list portals; me->GetCreatureListWithEntryInGrid(portals, NPC_MURU_PORTAL_TARGET, 100.0f); for (Creature* portal : portals) portal->RemoveAllAuras(); } }; struct boss_muru : public BossAI { boss_muru(Creature* creature) : BossAI(creature, DATA_MURU) { Initialize(); SetCombatMovement(false); } void Initialize() { _hasEnraged = false; _phase = PHASE_ONE; _entropiusGUID.Clear(); } void Reset() override { _Reset(); Initialize(); me->SetUninteractible(false); me->SetVisible(true); } void EnterEvadeMode(EvadeReason /*why*/) override { BossAI::EnterEvadeMode(); if (Creature* entropius = ObjectAccessor::GetCreature(*me, _entropiusGUID)) entropius->AI()->EnterEvadeMode(); } void ScheduleTasks() override { scheduler.Schedule(Minutes(10), [this](TaskContext /*context*/) { if (Creature* entropius = ObjectAccessor::GetCreature(*me, _entropiusGUID)) entropius->CastSpell(entropius, SPELL_ENRAGE); DoCast(me, SPELL_ENRAGE); _hasEnraged = true; }); scheduler.Schedule(Seconds(10), [this](TaskContext /*context*/) { DoCast(me, SPELL_SUMMON_BLOOD_ELVES_SCRIPT, true); DoCast(me, SPELL_SUMMON_BLOOD_ELVES_PERIODIC, true); }); } void JustEngagedWith(Unit* who) override { BossAI::JustEngagedWith(who); DoCast(me, SPELL_OPEN_PORTAL_PERIODIC, true); DoCast(me, SPELL_DARKNESS_PERIODIC, true); DoCast(me, SPELL_NEGATIVE_ENERGY_PERIODIC, true); } void DamageTaken(Unit* /*done_by*/, uint32& damage, DamageEffectType /*damageType*/, SpellInfo const* /*spellInfo = nullptr*/) override { if (damage >= me->GetHealth()) { damage = me->GetHealth() - 1; if (_phase != PHASE_ONE) return; _phase = PHASE_TWO; me->RemoveAllAuras(); DoCast(me, SPELL_OPEN_ALL_PORTALS, true); me->SetUninteractible(true); scheduler.Schedule(Seconds(6), [this](TaskContext /*context*/) { DoCast(me, SPELL_SUMMON_ENTROPIUS, true); }); } } void JustSummoned(Creature* summon) override { if (summon->GetEntry() == NPC_ENTROPIUS) { me->SetVisible(false); _entropiusGUID = summon->GetGUID(); DoZoneInCombat(summon); if (_hasEnraged) summon->CastSpell(summon, SPELL_ENRAGE, true); return; } BossAI::JustSummoned(summon); } void UpdateAI(uint32 diff) override { if (!UpdateVictim()) return; scheduler.Update(diff); } private: ObjectGuid _entropiusGUID; bool _hasEnraged; uint8 _phase; }; struct npc_muru_portal : public ScriptedAI { npc_muru_portal(Creature* creature) : ScriptedAI(creature) { } void JustSummoned(Creature* summon) override { DoCast(summon, SPELL_SUMMON_VOID_SENTINEL_SUMMONER_VISUAL, true); summon->m_Events.AddEvent(new VoidSpawnSummon(summon), summon->m_Events.CalculateTime(1500ms)); } void SpellHit(WorldObject* /*caster*/, SpellInfo const* spellInfo) override { switch (spellInfo->Id) { case SPELL_OPEN_ALL_PORTALS: DoCastAOE(SPELL_OPEN_PORTAL, true); DoCastAOE(SPELL_TRANSFORM_VISUAL_MISSILE, true); break; case SPELL_OPEN_PORTAL_2: DoCastAOE(SPELL_OPEN_PORTAL, true); _scheduler.Schedule(Seconds(6), [this](TaskContext /*context*/) { DoCastAOE(SPELL_SUMMON_VOID_SENTINEL_SUMMONER, true); }); break; default: break; } } void UpdateAI(uint32 diff) override { _scheduler.Update(diff); } private: TaskScheduler _scheduler; }; struct npc_dark_fiend : public ScriptedAI { npc_dark_fiend(Creature* creature) : ScriptedAI(creature) { Initialize(); } void Initialize() { me->SetDisplayFromModel(1); me->SetReactState(REACT_PASSIVE); DoCast(me, SPELL_DARKFIEND_SKIN, true); _scheduler.Schedule(Seconds(2), [this](TaskContext /*context*/) { me->SetReactState(REACT_AGGRESSIVE); me->SetUninteractible(false); if (Creature* _summoner = ObjectAccessor::GetCreature(*me, _summonerGUID)) if (Unit* target = _summoner->AI()->SelectTarget(SelectTargetMethod::Random, 0)) AttackStart(target); }); _scheduler.Schedule(Seconds(3), [this](TaskContext context) { if (me->IsWithinDist(me->GetVictim(), 5.0f) && me->HasAura(SPELL_DARKFIEND_SKIN)) { DoCastAOE(SPELL_DARKFIEND_DAMAGE, false); me->DisappearAndDie(); } context.Repeat(Milliseconds(500)); }); } void IsSummonedBy(WorldObject* summoner) override { _summonerGUID = summoner->GetGUID(); } bool CanAIAttack(Unit const* /*target*/) const override { return me->HasAura(SPELL_DARKFIEND_SKIN); } void UpdateAI(uint32 diff) override { _scheduler.Update(diff); } private: TaskScheduler _scheduler; ObjectGuid _summonerGUID; }; struct npc_void_sentinel : public ScriptedAI { npc_void_sentinel(Creature* creature) : ScriptedAI(creature) { _instance = me->GetInstanceScript(); } void IsSummonedBy(WorldObject* /*summoner*/) override { if (Creature* muru = _instance->GetCreature(DATA_MURU)) muru->AI()->JustSummoned(me); } void JustEngagedWith(Unit* /*who*/) override { DoCast(me, SPELL_SHADOW_PULSE_PERIODIC, true); _scheduler.Schedule(Seconds(45), [this](TaskContext context) { DoCastVictim(SPELL_VOID_BLAST, false); context.Repeat(); }); } void JustDied(Unit* /*killer*/) override { for (uint8 i = 0; i < MAX_VOID_SPAWNS; ++i) DoCastAOE(SPELL_SUMMON_VOID_SPAWN, true); } void UpdateAI(uint32 diff) override { _scheduler.Update(diff); } private: TaskScheduler _scheduler; InstanceScript* _instance; }; struct npc_blackhole : public ScriptedAI { npc_blackhole(Creature* creature) : ScriptedAI(creature) { _instance = creature->GetInstanceScript(); } void Reset() override { me->SetReactState(REACT_PASSIVE); DoCast(SPELL_BLACKHOLE_SUMMON_VISUAL); _scheduler.Schedule(Seconds(15), [this](TaskContext /*context*/) { me->DisappearAndDie(); }); _scheduler.Schedule(Seconds(1), [this](TaskContext context) { switch (context.GetRepeatCounter()) { case 0: me->SetReactState(REACT_AGGRESSIVE); DoCast(SPELL_BLACKHOLE_SUMMON_VISUAL_2); if (Unit* victim = ObjectAccessor::GetUnit(*me, _instance->GetGuidData(DATA_PLAYER_GUID))) AttackStart(victim); context.Repeat(Milliseconds(1200)); break; case 1: DoCast(SPELL_BLACKHOLE_SUMMON_VISUAL); context.Repeat(Seconds(2)); break; case 2: DoCast(SPELL_BLACKHOLE_PASSIVE); DoCast(SPELL_BLACK_HOLE_VISUAL_2); break; default: break; } }); } void UpdateAI(uint32 diff) override { _scheduler.Update(diff); } private: TaskScheduler _scheduler; InstanceScript* _instance; }; // 46050 - Summon Blood Elves Script class spell_summon_blood_elves_script : public SpellScript { bool Validate(SpellInfo const* /*spell*/) override { return ValidateSpellInfo(SummonBloodElvesSpells); } void HandleScript(SpellEffIndex /*effIndex*/) { for (uint8 i = 0; i < MAX_SUMMON_BLOOD_ELVES; ++i) GetCaster()->CastSpell(nullptr, SummonBloodElvesSpells[urand(0,3)], true); } void Register() override { OnEffectHitTarget += SpellEffectFn(spell_summon_blood_elves_script::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT); } }; // 45996 - Darkness class spell_muru_darkness : public SpellScript { bool Validate(SpellInfo const* /*spell*/) override { return ValidateSpellInfo(SummonDarkFiendSpells); } void HandleAfterCast() { for (uint8 i = 0; i < MAX_SUMMON_DARK_FIEND; ++i) GetCaster()->CastSpell(nullptr, SummonDarkFiendSpells[i], true); } void Register() override { AfterCast += SpellCastFn(spell_muru_darkness::HandleAfterCast); } }; // 45934 - Dark Fiend class spell_dark_fiend_skin : public AuraScript { void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) { if (GetTargetApplication()->GetRemoveMode() != AURA_REMOVE_BY_ENEMY_SPELL) return; if (Creature* target = GetTarget()->ToCreature()) { target->SetReactState(REACT_PASSIVE); target->AttackStop(); target->StopMoving(); target->CastSpell(target, SPELL_DARKFIEND_VISUAL, true); target->DespawnOrUnsummon(3s); } } void Register() override { AfterEffectRemove += AuraEffectRemoveFn(spell_dark_fiend_skin::OnRemove, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL); } }; // 46205 - Transform Visual Missile Periodic class spell_transform_visual_missile_periodic : public AuraScript { void OnPeriodic(AuraEffect const* /*aurEff*/) { GetTarget()->CastSpell(nullptr, RAND(TRANSFORM_VISUAL_MISSILE_1, TRANSFORM_VISUAL_MISSILE_2), true); } void Register() override { OnEffectPeriodic += AuraEffectPeriodicFn(spell_transform_visual_missile_periodic::OnPeriodic, EFFECT_0, SPELL_AURA_PERIODIC_DUMMY); } }; // 46041 - Summon Blood Elves Periodic class spell_summon_blood_elves_periodic : public AuraScript { void OnPeriodic(AuraEffect const* /*aurEff*/) { GetTarget()->CastSpell(nullptr, SPELL_SUMMON_BLOOD_ELVES_SCRIPT, true); } void Register() override { OnEffectPeriodic += AuraEffectPeriodicFn(spell_summon_blood_elves_periodic::OnPeriodic, EFFECT_0, SPELL_AURA_PERIODIC_DUMMY); } }; // 46284 - Negative Energy Periodic class spell_muru_negative_energy_periodic : public AuraScript { bool Validate(SpellInfo const* spellInfo) override { return ValidateSpellEffect({ { spellInfo->Id, EFFECT_0 } }) && ValidateSpellInfo({ spellInfo->GetEffect(EFFECT_0).TriggerSpell }); } void PeriodicTick(AuraEffect const* aurEff) { PreventDefaultAction(); CastSpellExtraArgs args(aurEff); args.AddSpellMod(SPELLVALUE_MAX_TARGETS, aurEff->GetTickNumber() / 10 + 1); GetTarget()->CastSpell(nullptr, aurEff->GetSpellEffectInfo().TriggerSpell, args); } void Register() override { OnEffectPeriodic += AuraEffectPeriodicFn(spell_muru_negative_energy_periodic::PeriodicTick, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL); } }; void AddSC_boss_muru() { RegisterSunwellPlateauCreatureAI(boss_muru); RegisterSunwellPlateauCreatureAI(boss_entropius); RegisterSunwellPlateauCreatureAI(npc_muru_portal); RegisterSunwellPlateauCreatureAI(npc_dark_fiend); RegisterSunwellPlateauCreatureAI(npc_void_sentinel); RegisterSunwellPlateauCreatureAI(npc_blackhole); RegisterSpellScript(spell_summon_blood_elves_script); RegisterSpellScript(spell_muru_darkness); RegisterSpellScript(spell_dark_fiend_skin); RegisterSpellScript(spell_transform_visual_missile_periodic); RegisterSpellScript(spell_summon_blood_elves_periodic); RegisterSpellScript(spell_muru_negative_energy_periodic); }