/* * 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 "black_temple.h" #include "ObjectAccessor.h" #include "ScriptedCreature.h" #include "SpellAuraEffects.h" #include "SpellScript.h" enum Spells { // Wrathbone Flayer SPELL_CLEAVE = 15496, SPELL_IGNORED = 39544, SPELL_SUMMON_CHANNEL = 40094, // Angered Soul Fragment SPELL_GREATER_INVISIBILITY = 41253, SPELL_ANGER = 41986, // Illidari Nightlord SPELL_SHADOW_INFERNO_DAMAGE = 39646 }; enum Creatures { NPC_BLOOD_MAGE = 22945, NPC_DEATHSHAPER = 22882 }; enum Events { // Wrathbone Flayer EVENT_GET_CHANNELERS = 1, EVENT_SET_CHANNELERS, EVENT_CLEAVE, EVENT_IGNORED }; enum Misc { GROUP_OUT_OF_COMBAT = 1 }; struct npc_wrathbone_flayer : public ScriptedAI { npc_wrathbone_flayer(Creature* creature) : ScriptedAI(creature) { Initialize(); _instance = creature->GetInstanceScript(); } void Initialize() { _enteredCombat = false; } void Reset() override { _events.ScheduleEvent(EVENT_GET_CHANNELERS, 3s); Initialize(); _bloodmageList.clear(); _deathshaperList.clear(); } void JustDied(Unit* /*killer*/) override { } void JustEngagedWith(Unit* /*who*/) override { _events.ScheduleEvent(EVENT_CLEAVE, 5s); _events.ScheduleEvent(EVENT_IGNORED, 7s); _enteredCombat = true; } void UpdateAI(uint32 diff) override { if (!_enteredCombat) { _events.Update(diff); while (uint32 eventId = _events.ExecuteEvent()) { switch (eventId) { case EVENT_GET_CHANNELERS: { std::list BloodMageList; me->GetCreatureListWithEntryInGrid(BloodMageList, NPC_BLOOD_MAGE, 15.0f); if (!BloodMageList.empty()) for (std::list::const_iterator itr = BloodMageList.begin(); itr != BloodMageList.end(); ++itr) { _bloodmageList.push_back((*itr)->GetGUID()); if ((*itr)->isDead()) (*itr)->Respawn(); } std::list DeathShaperList; me->GetCreatureListWithEntryInGrid(DeathShaperList, NPC_DEATHSHAPER, 15.0f); if (!DeathShaperList.empty()) for (std::list::const_iterator itr = DeathShaperList.begin(); itr != DeathShaperList.end(); ++itr) { _deathshaperList.push_back((*itr)->GetGUID()); if ((*itr)->isDead()) (*itr)->Respawn(); } _events.ScheduleEvent(EVENT_SET_CHANNELERS, 3s); break; } case EVENT_SET_CHANNELERS: { for (ObjectGuid guid : _bloodmageList) if (Creature* bloodmage = ObjectAccessor::GetCreature(*me, guid)) bloodmage->CastSpell(nullptr, SPELL_SUMMON_CHANNEL); for (ObjectGuid guid : _deathshaperList) if (Creature* deathshaper = ObjectAccessor::GetCreature(*me, guid)) deathshaper->CastSpell(nullptr, SPELL_SUMMON_CHANNEL); _events.ScheduleEvent(EVENT_SET_CHANNELERS, 12s); break; } default: break; } } } if (!UpdateVictim()) return; _events.Update(diff); while (uint32 eventId = _events.ExecuteEvent()) { switch (eventId) { case EVENT_CLEAVE: DoCastVictim(SPELL_CLEAVE); _events.ScheduleEvent(EVENT_CLEAVE, 1s, 2s); break; case EVENT_IGNORED: if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0)) DoCast(target, SPELL_IGNORED); _events.ScheduleEvent(EVENT_IGNORED, 10s); break; default: break; } } } private: InstanceScript* _instance; EventMap _events; GuidList _bloodmageList; GuidList _deathshaperList; bool _enteredCombat; }; struct npc_angered_soul_fragment : public ScriptedAI { npc_angered_soul_fragment(Creature* creature) : ScriptedAI(creature) { } void Reset() override { _scheduler.CancelAll(); _scheduler.Schedule(Seconds(1), GROUP_OUT_OF_COMBAT, [this](TaskContext invi) { DoCastSelf(SPELL_GREATER_INVISIBILITY); /* Workaround - On Retail creature appear and "vanish" again periodically, but i cant find packets with UPDATE_AURA on sniffs about it */ _scheduler.Schedule(Seconds(5), Seconds(10), GROUP_OUT_OF_COMBAT, [this](TaskContext /*context*/) { me->RemoveAurasDueToSpell(SPELL_GREATER_INVISIBILITY); }); invi.Repeat(Seconds(15), Seconds(25)); }); } void JustEngagedWith(Unit* /*who*/) override { me->RemoveAurasDueToSpell(SPELL_GREATER_INVISIBILITY); _scheduler.CancelGroup(GROUP_OUT_OF_COMBAT); _scheduler.Schedule(Seconds(1), [this](TaskContext anger) { Unit* target = me->GetVictim(); if (target && me->IsWithinMeleeRange(target)) DoCastSelf(SPELL_ANGER); else anger.Repeat(Seconds(1)); }); } void UpdateAI(uint32 diff) override { _scheduler.Update(diff); if (!UpdateVictim()) return; if (me->HasUnitState(UNIT_STATE_CASTING)) return; } private: TaskScheduler _scheduler; }; // 41986 - Anger class spell_soul_fragment_anger : public SpellScript { void HandleKill() { if (Creature* caster = GetCaster()->ToCreature()) caster->DespawnOrUnsummon(Milliseconds(200)); } void Register() override { AfterCast += SpellCastFn(spell_soul_fragment_anger::HandleKill); } }; // 39645 - Shadow Inferno class spell_illidari_nightlord_shadow_inferno : public AuraScript { bool Validate(SpellInfo const* /*spellInfo*/) override { return ValidateSpellInfo({ SPELL_SHADOW_INFERNO_DAMAGE }); } void OnPeriodic(AuraEffect const* aurEffect) { PreventDefaultAction(); int32 bp = aurEffect->GetTickNumber() * aurEffect->GetAmount(); GetUnitOwner()->CastSpell(GetUnitOwner(), SPELL_SHADOW_INFERNO_DAMAGE, CastSpellExtraArgs(TRIGGERED_FULL_MASK).AddSpellBP0(bp)); } void Register() override { OnEffectPeriodic += AuraEffectPeriodicFn(spell_illidari_nightlord_shadow_inferno::OnPeriodic, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL); } }; void AddSC_black_temple() { RegisterBlackTempleCreatureAI(npc_wrathbone_flayer); RegisterBlackTempleCreatureAI(npc_angered_soul_fragment); RegisterSpellScript(spell_soul_fragment_anger); RegisterSpellScript(spell_illidari_nightlord_shadow_inferno); }