diff options
author | Keader <keader.android@gmail.com> | 2017-01-01 21:11:15 -0200 |
---|---|---|
committer | DoctorKraft <DoctorKraft@users.noreply.github.com> | 2018-03-18 00:19:49 +0100 |
commit | 36910585c9cb27e22ecceca647909b4b20a2c087 (patch) | |
tree | 10e8fa8b0158d3d7d64d36461ebf7c1c8a786686 | |
parent | 7d96b98d51c5f3fd754f5b0fe97f0926d88af5c8 (diff) |
Core/Scripts: Illidari Council Rewrite (#18546)
Thanks to Sirikfoll, Krudor and Offl for all help
(cherry picked from commit 5af1fa22733c64e97f60967b36ea970a355d0598)
5 files changed, 1038 insertions, 953 deletions
diff --git a/sql/updates/world/master/2018_03_17_48_world_2017_01_01_06_world.sql b/sql/updates/world/master/2018_03_17_48_world_2017_01_01_06_world.sql new file mode 100644 index 00000000000..8e562ccdc56 --- /dev/null +++ b/sql/updates/world/master/2018_03_17_48_world_2017_01_01_06_world.sql @@ -0,0 +1,73 @@ +DELETE FROM `creature` WHERE `id` IN(22952,22950,22949,22951); +DELETE FROM `creature_summon_groups` WHERE `summonerId`=23426; -- Illidari Council Trigger +INSERT INTO `creature_summon_groups` (`summonerId`,`summonerType`,`groupId`,`entry`,`position_x`,`position_y`,`position_z`,`orientation`,`summonType`,`summonTime`) VALUES +(23426,0,1,22952,697.495,310.651,277.527,3.1765 ,6,3600000), -- Veras Darkshadow +(23426,0,1,22950,700.792,307.192,277.526,3.14159,6,3600000), -- High Nethermancer Zerevor +(23426,0,1,22949,700.739,302.722,277.526,3.10669,6,3600000), -- Gathios the Shatterer +(23426,0,1,22951,697.409,299.377,277.526,3.07178,6,3600000); -- Lady Malande + +DELETE FROM `conditions` WHERE `SourceTypeOrReferenceId`=13 AND `SourceEntry`=41333; -- Empyreal Equivalency +INSERT INTO `conditions` (`SourceTypeOrReferenceId`, `SourceGroup`, `SourceEntry`, `SourceId`, `ElseGroup`, `ConditionTypeOrReference`, `ConditionTarget`, `ConditionValue1`, `ConditionValue2`, `ConditionValue3`, `NegativeCondition`, `ErrorType`, `ErrorTextId`, `ScriptName`, `Comment`) VALUES +(13,1,41333,0,0,31,0,3,22950,0,0,0,0,'','Effect_0 hits High Nethermancer Zerevor'), +(13,1,41333,0,1,31,0,3,22949,0,0,0,0,'','Effect_0 hits Gathios the Shatterer'), +(13,1,41333,0,2,31,0,3,22951,0,0,0,0,'','Effect_0 hits Lady Malande'), +(13,1,41333,0,3,31,0,3,22952,0,0,0,0,'','Effect_0 hits Veras Darkshadow'); + +DELETE FROM `conditions` WHERE `SourceTypeOrReferenceId`=13 AND `SourceEntry`=41499; -- Empyreal Balance +INSERT INTO `conditions` (`SourceTypeOrReferenceId`, `SourceGroup`, `SourceEntry`, `SourceId`, `ElseGroup`, `ConditionTypeOrReference`, `ConditionTarget`, `ConditionValue1`, `ConditionValue2`, `ConditionValue3`, `NegativeCondition`, `ErrorType`, `ErrorTextId`, `ScriptName`, `Comment`) VALUES +(13,1,41499,0,0,31,0,3,22950,0,0,0,0,'','Effect_0 hits High Nethermancer Zerevor'), +(13,1,41499,0,1,31,0,3,22949,0,0,0,0,'','Effect_0 hits Gathios the Shatterer'), +(13,1,41499,0,2,31,0,3,22951,0,0,0,0,'','Effect_0 hits Lady Malande'), +(13,1,41499,0,3,31,0,3,22952,0,0,0,0,'','Effect_0 hits Veras Darkshadow'); + +DELETE FROM `conditions` WHERE `SourceTypeOrReferenceId`=13 AND `SourceEntry`=41342; -- Shared Rule +INSERT INTO `conditions` (`SourceTypeOrReferenceId`, `SourceGroup`, `SourceEntry`, `SourceId`, `ElseGroup`, `ConditionTypeOrReference`, `ConditionTarget`, `ConditionValue1`, `ConditionValue2`, `ConditionValue3`, `NegativeCondition`, `ErrorType`, `ErrorTextId`, `ScriptName`, `Comment`) VALUES +(13,1,41342,0,0,31,0,3,23426,0,0,0,0,'','Effect_0 hits The Illidari Council'); + +UPDATE `linked_respawn` SET `linkedGuid`=52479 WHERE `linkedGuid`=52762; + +UPDATE `creature_template` SET `flags_extra`=`flags_extra`|128, `ScriptName`='npc_veras_vanish_effect' WHERE `entry`=23451; +UPDATE `creature_template` SET `ScriptName`='boss_illidari_council' WHERE `entry`=23426; +UPDATE `creature_template` SET `ScriptName`='' WHERE `entry`=23499; + +DELETE FROM `spell_script_names` WHERE `ScriptName` IN( +'spell_illidari_council_empyreal_balance', +'spell_illidari_council_empyreal_equivalency', +'spell_illidari_council_balance_of_power', +'spell_illidari_council_deadly_strike', +'spell_illidari_council_deadly_poison', +'spell_illidari_council_judgement', +'spell_illidari_council_seal', +'spell_boss_lady_malande_shield', +'spell_illidari_council_reflective_shield', +'spell_illidari_dampen_magic'); +INSERT INTO `spell_script_names` (`spell_id`, `ScriptName`) VALUES +(41499,'spell_illidari_council_empyreal_balance'), +(41333,'spell_illidari_council_empyreal_equivalency'), +(41341,'spell_illidari_council_balance_of_power'), +(41480,'spell_illidari_council_deadly_strike'), +(41485,'spell_illidari_council_deadly_poison'), +(41467,'spell_illidari_council_judgement'), +(41469,'spell_illidari_council_seal'), +(41459,'spell_illidari_council_seal'), +(41475,'spell_illidari_council_reflective_shield'), +(41478,'spell_illidari_dampen_magic'); + +DELETE FROM `creature_text` WHERE `CreatureID` IN(22951,22949,22950,22952) AND (`GroupID` IN(3,4,5,6) OR (`GroupID`=2 AND `ID`=1)); +INSERT INTO `creature_text` (`CreatureID`,`GroupID`,`ID`,`Text`,`Type`,`Language`,`Probability`,`Emote`,`Duration`,`Sound`,`BroadcastTextId`,`TextRange`,`Comment`) VALUES +(22949,2,1,'You are MINE!',14,0,100,0,0,11427,21739,0,'council gath SPECIAL2'), +(22949,3,0,'Selama am\'oronor!',14,0,100,0,0,11423,21735,0,'council gath SLAY'), +(22949,4,0,'Well done!',14,0,100,0,0,11424,21736,0,'council gath SLAY_COMT'), +(22949,5,0,'Lord Illidan, I...',14,0,100,0,0,11425,21737,0,'council gath DEATH'), +(22951,2,1,'I\'m full of surprises!',14,0,100,0,0,11487,21719,0,'council mala SPECIAL2'), +(22951,3,0,'My work is done.',14,0,100,0,0,11483,21712,0,'council mala SLAY'), +(22951,4,0,'As it should be.',14,0,100,0,0,11484,21713,0,'council mala SLAY_COMT'), +(22951,5,0,'Destiny... awaits.',14,0,100,0,0,11485,21715,0,'council mala DEATH'), +(22950,2,1,'Sha\'amoor ara mashal?',14,0,100,0,0,11445,21731,0,'council zere SPECIAL2'), +(22950,3,0,'Shorel\'aran.',14,0,100,0,0,11441,21725,0,'council zere SLAY'), +(22950,4,0,'Belesa menoor!',14,0,100,0,0,11442,21727,0,'council zere SLAY_COMT'), +(22950,5,0,'Diel ma\'ahn... orindel\'o.',14,0,100,0,0,11443,21729,0,'council zere DEATH'), +(22952,2,1,'Anar\'alah belore!',14,0,100,0,0,11529,21705,0,'council vera SPECIAL2'), +(22952,3,0,'Valiant effort.',14,0,100,0,0,11525,21699,0,'council vera SLAY'), +(22952,4,0,'A glorious kill!',14,0,100,0,0,11526,21701,0,'council vera SLAY_COMT'), +(22952,5,0,'You got... lucky.',14,0,100,0,0,11527,21703,0,'council vera DEATH'); diff --git a/src/server/game/Spells/SpellMgr.cpp b/src/server/game/Spells/SpellMgr.cpp index a959a40003b..5f29ef5eafe 100644 --- a/src/server/game/Spells/SpellMgr.cpp +++ b/src/server/game/Spells/SpellMgr.cpp @@ -2674,8 +2674,11 @@ void SpellMgr::LoadSpellInfoCorrections() const_cast<SpellEffectInfo*>(spellInfo->GetEffect(EFFECT_0))->SpellClassMask = flag128(685904631, 1151048, 0, 0); }); - // Death and Decay - ApplySpellFix({ 52212 }, [](SpellInfo* spellInfo) + ApplySpellFix({ + 52212, // Death and Decay + 41485, // Deadly Poison - Black Temple + 41487 // Envenom - Black Temple + }, [](SpellInfo* spellInfo) { spellInfo->AttributesEx6 |= SPELL_ATTR6_CAN_TARGET_INVISIBLE; }); diff --git a/src/server/scripts/Outland/BlackTemple/boss_illidari_council.cpp b/src/server/scripts/Outland/BlackTemple/boss_illidari_council.cpp new file mode 100644 index 00000000000..b9090aba09e --- /dev/null +++ b/src/server/scripts/Outland/BlackTemple/boss_illidari_council.cpp @@ -0,0 +1,959 @@ +/* + * Copyright (C) 2008-2018 TrinityCore <https://www.trinitycore.org/> + * + * 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 <http://www.gnu.org/licenses/>. + */ + +#include "ScriptMgr.h" +#include "ScriptedCreature.h" +#include "SpellScript.h" +#include "SpellAuraEffects.h" +#include "black_temple.h" +#include "GridNotifiers.h" +#include "PassiveAI.h" +#include "InstanceScript.h" + +enum Says +{ + SAY_COUNCIL_AGRO = 0, + SAY_COUNCIL_ENRAGE = 1, + SAY_COUNCIL_SPECIAL = 2, + SAY_COUNCIL_SLAY = 3, + SAY_COUNCIL_COMNT = 4, + SAY_COUNCIL_DEATH = 5 +}; + +enum Spells +{ + // Illidari Council (Trigger) + SPELL_EMPYREAL_BALANCE = 41499, + SPELL_EMPYREAL_EQUIVALENCY = 41333, + + // Generic + SPELL_SHARED_RULE = 41342, + SPELL_BERSERK = 45078, + SPELL_BALANCE_OF_POWER = 41341, + SPELL_QUIET_SUICIDE = 3617, // Serverside spell + + // High Nethermancer Zerevor's + SPELL_FLAMESTRIKE = 41481, + SPELL_BLIZZARD = 41482, + SPELL_ARCANE_BOLT = 41483, + SPELL_ARCANE_EXPLOSION = 41524, + SPELL_DAMPEN_MAGIC = 41478, + + // Lady Malande's + SPELL_EMPOWERED_SMITE = 41471, + SPELL_CIRCLE_OF_HEALING = 41455, + SPELL_REFLECTIVE_SHIELD = 41475, + SPELL_REFLECTIVE_SHIELD_DAMAGE = 33619, + SPELL_DIVINE_WRATH = 41472, + + // Gathios the Shatterer's + SPELL_BLESS_PROTECTION = 41450, + SPELL_BLESS_SPELL_WARDING = 41451, + SPELL_CONSECRATION = 41541, + SPELL_HAMMER_OF_JUSTICE = 41468, + SPELL_SEAL_OF_COMMAND = 41469, + SPELL_SEAL_OF_BLOOD = 41459, + SPELL_CHROMATIC_AURA = 41453, + SPELL_DEVOTION_AURA = 41452, + SPELL_JUDGEMENT_PRIMER = 41473, + SPELL_JUDGEMENT = 41467, + SPELL_JUDGEMENT_OF_COMMAND = 41470, + SPELL_JUDGEMENT_OF_BLOOD = 41461, + + // Veras Darkshadow's + SPELL_DEADLY_STRIKE = 41480, + SPELL_DEADLY_POISON = 41485, + SPELL_ENVENOM = 41487, + SPELL_VANISH = 41476, + + // Veras Vanish Effect + SPELL_BIRTH = 40031, + SPELL_ENVENOM_DUMMY = 41510 +}; + +enum IllidariEvents +{ + EVENT_EMPYREAL_EQUIVALENCY = 1, + EVENT_VANISH, + EVENT_DEADLY_STRIKE, + EVENT_FLAMESTRIKE, + EVENT_BLIZZARD, + EVENT_ARCANE_EXPLOSION, + EVENT_ARCANE_EXPLOSION_CHECK, + EVENT_DAMPEN_MAGIC, + EVENT_BLESS, + EVENT_CONSECRATION, + EVENT_AURA, + EVENT_JUDGEMENT, + EVENT_HAMMER_OF_JUSTICE, + EVENT_CIRCLE_OF_HEALING, + EVENT_REFLECTIVE_SHIELD, + EVENT_DIVINE_WRATH, + EVENT_BERSERK +}; + +enum IllidariMisc +{ + SUMMON_COUNCIL_GROUP = 1, + ACTION_REFRESH_DAMPEN +}; + +uint32 const CouncilData[4] = +{ + DATA_GATHIOS_THE_SHATTERER, + DATA_HIGH_NETHERMANCER_ZEREVOR, + DATA_LADY_MALANDE, + DATA_VERAS_DARKSHADOW +}; + +static uint32 GetRandomBossExcept(uint32 exception) +{ + std::vector<uint32> bossData; + for (uint32 data : CouncilData) + if (data != exception) + bossData.emplace_back(data); + + return bossData[urand(0, 3)]; +} + +class boss_illidari_council : public CreatureScript +{ +public: + boss_illidari_council() : CreatureScript("boss_illidari_council") { } + + struct boss_illidari_councilAI : public BossAI + { + boss_illidari_councilAI(Creature* creature) : BossAI(creature, DATA_ILLIDARI_COUNCIL), _inCombat(false) { } + + void Reset() override + { + _Reset(); + _inCombat = false; + me->SummonCreatureGroup(SUMMON_COUNCIL_GROUP); + DoCastSelf(SPELL_EMPYREAL_BALANCE, true); + } + + void EnterCombat(Unit* /*who*/) override + { + if (!_inCombat) + { + _inCombat = true; + _EnterCombat(); + for (uint32 bossData : CouncilData) + { + if (Creature* council = instance->GetCreature(bossData)) + { + instance->SendEncounterUnit(ENCOUNTER_FRAME_ENGAGE, council); + DoZoneInCombat(council); + } + } + events.ScheduleEvent(EVENT_EMPYREAL_EQUIVALENCY, Seconds(2)); + events.ScheduleEvent(EVENT_BERSERK, Minutes(15)); + if (Creature* council = instance->GetCreature(CouncilData[urand(0, 3)])) + council->AI()->Talk(SAY_COUNCIL_AGRO); + } + } + + void EnterEvadeMode(EvadeReason /*why*/) override + { + if (!me->IsInEvadeMode()) + { + _inCombat = false; + for (uint32 bossData : CouncilData) + if (Creature* council = instance->GetCreature(bossData)) + instance->SendEncounterUnit(ENCOUNTER_FRAME_DISENGAGE, council); + + summons.DespawnAll(); + _DespawnAtEvade(); + } + } + + void JustDied(Unit* /*killer*/) override + { + _inCombat = false; + events.Reset(); + instance->SetBossState(DATA_ILLIDARI_COUNCIL, DONE); + + for (uint32 bossData : CouncilData) + { + if (Creature* council = instance->GetCreature(bossData)) + { + // Allow loot + instance->SendEncounterUnit(ENCOUNTER_FRAME_DISENGAGE, council); + council->LowerPlayerDamageReq(council->GetMaxHealth()); + council->CastSpell(council, SPELL_QUIET_SUICIDE, true); + } + } + } + + void UpdateAI(uint32 diff) override + { + if (!UpdateVictim()) + return; + + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + + events.Update(diff); + + while (uint32 eventId = events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_EMPYREAL_EQUIVALENCY: + DoCastSelf(SPELL_EMPYREAL_EQUIVALENCY, true); + events.Repeat(Seconds(2)); + break; + case EVENT_BERSERK: + for (uint32 bossData : CouncilData) + { + if (Creature* council = instance->GetCreature(bossData)) + { + council->CastSpell(council, SPELL_BERSERK, true); + council->AI()->Talk(SAY_COUNCIL_ENRAGE); + } + } + break; + default: + break; + } + + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + } + } + + private: + bool _inCombat; + }; + + CreatureAI* GetAI(Creature* creature) const override + { + return GetBlackTempleAI<boss_illidari_councilAI>(creature); + } +}; + +struct IllidariCouncilBossAI : public BossAI +{ + IllidariCouncilBossAI(Creature* creature, uint32 bossId) : BossAI(creature, bossId), _bossId(bossId) + { + SetBoundary(instance->GetBossBoundary(DATA_ILLIDARI_COUNCIL)); + } + + void Reset() override + { + me->SetCombatPulseDelay(0); + events.Reset(); + } + + void EnterCombat(Unit* /*who*/) override + { + me->SetCombatPulseDelay(5); + me->setActive(true); + if (Creature* illidari = instance->GetCreature(DATA_ILLIDARI_COUNCIL)) + DoZoneInCombat(illidari); + ScheduleTasks(); + } + + virtual void ScheduleTasks() = 0; + + void JustDied(Unit* /*killer*/) override + { + Talk(SAY_COUNCIL_DEATH); + } + + void EnterEvadeMode(EvadeReason why) override + { + if (Creature* illidari = instance->GetCreature(DATA_ILLIDARI_COUNCIL)) + illidari->AI()->EnterEvadeMode(why); + } + + void DamageTaken(Unit* who, uint32 &damage) override + { + if (damage >= me->GetHealth() && who->GetGUID() != me->GetGUID()) + damage = me->GetHealth() - 1; + } + + void KilledUnit(Unit* victim) override + { + if (victim->GetTypeId() == TYPEID_PLAYER) + Talk(SAY_COUNCIL_SLAY); + + if (roll_chance_i(30)) + if (Creature* boss = instance->GetCreature(GetRandomBossExcept(_bossId))) + boss->AI()->Talk(SAY_COUNCIL_COMNT); + } + +private: + uint32 _bossId; +}; + +class HammerTargetSelector : public std::unary_function<Unit*, bool> +{ +public: + HammerTargetSelector(Unit const* unit) : _me(unit) { } + + bool operator()(Unit* unit) const + { + return _me->IsInRange(unit, 10.0f, 40.0f); + } + +private: + Unit const* _me; +}; + +class boss_gathios_the_shatterer : public CreatureScript +{ +public: + boss_gathios_the_shatterer() : CreatureScript("boss_gathios_the_shatterer") { } + + struct boss_gathios_the_shattererAI : public IllidariCouncilBossAI + { + boss_gathios_the_shattererAI(Creature* creature) : IllidariCouncilBossAI(creature, DATA_GATHIOS_THE_SHATTERER) { } + + void ScheduleTasks() override + { + DoCastSelf(SPELL_SEAL_OF_BLOOD); + events.ScheduleEvent(EVENT_BLESS, Seconds(20)); + events.ScheduleEvent(EVENT_CONSECRATION, Seconds(10)); + events.ScheduleEvent(EVENT_HAMMER_OF_JUSTICE, Seconds(10)); + events.ScheduleEvent(EVENT_JUDGEMENT, Seconds(15)); + events.ScheduleEvent(EVENT_AURA, Seconds(6)); + } + + void ExecuteEvent(uint32 eventId) override + { + switch (eventId) + { + case EVENT_BLESS: + { + std::list<Unit*> TargetList; + Trinity::AnyFriendlyUnitInObjectRangeCheck checker(me, me, 100.0f); + Trinity::UnitListSearcher<Trinity::AnyFriendlyUnitInObjectRangeCheck> searcher(me, TargetList, checker); + Cell::VisitAllObjects(me, searcher, 100.0f); + + if (!TargetList.empty()) + { + Unit* target = Trinity::Containers::SelectRandomContainerElement(TargetList); + DoCast(target, RAND(SPELL_BLESS_PROTECTION, SPELL_BLESS_SPELL_WARDING)); + } + events.Repeat(Seconds(30), Seconds(45)); + break; + } + case EVENT_AURA: + DoCastSelf(RAND(SPELL_CHROMATIC_AURA, SPELL_DEVOTION_AURA)); + events.Repeat(Seconds(30)); + break; + case EVENT_HAMMER_OF_JUSTICE: + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 1, HammerTargetSelector(me))) + DoCast(target, SPELL_HAMMER_OF_JUSTICE); + events.Repeat(Seconds(20)); + break; + case EVENT_JUDGEMENT: + DoCastVictim(SPELL_JUDGEMENT); + events.Repeat(Seconds(15)); + break; + case EVENT_CONSECRATION: + DoCastSelf(SPELL_CONSECRATION); + events.Repeat(Seconds(30), Seconds(35)); + break; + default: + break; + } + } + }; + + CreatureAI* GetAI(Creature* creature) const override + { + return GetBlackTempleAI<boss_gathios_the_shattererAI>(creature); + } +}; + +class boss_high_nethermancer_zerevor : public CreatureScript +{ +public: + boss_high_nethermancer_zerevor() : CreatureScript("boss_high_nethermancer_zerevor") { } + + struct boss_high_nethermancer_zerevorAI : public IllidariCouncilBossAI + { + boss_high_nethermancer_zerevorAI(Creature* creature) : IllidariCouncilBossAI(creature, DATA_HIGH_NETHERMANCER_ZEREVOR), _canUseArcaneExplosion(true) { } + + void Reset() override + { + IllidariCouncilBossAI::Reset(); + _canUseArcaneExplosion = true; + DoCastSelf(SPELL_DAMPEN_MAGIC); + } + + void ScheduleTasks() override + { + events.ScheduleEvent(EVENT_FLAMESTRIKE, Seconds(8)); + events.ScheduleEvent(EVENT_BLIZZARD, Seconds(25)); + events.ScheduleEvent(EVENT_ARCANE_EXPLOSION, Seconds(5)); + DoCastSelf(SPELL_DAMPEN_MAGIC); + } + + void DoAction(int32 actionId) override + { + if (actionId == ACTION_REFRESH_DAMPEN) + events.ScheduleEvent(EVENT_DAMPEN_MAGIC, Seconds(50)); + } + void ExecuteEvent(uint32 eventId) override + { + switch (eventId) + { + case EVENT_FLAMESTRIKE: + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0)) + DoCast(target, SPELL_FLAMESTRIKE); + Talk(SAY_COUNCIL_SPECIAL); + events.Repeat(Seconds(40)); + break; + case EVENT_BLIZZARD: + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0)) + DoCast(target, SPELL_BLIZZARD); + events.Repeat(Seconds(15), Seconds(40)); + break; + case EVENT_ARCANE_EXPLOSION_CHECK: + _canUseArcaneExplosion = true; + break; + case EVENT_ARCANE_EXPLOSION: + if (_canUseArcaneExplosion && SelectTarget(SELECT_TARGET_RANDOM, 0, 10.0f)) + { + DoCastSelf(SPELL_ARCANE_EXPLOSION); + _canUseArcaneExplosion = false; + events.ScheduleEvent(EVENT_ARCANE_EXPLOSION_CHECK, Seconds(5)); + } + events.Repeat(Seconds(1)); + break; + case EVENT_DAMPEN_MAGIC: + DoCastSelf(SPELL_DAMPEN_MAGIC); + break; + default: + break; + } + } + + void UpdateAI(uint32 diff) override + { + if (!UpdateVictim()) + return; + + events.Update(diff); + + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + + while (uint32 eventId = events.ExecuteEvent()) + { + ExecuteEvent(eventId); + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + } + + DoSpellAttackIfReady(SPELL_ARCANE_BOLT); + } + + private: + bool _canUseArcaneExplosion; + }; + + CreatureAI* GetAI(Creature* creature) const override + { + return GetBlackTempleAI<boss_high_nethermancer_zerevorAI>(creature); + } + +}; + +class boss_lady_malande : public CreatureScript +{ +public: + boss_lady_malande() : CreatureScript("boss_lady_malande") { } + + struct boss_lady_malandeAI : public IllidariCouncilBossAI + { + boss_lady_malandeAI(Creature* creature) : IllidariCouncilBossAI(creature, DATA_LADY_MALANDE) { } + + void ScheduleTasks() override + { + events.ScheduleEvent(EVENT_CIRCLE_OF_HEALING, Seconds(20)); + events.ScheduleEvent(EVENT_REFLECTIVE_SHIELD, Seconds(25)); + events.ScheduleEvent(EVENT_DIVINE_WRATH, Seconds(32)); + } + + void HealReceived(Unit* /*who*/, uint32& addhealth) override + { + // Need be negative to heal trigger + int32 bp = addhealth * (-1); + me->CastCustomSpell(SPELL_SHARED_RULE, SPELLVALUE_BASE_POINT0, bp, (Unit*) nullptr, true); + } + + void ExecuteEvent(uint32 eventId) override + { + switch (eventId) + { + case EVENT_CIRCLE_OF_HEALING: + DoCastSelf(SPELL_CIRCLE_OF_HEALING); + events.Repeat(Seconds(20), Seconds(35)); + break; + case EVENT_REFLECTIVE_SHIELD: + DoCastSelf(SPELL_REFLECTIVE_SHIELD); + Talk(SAY_COUNCIL_SPECIAL); + events.Repeat(Seconds(40)); + break; + case EVENT_DIVINE_WRATH: + DoCastVictim(SPELL_DIVINE_WRATH); + events.Repeat(Seconds(20)); + break; + default: + break; + } + } + + void UpdateAI(uint32 diff) override + { + if (!UpdateVictim()) + return; + + events.Update(diff); + + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + + while (uint32 eventId = events.ExecuteEvent()) + { + ExecuteEvent(eventId); + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + } + + DoSpellAttackIfReady(SPELL_EMPOWERED_SMITE); + } + }; + + CreatureAI* GetAI(Creature* creature) const override + { + return GetBlackTempleAI<boss_lady_malandeAI>(creature); + } + +}; + +class boss_veras_darkshadow : public CreatureScript +{ +public: + boss_veras_darkshadow() : CreatureScript("boss_veras_darkshadow") { } + + struct boss_veras_darkshadowAI : public IllidariCouncilBossAI + { + boss_veras_darkshadowAI(Creature* creature) : IllidariCouncilBossAI(creature, DATA_VERAS_DARKSHADOW) + { + me->SetMaxHealth(1327900); + me->SetFullHealth(); + } + + void ScheduleTasks() override + { + events.ScheduleEvent(EVENT_DEADLY_STRIKE, Seconds(18)); + events.ScheduleEvent(EVENT_VANISH, Seconds(18)); + } + + void ExecuteEvent(uint32 eventId) override + { + switch (eventId) + { + case EVENT_DEADLY_STRIKE: + DoCastSelf(SPELL_DEADLY_STRIKE); + events.Repeat(Seconds(60)); + break; + case EVENT_VANISH: + DoCastSelf(SPELL_VANISH); + Talk(SAY_COUNCIL_SPECIAL); + events.Repeat(Seconds(60)); + break; + default: + break; + } + } + }; + + CreatureAI* GetAI(Creature* creature) const override + { + return GetBlackTempleAI<boss_veras_darkshadowAI>(creature); + } +}; + +class npc_veras_vanish_effect : public CreatureScript +{ +public: + npc_veras_vanish_effect() : CreatureScript("npc_veras_vanish_effect") { } + + struct npc_veras_vanish_effectAI : public PassiveAI + { + npc_veras_vanish_effectAI(Creature* creature) : PassiveAI(creature) { } + + void Reset() override + { + DoCastSelf(SPELL_BIRTH, true); + DoCastSelf(SPELL_ENVENOM_DUMMY, true); + } + }; + + CreatureAI* GetAI(Creature* creature) const override + { + return GetBlackTempleAI<npc_veras_vanish_effectAI>(creature); + } +}; + +// 41499 - Empyreal Balance +class spell_illidari_council_empyreal_balance : public SpellScriptLoader +{ + public: + spell_illidari_council_empyreal_balance() : SpellScriptLoader("spell_illidari_council_empyreal_balance") { } + + class spell_illidari_council_empyreal_balance_SpellScript : public SpellScript + { + PrepareSpellScript(spell_illidari_council_empyreal_balance_SpellScript); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo({ SPELL_BALANCE_OF_POWER }); + } + + void HandleDummy(SpellEffIndex /*effIndex*/) + { + Unit* target = GetHitUnit(); + target->CastSpell(target, SPELL_BALANCE_OF_POWER, true); + } + + void Register() override + { + OnEffectHitTarget += SpellEffectFn(spell_illidari_council_empyreal_balance_SpellScript::HandleDummy, EFFECT_0, SPELL_EFFECT_DUMMY); + } + }; + + SpellScript* GetSpellScript() const override + { + return new spell_illidari_council_empyreal_balance_SpellScript(); + } +}; + +// 41333 - Empyreal Equivalency +class spell_illidari_council_empyreal_equivalency : public SpellScriptLoader +{ + public: + spell_illidari_council_empyreal_equivalency() : SpellScriptLoader("spell_illidari_council_empyreal_equivalency") { } + + class spell_illidari_council_empyreal_equivalency_SpellScript : public SpellScript + { + PrepareSpellScript(spell_illidari_council_empyreal_equivalency_SpellScript); + + void HandleScript(SpellEffIndex /*effIndex*/) + { + Unit* target = GetHitUnit(); + int32 casterHpPct = (int32) GetCaster()->GetHealthPct(); + uint32 newHp = target->CountPctFromMaxHealth(casterHpPct); + if (newHp <= 0) + newHp = target->GetMaxHealth() - 1; + target->SetHealth(newHp); + } + + void Register() override + { + OnEffectHitTarget += SpellEffectFn(spell_illidari_council_empyreal_equivalency_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_DUMMY); + } + }; + + SpellScript* GetSpellScript() const override + { + return new spell_illidari_council_empyreal_equivalency_SpellScript(); + } +}; + +// 41341 - Balance of Power +class spell_illidari_council_balance_of_power : public SpellScriptLoader +{ + public: + spell_illidari_council_balance_of_power() : SpellScriptLoader("spell_illidari_council_balance_of_power") { } + + class spell_illidari_council_balance_of_power_AuraScript : public AuraScript + { + PrepareAuraScript(spell_illidari_council_balance_of_power_AuraScript); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo({ SPELL_SHARED_RULE }); + } + + void Absorb(AuraEffect* aurEff, DamageInfo& dmgInfo, uint32& /*absorbAmount*/) + { + PreventDefaultAction(); + int32 bp = dmgInfo.GetDamage(); + GetTarget()->CastCustomSpell(SPELL_SHARED_RULE, SPELLVALUE_BASE_POINT0, bp, (Unit*) nullptr, true, nullptr, aurEff); + } + + void Register() override + { + OnEffectAbsorb += AuraEffectAbsorbFn(spell_illidari_council_balance_of_power_AuraScript::Absorb, EFFECT_0); + } + }; + + AuraScript* GetAuraScript() const override + { + return new spell_illidari_council_balance_of_power_AuraScript(); + } +}; + +// 41480 - Deadly Strike +class spell_illidari_council_deadly_strike : public SpellScriptLoader +{ + public: + spell_illidari_council_deadly_strike() : SpellScriptLoader("spell_illidari_council_deadly_strike") { } + + class spell_illidari_council_deadly_strike_AuraScript : public AuraScript + { + PrepareAuraScript(spell_illidari_council_deadly_strike_AuraScript); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo({ SPELL_DEADLY_POISON }); + } + + void OnTrigger(AuraEffect const* aurEff) + { + PreventDefaultAction(); + + if (Unit* victim = GetTarget()->GetAI()->SelectTarget(SELECT_TARGET_RANDOM, 0)) + GetTarget()->CastSpell(victim, SPELL_DEADLY_POISON, true, nullptr, aurEff); + } + + void Register() override + { + OnEffectPeriodic += AuraEffectPeriodicFn(spell_illidari_council_deadly_strike_AuraScript::OnTrigger, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL); + } + }; + + AuraScript* GetAuraScript() const override + { + return new spell_illidari_council_deadly_strike_AuraScript(); + } +}; + +// 41485 - Deadly Poison +class spell_illidari_council_deadly_poison : public SpellScriptLoader +{ + public: + spell_illidari_council_deadly_poison() : SpellScriptLoader("spell_illidari_council_deadly_poison") { } + + class spell_illidari_council_deadly_poison_AuraScript : public AuraScript + { + PrepareAuraScript(spell_illidari_council_deadly_poison_AuraScript); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo({ SPELL_ENVENOM }); + } + + void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) + { + if (Unit* caster = GetCaster()) + caster->CastSpell(GetTarget(), SPELL_ENVENOM, true); + } + + void Register() override + { + OnEffectRemove += AuraEffectRemoveFn(spell_illidari_council_deadly_poison_AuraScript::OnRemove, EFFECT_0, SPELL_AURA_PERIODIC_DAMAGE, AURA_EFFECT_HANDLE_REAL); + } + }; + + AuraScript* GetAuraScript() const override + { + return new spell_illidari_council_deadly_poison_AuraScript(); + } +}; + +// 41475 - Reflective Shield +class spell_illidari_council_reflective_shield : public SpellScriptLoader +{ + public: + spell_illidari_council_reflective_shield() : SpellScriptLoader("spell_illidari_council_reflective_shield") { } + + class spell_illidari_council_reflective_shield_AuraScript : public AuraScript + { + PrepareAuraScript(spell_illidari_council_reflective_shield_AuraScript); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo({ SPELL_REFLECTIVE_SHIELD_DAMAGE }); + } + + void OnAbsorb(AuraEffect* aurEff, DamageInfo & dmgInfo, uint32 & absorbAmount) + { + Unit* target = GetTarget(); + if (dmgInfo.GetAttacker() == target) + return; + + int32 bp = absorbAmount / 2; + target->CastCustomSpell(dmgInfo.GetAttacker(), SPELL_REFLECTIVE_SHIELD_DAMAGE, &bp, nullptr, nullptr, true, nullptr, aurEff); + } + + void Register() override + { + AfterEffectAbsorb += AuraEffectAbsorbFn(spell_illidari_council_reflective_shield_AuraScript::OnAbsorb, EFFECT_0); + } + }; + + AuraScript* GetAuraScript() const override + { + return new spell_illidari_council_reflective_shield_AuraScript(); + } +}; + +// 41467 - Judgement +class spell_illidari_council_judgement : public SpellScriptLoader +{ + public: + spell_illidari_council_judgement() : SpellScriptLoader("spell_illidari_council_judgement") { } + + class spell_illidari_council_judgement_SpellScript : public SpellScript + { + PrepareSpellScript(spell_illidari_council_judgement_SpellScript); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo( + { + SPELL_JUDGEMENT_OF_BLOOD, + SPELL_JUDGEMENT_OF_COMMAND, + SPELL_JUDGEMENT_PRIMER + }); + } + + void HandleScript(SpellEffIndex /*effIndex*/) + { + Unit* caster = GetCaster(); + Unit* target = GetHitUnit(); + uint32 judgementId = caster->HasAura(SPELL_SEAL_OF_BLOOD) ? SPELL_JUDGEMENT_OF_BLOOD : SPELL_JUDGEMENT_OF_COMMAND; + caster->CastSpell(target, SPELL_JUDGEMENT_PRIMER, true); + caster->CastSpell(target, judgementId, true); + } + + void OnFinishCast() + { + if (Creature* caster = GetCaster()->ToCreature()) + caster->AI()->Talk(SAY_COUNCIL_SPECIAL); + } + + void Register() override + { + OnEffectHitTarget += SpellEffectFn(spell_illidari_council_judgement_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT); + AfterCast += SpellCastFn(spell_illidari_council_judgement_SpellScript::OnFinishCast); + } + }; + + SpellScript* GetSpellScript() const override + { + return new spell_illidari_council_judgement_SpellScript(); + } +}; + +/* 41469 - Seal of Command + 41459 - Seal of Blood */ +class spell_illidari_council_seal : public SpellScriptLoader +{ + public: + spell_illidari_council_seal() : SpellScriptLoader("spell_illidari_council_seal") { } + + class spell_illidari_council_seal_AuraScript : public AuraScript + { + PrepareAuraScript(spell_illidari_council_seal_AuraScript); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo({ SPELL_SEAL_OF_COMMAND, SPELL_SEAL_OF_BLOOD }); + } + + void OnRemove(AuraEffect const* aurEff, AuraEffectHandleModes /*mode*/) + { + Unit* target = GetTarget(); + if (target->IsInWorld() && target->IsAlive()) + { + uint32 spellId = aurEff->GetId() == SPELL_SEAL_OF_COMMAND ? SPELL_SEAL_OF_BLOOD : SPELL_SEAL_OF_COMMAND; + target->CastSpell(target, spellId, true); + } + } + + void Register() override + { + OnEffectRemove += AuraEffectRemoveFn(spell_illidari_council_seal_AuraScript::OnRemove, EFFECT_2, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL); + } + }; + + AuraScript* GetAuraScript() const override + { + return new spell_illidari_council_seal_AuraScript(); + } +}; + +// 41478 - Dampen Magic +class spell_illidari_dampen_magic : public SpellScriptLoader +{ + public: + spell_illidari_dampen_magic() : SpellScriptLoader("spell_illidari_dampen_magic") { } + + class spell_illidari_dampen_magic_AuraScript : public AuraScript + { + PrepareAuraScript(spell_illidari_dampen_magic_AuraScript); + + void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) + { + if (Creature* target = GetTarget()->ToCreature()) + { + AuraRemoveMode mode = GetTargetApplication()->GetRemoveMode(); + if (mode == AURA_REMOVE_BY_ENEMY_SPELL || mode == AURA_REMOVE_BY_EXPIRE) + target->AI()->DoAction(ACTION_REFRESH_DAMPEN); + } + } + + void Register() override + { + OnEffectRemove += AuraEffectRemoveFn(spell_illidari_dampen_magic_AuraScript::OnRemove, EFFECT_0, SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN, AURA_EFFECT_HANDLE_REAL); + } + }; + + AuraScript* GetAuraScript() const override + { + return new spell_illidari_dampen_magic_AuraScript(); + } +}; + +void AddSC_boss_illidari_council() +{ + new boss_illidari_council(); + new boss_gathios_the_shatterer(); + new boss_lady_malande(); + new boss_veras_darkshadow(); + new boss_high_nethermancer_zerevor(); + new npc_veras_vanish_effect(); + new spell_illidari_council_empyreal_balance(); + new spell_illidari_council_empyreal_equivalency(); + new spell_illidari_council_balance_of_power(); + new spell_illidari_council_deadly_strike(); + new spell_illidari_council_deadly_poison(); + new spell_illidari_council_reflective_shield(); + new spell_illidari_council_judgement(); + new spell_illidari_council_seal(); + new spell_illidari_dampen_magic(); +} diff --git a/src/server/scripts/Outland/BlackTemple/illidari_council.cpp b/src/server/scripts/Outland/BlackTemple/illidari_council.cpp deleted file mode 100644 index e0a332f867d..00000000000 --- a/src/server/scripts/Outland/BlackTemple/illidari_council.cpp +++ /dev/null @@ -1,950 +0,0 @@ -/* - * Copyright (C) 2008-2018 TrinityCore <https://www.trinitycore.org/> - * Copyright (C) 2006-2009 ScriptDev2 <https://scriptdev2.svn.sourceforge.net/> - * - * 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 <http://www.gnu.org/licenses/>. - */ - -/* ScriptData -SDName: Illidari_Council -SD%Complete: 95 -SDComment: Circle of Healing not working properly. -SDCategory: Black Temple -EndScriptData */ - -#include "ScriptMgr.h" -#include "black_temple.h" -#include "InstanceScript.h" -#include "MotionMaster.h" -#include "ObjectAccessor.h" -#include "ScriptedCreature.h" -#include "SpellScript.h" - -enum IllidariCouncil -{ - //Speech'n'Sounds - SAY_GATH_SPECIAL1 = 2, - SAY_GATH_SPECIAL2 = 3, - SAY_GATH_SLAY = 4, - SAY_GATH_COMNT = 5, - SAY_GATH_DEATH = 6, - - SAY_MALA_SPECIAL1 = 2, - SAY_MALA_SPECIAL2 = 3, - SAY_MALA_SLAY = 4, - SAY_MALA_COMNT = 5, - SAY_MALA_DEATH = 6, - - SAY_ZERE_SPECIAL1 = 2, - SAY_ZERE_SPECIAL2 = 3, - SAY_ZERE_SLAY = 4, - SAY_ZERE_COMNT = 5, - SAY_ZERE_DEATH = 6, - - SAY_VERA_SPECIAL1 = 2, - SAY_VERA_SPECIAL2 = 3, - SAY_VERA_SLAY = 4, - SAY_VERA_COMNT = 5, - SAY_VERA_DEATH = 6, - - AKAMAID = 23089, - - // High Nethermancer Zerevor's spells - SPELL_FLAMESTRIKE = 41481, - SPELL_BLIZZARD = 41482, - SPELL_ARCANE_BOLT = 41483, - SPELL_ARCANE_EXPLOSION = 41524, - SPELL_DAMPEN_MAGIC = 41478, - - // Lady Malande's spells - SPELL_EMPOWERED_SMITE = 41471, - SPELL_CIRCLE_OF_HEALING = 41455, - SPELL_REFLECTIVE_SHIELD = 41475, - SPELL_REFLECTIVE_SHIELD_T = 33619, - SPELL_DIVINE_WRATH = 41472, - SPELL_HEAL_VISUAL = 24171, - - // Gathios the Shatterer's spells - SPELL_BLESS_PROTECTION = 41450, - SPELL_BLESS_SPELLWARD = 41451, - SPELL_CONSECRATION = 41541, - SPELL_HAMMER_OF_JUSTICE = 41468, - SPELL_SEAL_OF_COMMAND = 41469, - SPELL_SEAL_OF_BLOOD = 41459, - SPELL_CHROMATIC_AURA = 41453, - SPELL_DEVOTION_AURA = 41452, - - // Veras Darkshadow's spells - SPELL_DEADLY_POISON = 41485, - SPELL_ENVENOM = 41487, - SPELL_VANISH = 41479, - SPELL_BERSERK = 45078 -}; - -struct CouncilYells -{ - int32 entry; - uint32 timer; -}; - -static CouncilYells CouncilAggro[]= -{ - {0, 5000}, // Gathios - {0, 5500}, // Veras - {0, 5000}, // Malande - {0, 0}, // Zerevor -}; - -// Need to get proper timers for this later -static CouncilYells CouncilEnrage[]= -{ - {1, 2000}, // Gathios - {1, 6000}, // Veras - {1, 5000}, // Malande - {1, 0}, // Zerevor -}; - -class npc_blood_elf_council_voice_trigger : public CreatureScript -{ -public: - npc_blood_elf_council_voice_trigger() : CreatureScript("npc_blood_elf_council_voice_trigger") { } - - CreatureAI* GetAI(Creature* c) const override - { - return GetBlackTempleAI<npc_blood_elf_council_voice_triggerAI>(c); - } - - struct npc_blood_elf_council_voice_triggerAI : public ScriptedAI - { - npc_blood_elf_council_voice_triggerAI(Creature* creature) : ScriptedAI(creature) - { - Initialize(); - } - - void Initialize() - { - EnrageTimer = 900000; // 15 minutes - AggroYellTimer = 500; - - YellCounter = 0; - - EventStarted = false; - } - - ObjectGuid Council[4]; - - uint32 EnrageTimer; - uint32 AggroYellTimer; - - uint8 YellCounter; // Serves as the counter for both the aggro and enrage yells - - bool EventStarted; - - void Reset() override - { - Initialize(); - } - - // finds and stores the GUIDs for each Council member using instance data system. - void LoadCouncilGUIDs() - { - if (InstanceScript* instance = me->GetInstanceScript()) - { - Council[0] = instance->GetGuidData(DATA_GATHIOS_THE_SHATTERER); - Council[1] = instance->GetGuidData(DATA_VERAS_DARKSHADOW); - Council[2] = instance->GetGuidData(DATA_LADY_MALANDE); - Council[3] = instance->GetGuidData(DATA_HIGH_NETHERMANCER_ZEREVOR); - } - } - - void EnterCombat(Unit* /*who*/) override { } - - void AttackStart(Unit* /*who*/) override { } - void MoveInLineOfSight(Unit* /*who*/) override { } - - - void UpdateAI(uint32 diff) override - { - if (!EventStarted) - return; - - if (YellCounter > 3) - return; - - if (AggroYellTimer) - { - if (AggroYellTimer <= diff) - { - if (Creature* pMember = ObjectAccessor::GetCreature(*me, Council[YellCounter])) - { - pMember->AI()->Talk(CouncilAggro[YellCounter].entry); - AggroYellTimer = CouncilAggro[YellCounter].timer; - } - ++YellCounter; - if (YellCounter > 3) - YellCounter = 0; // Reuse for Enrage Yells - } else AggroYellTimer -= diff; - } - - if (EnrageTimer) - { - if (EnrageTimer <= diff) - { - if (Creature* pMember = ObjectAccessor::GetCreature(*me, Council[YellCounter])) - { - pMember->CastSpell(pMember, SPELL_BERSERK, true); - pMember->AI()->Talk(CouncilEnrage[YellCounter].entry); - EnrageTimer = CouncilEnrage[YellCounter].timer; - } - ++YellCounter; - } else EnrageTimer -= diff; - } - } - }; - -}; - -class npc_illidari_council : public CreatureScript -{ -public: - npc_illidari_council() : CreatureScript("npc_illidari_council") { } - - CreatureAI* GetAI(Creature* creature) const override - { - return GetBlackTempleAI<npc_illidari_councilAI>(creature); - } - - struct npc_illidari_councilAI : public ScriptedAI - { - npc_illidari_councilAI(Creature* creature) : ScriptedAI(creature) - { - Initialize(); - instance = creature->GetInstanceScript(); - SetBoundary(instance->GetBossBoundary(DATA_ILLIDARI_COUNCIL)); - } - - void Initialize() - { - CheckTimer = 2000; - EndEventTimer = 0; - - DeathCount = 0; - EventBegun = false; - } - - InstanceScript* instance; - - ObjectGuid Council[4]; - - uint32 CheckTimer; - uint32 EndEventTimer; - - uint8 DeathCount; - - bool EventBegun; - - void Reset() override - { - Initialize(); - - Creature* pMember = nullptr; - for (uint8 i = 0; i < 4; ++i) - { - pMember = ObjectAccessor::GetCreature((*me), Council[i]); - if (!pMember) - continue; - - if (!pMember->IsAlive()) - { - pMember->RemoveCorpse(); - pMember->Respawn(); - } - pMember->AI()->EnterEvadeMode(); - } - - instance->SetBossState(DATA_ILLIDARI_COUNCIL, NOT_STARTED); - if (Creature* VoiceTrigger = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_BLOOD_ELF_COUNCIL_VOICE))) - VoiceTrigger->AI()->EnterEvadeMode(); - - me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - me->SetDisplayId(11686); - } - - void EnterCombat(Unit* /*who*/) override { } - void AttackStart(Unit* /*who*/) override { } - void MoveInLineOfSight(Unit* /*who*/) override { } - - - void StartEvent(Unit* target) - { - if (target && target->IsAlive()) - { - Council[0] = instance->GetGuidData(DATA_GATHIOS_THE_SHATTERER); - Council[1] = instance->GetGuidData(DATA_HIGH_NETHERMANCER_ZEREVOR); - Council[2] = instance->GetGuidData(DATA_LADY_MALANDE); - Council[3] = instance->GetGuidData(DATA_VERAS_DARKSHADOW); - - // Start the event for the Voice Trigger - if (Creature* VoiceTrigger = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_BLOOD_ELF_COUNCIL_VOICE))) - { - ENSURE_AI(npc_blood_elf_council_voice_trigger::npc_blood_elf_council_voice_triggerAI, VoiceTrigger->AI())->LoadCouncilGUIDs(); - ENSURE_AI(npc_blood_elf_council_voice_trigger::npc_blood_elf_council_voice_triggerAI, VoiceTrigger->AI())->EventStarted = true; - } - - for (uint8 i = 0; i < 4; ++i) - { - if (!Council[i].IsEmpty()) - { - if (Creature* member = ObjectAccessor::GetCreature(*me, Council[i])) - if (member->IsAlive()) - member->AI()->AttackStart(target); - } - } - - instance->SetBossState(DATA_ILLIDARI_COUNCIL, IN_PROGRESS); - - EventBegun = true; - } - } - - void UpdateAI(uint32 diff) override - { - if (!EventBegun) - return; - - if (EndEventTimer) - { - if (EndEventTimer <= diff) - { - if (DeathCount > 3) - { - if (Creature* VoiceTrigger = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_BLOOD_ELF_COUNCIL_VOICE))) - VoiceTrigger->DealDamage(VoiceTrigger, VoiceTrigger->GetHealth(), nullptr, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, nullptr, false); - instance->SetBossState(DATA_ILLIDARI_COUNCIL, DONE); - //me->SummonCreature(AKAMAID, 746.466980f, 304.394989f, 311.90208f, 6.272870f, TEMPSUMMON_DEAD_DESPAWN, 0); - me->DealDamage(me, me->GetHealth(), nullptr, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, nullptr, false); - return; - } - - Creature* pMember = (ObjectAccessor::GetCreature(*me, Council[DeathCount])); - if (pMember && pMember->IsAlive()) - pMember->DealDamage(pMember, pMember->GetHealth(), nullptr, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, nullptr, false); - ++DeathCount; - EndEventTimer = 1500; - } else EndEventTimer -= diff; - } - - if (CheckTimer) - { - if (CheckTimer <= diff) - { - uint8 EvadeCheck = 0; - for (uint8 i = 0; i < 4; ++i) - { - if (!Council[i].IsEmpty()) - { - if (Creature* Member = (ObjectAccessor::GetCreature((*me), Council[i]))) - { - // This is the evade/death check. - if (Member->IsAlive() && !Member->GetVictim()) - ++EvadeCheck; //If all members evade, we reset so that players can properly reset the event - else if (!Member->IsAlive()) // If even one member dies, kill the rest, set instance data, and kill self. - { - EndEventTimer = 1000; - CheckTimer = 0; - return; - } - } - } - } - - if (EvadeCheck > 3) - Reset(); - - CheckTimer = 2000; - } else CheckTimer -= diff; - } - - } - }; - -}; - -struct boss_illidari_councilAI : public ScriptedAI -{ - boss_illidari_councilAI(Creature* creature) : ScriptedAI(creature) - { - instance = creature->GetInstanceScript(); - LoadedGUIDs = false; - } - - ObjectGuid Council[4]; - - InstanceScript* instance; - - bool LoadedGUIDs; - - void EnterCombat(Unit* who) override - { - if (Creature* controller = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_ILLIDARI_COUNCIL))) - ENSURE_AI(npc_illidari_council::npc_illidari_councilAI, controller->AI())->StartEvent(who); - DoZoneInCombat(); - // Load GUIDs on first aggro because the Creature guids are only set as the creatures are created in world- - // this means that for each creature, it will attempt to LoadGUIDs even though some of the other creatures are - // not in world, and thus have no GUID set in the instance data system. Putting it in aggro ensures that all the creatures - // have been loaded and have their GUIDs set in the instance data system. - if (!LoadedGUIDs) - LoadGUIDs(); - } - - void EnterEvadeMode(EvadeReason why) override - { - for (uint8 i = 0; i < 4; ++i) - { - if (Unit* unit = ObjectAccessor::GetUnit(*me, Council[i])) - if (unit != me && unit->GetVictim()) - { - AttackStart(unit->GetVictim()); - return; - } - } - ScriptedAI::EnterEvadeMode(why); - } - - void DamageTaken(Unit* done_by, uint32 &damage) override - { - if (done_by == me) - return; - - damage /= 4; - for (uint8 i = 0; i < 4; ++i) - { - if (Creature* unit = ObjectAccessor::GetCreature(*me, Council[i])) - if (unit != me && damage < unit->GetHealth()) - { - unit->ModifyHealth(-int32(damage)); - unit->LowerPlayerDamageReq(damage); - } - } - } - - void LoadGUIDs() - { - Council[0] = instance->GetGuidData(DATA_LADY_MALANDE); - Council[1] = instance->GetGuidData(DATA_HIGH_NETHERMANCER_ZEREVOR); - Council[2] = instance->GetGuidData(DATA_GATHIOS_THE_SHATTERER); - Council[3] = instance->GetGuidData(DATA_VERAS_DARKSHADOW); - - LoadedGUIDs = true; - } -}; - -class boss_gathios_the_shatterer : public CreatureScript -{ -public: - boss_gathios_the_shatterer() : CreatureScript("boss_gathios_the_shatterer") { } - - CreatureAI* GetAI(Creature* creature) const override - { - return GetBlackTempleAI<boss_gathios_the_shattererAI>(creature); - } - - struct boss_gathios_the_shattererAI : public boss_illidari_councilAI - { - boss_gathios_the_shattererAI(Creature* creature) : boss_illidari_councilAI(creature) - { - Initialize(); - } - - void Initialize() - { - ConsecrationTimer = 40000; - HammerOfJusticeTimer = 10000; - SealTimer = 40000; - AuraTimer = 90000; - BlessingTimer = 60000; - } - - uint32 ConsecrationTimer; - uint32 HammerOfJusticeTimer; - uint32 SealTimer; - uint32 AuraTimer; - uint32 BlessingTimer; - - void Reset() override - { - Initialize(); - } - - void KilledUnit(Unit* /*victim*/) override - { - Talk(SAY_GATH_SLAY); - } - - void JustDied(Unit* /*killer*/) override - { - Talk(SAY_GATH_DEATH); - } - - Unit* SelectCouncilMember() - { - Unit* unit = me; - uint32 member = 0; // He chooses Lady Malande most often - - if (rand32() % 10 == 0) // But there is a chance he picks someone else. - member = urand(1, 3); - - if (member != 2) // No need to create another pointer to us using Unit::GetUnit - unit = ObjectAccessor::GetUnit(*me, Council[member]); - return unit; - } - - void CastAuraOnCouncil() - { - uint32 spellid = 0; - switch (urand(0, 1)) - { - case 0: spellid = SPELL_DEVOTION_AURA; break; - case 1: spellid = SPELL_CHROMATIC_AURA; break; - } - for (uint8 i = 0; i < 4; ++i) - { - Unit* unit = ObjectAccessor::GetUnit(*me, Council[i]); - if (unit) - unit->CastSpell(unit, spellid, true, 0, 0, me->GetGUID()); - } - } - - void UpdateAI(uint32 diff) override - { - if (!UpdateVictim()) - return; - - if (BlessingTimer <= diff) - { - if (Unit* unit = SelectCouncilMember()) - { - switch (urand(0, 1)) - { - case 0: - DoCast(unit, SPELL_BLESS_SPELLWARD); - break; - - case 1: - DoCast(unit, SPELL_BLESS_PROTECTION); - break; - } - } - BlessingTimer = 60000; - } else BlessingTimer -= diff; - - if (ConsecrationTimer <= diff) - { - DoCast(me, SPELL_CONSECRATION); - ConsecrationTimer = 40000; - } else ConsecrationTimer -= diff; - - if (HammerOfJusticeTimer <= diff) - { - if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0)) - { - // is in ~10-40 yd range - if (me->IsInRange(target, 10.0f, 40.0f, false)) - { - DoCast(target, SPELL_HAMMER_OF_JUSTICE); - HammerOfJusticeTimer = 20000; - } - } - } else HammerOfJusticeTimer -= diff; - - if (SealTimer <= diff) - { - switch (urand(0, 1)) - { - case 0: DoCast(me, SPELL_SEAL_OF_COMMAND); break; - case 1: DoCast(me, SPELL_SEAL_OF_BLOOD); break; - } - SealTimer = 40000; - } else SealTimer -= diff; - - if (AuraTimer <= diff) - { - CastAuraOnCouncil(); - AuraTimer = 90000; - } else AuraTimer -= diff; - - DoMeleeAttackIfReady(); - } - }; - -}; - -class boss_high_nethermancer_zerevor : public CreatureScript -{ -public: - boss_high_nethermancer_zerevor() : CreatureScript("boss_high_nethermancer_zerevor") { } - - CreatureAI* GetAI(Creature* creature) const override - { - return GetBlackTempleAI<boss_high_nethermancer_zerevorAI>(creature); - } - - struct boss_high_nethermancer_zerevorAI : public boss_illidari_councilAI - { - boss_high_nethermancer_zerevorAI(Creature* creature) : boss_illidari_councilAI(creature) - { - Initialize(); - } - - void Initialize() - { - BlizzardTimer = urand(30, 91) * 1000; - FlamestrikeTimer = urand(30, 91) * 1000; - ArcaneBoltTimer = 10000; - DampenMagicTimer = 2000; - ArcaneExplosionTimer = 14000; - Cooldown = 0; - } - - uint32 BlizzardTimer; - uint32 FlamestrikeTimer; - uint32 ArcaneBoltTimer; - uint32 DampenMagicTimer; - uint32 Cooldown; - uint32 ArcaneExplosionTimer; - - void Reset() override - { - Initialize(); - } - - void KilledUnit(Unit* /*victim*/) override - { - Talk(SAY_ZERE_SLAY); - } - - void JustDied(Unit* /*killer*/) override - { - Talk(SAY_ZERE_DEATH); - } - - void UpdateAI(uint32 diff) override - { - if (!UpdateVictim()) - return; - - if (Cooldown) - { - if (Cooldown <= diff) Cooldown = 0; - else - { - Cooldown -= diff; - return; // Don't cast any other spells if global cooldown is still ticking - } - } - - if (DampenMagicTimer <= diff) - { - DoCast(me, SPELL_DAMPEN_MAGIC); - Cooldown = 1000; - DampenMagicTimer = 67200; // almost 1, 12 minutes - ArcaneBoltTimer += 1000; // Give the Mage some time to spellsteal Dampen. - } else DampenMagicTimer -= diff; - - if (ArcaneExplosionTimer <= diff) - { - DoCastVictim(SPELL_ARCANE_EXPLOSION); - Cooldown = 1000; - ArcaneExplosionTimer = 14000; - } else ArcaneExplosionTimer -= diff; - - if (ArcaneBoltTimer <= diff) - { - DoCastVictim(SPELL_ARCANE_BOLT); - ArcaneBoltTimer = 3000; - Cooldown = 2000; - } else ArcaneBoltTimer -= diff; - - if (BlizzardTimer <= diff) - { - if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0)) - { - DoCast(target, SPELL_BLIZZARD); - BlizzardTimer = urand(45, 91) * 1000; - FlamestrikeTimer += 10000; - Cooldown = 1000; - } - } else BlizzardTimer -= diff; - - if (FlamestrikeTimer <= diff) - { - if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0)) - { - DoCast(target, SPELL_FLAMESTRIKE); - FlamestrikeTimer = urand(55, 101) * 1000; - BlizzardTimer += 10000; - Cooldown = 2000; - } - } else FlamestrikeTimer -= diff; - } - }; - -}; - -class boss_lady_malande : public CreatureScript -{ -public: - boss_lady_malande() : CreatureScript("boss_lady_malande") { } - - CreatureAI* GetAI(Creature* creature) const override - { - return GetBlackTempleAI<boss_lady_malandeAI>(creature); - } - - struct boss_lady_malandeAI : public boss_illidari_councilAI - { - boss_lady_malandeAI(Creature* creature) : boss_illidari_councilAI(creature) - { - Initialize(); - } - - void Initialize() - { - EmpoweredSmiteTimer = 38000; - CircleOfHealingTimer = 20000; - DivineWrathTimer = 40000; - ReflectiveShieldTimer = 0; - } - - uint32 EmpoweredSmiteTimer; - uint32 CircleOfHealingTimer; - uint32 DivineWrathTimer; - uint32 ReflectiveShieldTimer; - - void Reset() override - { - Initialize(); - } - - void KilledUnit(Unit* /*victim*/) override - { - Talk(SAY_MALA_SLAY); - } - - void JustDied(Unit* /*killer*/) override - { - Talk(SAY_MALA_DEATH); - } - - void UpdateAI(uint32 diff) override - { - if (!UpdateVictim()) - return; - - if (EmpoweredSmiteTimer <= diff) - { - if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0)) - { - DoCast(target, SPELL_EMPOWERED_SMITE); - EmpoweredSmiteTimer = 38000; - } - } else EmpoweredSmiteTimer -= diff; - - if (CircleOfHealingTimer <= diff) - { - DoCast(me, SPELL_CIRCLE_OF_HEALING); - CircleOfHealingTimer = 60000; - } else CircleOfHealingTimer -= diff; - - if (DivineWrathTimer <= diff) - { - if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0)) - { - DoCast(target, SPELL_DIVINE_WRATH); - DivineWrathTimer = urand(40, 81) * 1000; - } - } else DivineWrathTimer -= diff; - - if (ReflectiveShieldTimer <= diff) - { - DoCast(me, SPELL_REFLECTIVE_SHIELD); - ReflectiveShieldTimer = 65000; - } else ReflectiveShieldTimer -= diff; - - DoMeleeAttackIfReady(); - } - }; - -}; - -class boss_veras_darkshadow : public CreatureScript -{ -public: - boss_veras_darkshadow() : CreatureScript("boss_veras_darkshadow") { } - - CreatureAI* GetAI(Creature* creature) const override - { - return GetBlackTempleAI<boss_veras_darkshadowAI>(creature); - } - - struct boss_veras_darkshadowAI : public boss_illidari_councilAI - { - boss_veras_darkshadowAI(Creature* creature) : boss_illidari_councilAI(creature) - { - Initialize(); - } - - void Initialize() - { - DeadlyPoisonTimer = 20000; - VanishTimer = urand(60, 121) * 1000; - AppearEnvenomTimer = 150000; - - HasVanished = false; - } - - uint32 DeadlyPoisonTimer; - uint32 VanishTimer; - uint32 AppearEnvenomTimer; - - bool HasVanished; - - void Reset() override - { - Initialize(); - me->SetVisible(true); - me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - } - - void KilledUnit(Unit* /*victim*/) override - { - Talk(SAY_VERA_SLAY); - } - - void JustDied(Unit* /*killer*/) override - { - Talk(SAY_VERA_DEATH); - } - - void UpdateAI(uint32 diff) override - { - if (!UpdateVictim()) - return; - - if (!HasVanished) - { - if (DeadlyPoisonTimer <= diff) - { - DoCastVictim(SPELL_DEADLY_POISON); - DeadlyPoisonTimer = urand(15, 46) * 1000; - } else DeadlyPoisonTimer -= diff; - - if (AppearEnvenomTimer <= diff) // Cast Envenom. This is cast 4 seconds after Vanish is over - { - DoCastVictim(SPELL_ENVENOM); - AppearEnvenomTimer = 90000; - } else AppearEnvenomTimer -= diff; - - if (VanishTimer <= diff) // Disappear and stop attacking, but follow a random unit - { - if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0)) - { - VanishTimer = 30000; - AppearEnvenomTimer= 28000; - HasVanished = true; - me->SetVisible(false); - me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - DoResetThreat(); - // Chase a unit. Check before DoMeleeAttackIfReady prevents from attacking - me->AddThreat(target, 500000.0f); - me->GetMotionMaster()->MoveChase(target); - } - } else VanishTimer -= diff; - - DoMeleeAttackIfReady(); - } - else - { - if (VanishTimer <= diff) // Become attackable and poison current target - { - Unit* target = me->GetVictim(); - DoCast(target, SPELL_DEADLY_POISON); - me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - DoResetThreat(); - me->AddThreat(target, 3000.0f); // Make Veras attack his target for a while, he will cast Envenom 4 seconds after. - DeadlyPoisonTimer += 6000; - VanishTimer = 90000; - AppearEnvenomTimer = 4000; - HasVanished = false; - } else VanishTimer -= diff; - - if (AppearEnvenomTimer <= diff) // Appear 2 seconds before becoming attackable (Shifting out of vanish) - { - me->GetMotionMaster()->Clear(); - me->GetMotionMaster()->MoveChase(me->GetVictim()); - me->SetVisible(true); - AppearEnvenomTimer = 6000; - } else AppearEnvenomTimer -= diff; - } - } - }; -}; - -// SPELL_REFLECTIVE_SHIELD -class spell_boss_lady_malande_shield : public SpellScriptLoader -{ -public: - spell_boss_lady_malande_shield() : SpellScriptLoader("spell_boss_lady_malande_shield") { } - - class spell_boss_lady_malande_shield_AuraScript : public AuraScript - { - PrepareAuraScript(spell_boss_lady_malande_shield_AuraScript); - - bool Validate(SpellInfo const* /*spellInfo*/) override - { - return ValidateSpellInfo({ SPELL_REFLECTIVE_SHIELD_T }); - } - - void Trigger(AuraEffect* aurEff, DamageInfo & dmgInfo, uint32 & absorbAmount) - { - Unit* target = GetTarget(); - if (dmgInfo.GetAttacker() == target) - return; - int32 bp = absorbAmount / 2; - target->CastCustomSpell(dmgInfo.GetAttacker(), SPELL_REFLECTIVE_SHIELD_T, &bp, nullptr, nullptr, true, nullptr, aurEff); - } - - void Register() override - { - AfterEffectAbsorb += AuraEffectAbsorbFn(spell_boss_lady_malande_shield_AuraScript::Trigger, EFFECT_0); - } - }; - - AuraScript* GetAuraScript() const override - { - return new spell_boss_lady_malande_shield_AuraScript(); - } -}; - -void AddSC_boss_illidari_council() -{ - new npc_illidari_council(); - new npc_blood_elf_council_voice_trigger(); - new boss_gathios_the_shatterer(); - new boss_lady_malande(); - new boss_veras_darkshadow(); - new boss_high_nethermancer_zerevor(); - new spell_boss_lady_malande_shield(); -} diff --git a/src/server/scripts/Outland/BlackTemple/instance_black_temple.cpp b/src/server/scripts/Outland/BlackTemple/instance_black_temple.cpp index 64e294533e3..01f18df6b9f 100644 --- a/src/server/scripts/Outland/BlackTemple/instance_black_temple.cpp +++ b/src/server/scripts/Outland/BlackTemple/instance_black_temple.cpp @@ -75,7 +75,7 @@ ObjectData const creatureData[] = { NPC_VERAS_DARKSHADOW, DATA_VERAS_DARKSHADOW }, { NPC_BLOOD_ELF_COUNCIL_VOICE, DATA_BLOOD_ELF_COUNCIL_VOICE }, { NPC_BLACK_TEMPLE_TRIGGER, DATA_BLACK_TEMPLE_TRIGGER }, - { 0, 0 } // end + { 0, 0 } // END }; ObjectData const gameObjectData[] = |