diff options
author | ccrs <ccrs@users.noreply.github.com> | 2021-08-19 03:16:46 +0200 |
---|---|---|
committer | ccrs <ccrs@users.noreply.github.com> | 2021-08-19 03:16:46 +0200 |
commit | 7360c2d1567be05f81bdb51d0b74f5fd4e263d6a (patch) | |
tree | 84bd4be80283810153fd6a5b1992d41442988133 | |
parent | 32282b7326840da0adcd08044a8086568439d794 (diff) |
Scripts/Ahnkahet: implement Herald Volazj's Twisted Visage AI + small corrections to Herald's own AI
sorry about indentation
timers are guessed
summoning logic unchanged, remains not blizzlike
visage's spells missing spelldifficulty_dbc entries
-rw-r--r-- | sql/updates/world/3.3.5/2021_08_19_00_world.sql | 1 | ||||
-rw-r--r-- | src/server/scripts/Northrend/AzjolNerub/Ahnkahet/boss_herald_volazj.cpp | 586 |
2 files changed, 508 insertions, 79 deletions
diff --git a/sql/updates/world/3.3.5/2021_08_19_00_world.sql b/sql/updates/world/3.3.5/2021_08_19_00_world.sql new file mode 100644 index 00000000000..84824157da5 --- /dev/null +++ b/sql/updates/world/3.3.5/2021_08_19_00_world.sql @@ -0,0 +1 @@ +UPDATE `creature_template` SET `ScriptName`='npc_twisted_visage' WHERE `entry`=30625;
\ No newline at end of file diff --git a/src/server/scripts/Northrend/AzjolNerub/Ahnkahet/boss_herald_volazj.cpp b/src/server/scripts/Northrend/AzjolNerub/Ahnkahet/boss_herald_volazj.cpp index c0ab502f453..055884e14d9 100644 --- a/src/server/scripts/Northrend/AzjolNerub/Ahnkahet/boss_herald_volazj.cpp +++ b/src/server/scripts/Northrend/AzjolNerub/Ahnkahet/boss_herald_volazj.cpp @@ -15,75 +15,127 @@ * with this program. If not, see <http://www.gnu.org/licenses/>. */ -/* - * Comment: Missing AI for Twisted Visages - */ - -#include "ScriptMgr.h" #include "ahnkahet.h" +#include "CommonHelpers.h" #include "InstanceScript.h" #include "Map.h" #include "ObjectAccessor.h" #include "Player.h" #include "ScriptedCreature.h" +#include "ScriptMgr.h" #include "SpellScript.h" #include "SpellInfo.h" #include "TemporarySummon.h" enum VolazjTexts { - SAY_AGGRO = 0, - SAY_INSANITY = 1, - SAY_SLAY_1 = 2, - SAY_SLAY_2 = 3, - SAY_SLAY_3 = 4, - SAY_DEATH_1 = 5, - SAY_DEATH_2 = 6, - - WHISPER_AGGRO = 7, - WHISPER_INSANITY = 8, - WHISPER_SLAY_1 = 9, - WHISPER_SLAY_2 = 10, - WHISPER_SLAY_3 = 11, - WHISPER_DEATH_1 = 12, - WHISPER_DEATH_2 = 13 + SAY_AGGRO = 0, + SAY_INSANITY = 1, + SAY_SLAY_1 = 2, + SAY_SLAY_2 = 3, + SAY_SLAY_3 = 4, + SAY_DEATH_1 = 5, + SAY_DEATH_2 = 6, + + WHISPER_AGGRO = 7, + WHISPER_INSANITY = 8, + WHISPER_SLAY_1 = 9, + WHISPER_SLAY_2 = 10, + WHISPER_SLAY_3 = 11, + WHISPER_DEATH_1 = 12, + WHISPER_DEATH_2 = 13 }; enum VolazjSpells { - SPELL_INSANITY = 57496, // Dummy - INSANITY_VISUAL = 57561, - SPELL_INSANITY_TARGET = 57508, - SPELL_MIND_FLAY = 57941, - SPELL_SHADOW_BOLT_VOLLEY = 57942, - SPELL_SHIVER = 57949, - SPELL_CLONE_PLAYER = 57507, // cast on player during insanity - SPELL_INSANITY_PHASING_1 = 57508, - SPELL_INSANITY_PHASING_2 = 57509, - SPELL_INSANITY_PHASING_3 = 57510, - SPELL_INSANITY_PHASING_4 = 57511, - SPELL_INSANITY_PHASING_5 = 57512, - - SPELL_WHISPER_AGGRO = 60291, - SPELL_WHISPER_INSANITY = 60292, - SPELL_WHISPER_SLAY_1 = 60293, - SPELL_WHISPER_SLAY_2 = 60294, - SPELL_WHISPER_SLAY_3 = 60295, - SPELL_WHISPER_DEATH_1 = 60296, - SPELL_WHISPER_DEATH_2 = 60297 + SPELL_INSANITY = 57496, // Dummy + INSANITY_VISUAL = 57561, + SPELL_INSANITY_TARGET = 57508, + SPELL_MIND_FLAY = 57941, + SPELL_SHADOW_BOLT_VOLLEY = 57942, + SPELL_SHIVER = 57949, + SPELL_CLONE_PLAYER = 57507, // cast on player during insanity + SPELL_INSANITY_PHASING_1 = 57508, + SPELL_INSANITY_PHASING_2 = 57509, + SPELL_INSANITY_PHASING_3 = 57510, + SPELL_INSANITY_PHASING_4 = 57511, + SPELL_INSANITY_PHASING_5 = 57512, + + SPELL_WHISPER_AGGRO = 60291, + SPELL_WHISPER_INSANITY = 60292, + SPELL_WHISPER_SLAY_1 = 60293, + SPELL_WHISPER_SLAY_2 = 60294, + SPELL_WHISPER_SLAY_3 = 60295, + SPELL_WHISPER_DEATH_1 = 60296, + SPELL_WHISPER_DEATH_2 = 60297, + + SPELL_TWISTED_VISAGE_VISUAL = 57551, + SPELL_TWISTED_VISAGE_DEATH = 57555, + + // Death Knight + SPELL_TWISTED_VISAGE_DEATH_GRIP = 57602, + SPELL_TWISTED_VISAGE_PLAGUE_STRIKE = 57599, + // Druid + SPELL_TWISTED_VISAGE_WRATH = 57648, + SPELL_TWISTED_VISAGE_MOONFIRE = 57647, + SPELL_TWISTED_VISAGE_LIFEBLOOM = 57762, + SPELL_TWISTED_VISAGE_CAT_FORM = 57655, + SPELL_TWISTED_VISAGE_MANGLE = 57657, + SPELL_TWISTED_VISAGE_RIP = 57661, + SPELL_TWISTED_VISAGE_NOURISH = 57765, + // Hunter + SPELL_TWISTED_VISAGE_SHOOT = 57589, + SPELL_TWISTED_VISAGE_DISENGAGE = 57635, + // Mage + SPELL_TWISTED_VISAGE_FIREBALL = 57628, + SPELL_TWISTED_VISAGE_FROST_NOVA = 57629, + // Paladin + SPELL_TWISTED_VISAGE_CONSECRATION = 57798, + SPELL_TWISTED_VISAGE_AVENGER__S_SHIELD = 57799, + SPELL_TWISTED_VISAGE_SEAL_OF_COMMAND = 57769, + SPELL_TWISTED_VISAGE_JUDGEMENT_OF_LIGHT = 57774, + // Priest + SPELL_TWISTED_VISAGE_GREATER_HEAL = 57775, + SPELL_TWISTED_VISAGE_RENEW = 57777, + SPELL_TWISTED_VISAGE_SHADOW_WORD_PAIN = 57778, + SPELL_TWISTED_VISAGE_MIND_FLAY = 57779, + // Rogue + SPELL_TWISTED_VISAGE_EVISCERATE = 57641, + SPELL_TWISTED_VISAGE_SINISTER_STRIKE = 57640, + // Shaman + SPELL_TWISTED_VISAGE_EARTH_SHOCK = 57783, + SPELL_TWISTED_VISAGE_LIGHTNING_BOLT = 57781, + SPELL_TWISTED_VISAGE_EARTH_SHIELD = 57802, + SPELL_TWISTED_VISAGE_HEALING_WEAVE = 57785, + SPELL_TWISTED_VISAGE_THUNDERSTORM = 57784, + // Warlock + SPELL_TWISTED_VISAGE_CORRUPTION = 57645, + SPELL_TWISTED_VISAGE_SHADOW_BOLT = 57644, + // Warrior + SPELL_TWISTED_VISAGE_THUNDER_CLAP = 57832, + SPELL_TWISTED_VISAGE_DEVASTATE = 57795, + SPELL_TWISTED_VISAGE_MORTAL_STRIKE = 57789, + SPELL_TWISTED_VISAGE_INTERCEPT = 61490, + SPELL_TWISTED_VISAGE_HAMSTRING = 9080, + SPELL_TWISTED_VISAGE_BLOODTHIRST = 57790, }; enum VolazjAchievements { - ACHIEV_QUICK_DEMISE_START_EVENT = 20382, + ACHIEV_QUICK_DEMISE_START_EVENT = 20382, +}; + +enum VolazjMisc +{ + DATA_TWISTED_VISAGE_PLAYER_CLASS = 1, + DATA_TWISTED_VISAGE_PLAYER_SPEC = 2, }; struct boss_volazj : public BossAI { - boss_volazj(Creature* creature) : BossAI(creature, DATA_HERALD_VOLAZJ), _insanityHandled(0) + boss_volazj(Creature* creature) : BossAI(creature, DATA_HERALD_VOLAZJ) { Initialize(); - _instance = creature->GetInstanceScript(); } void Reset() override @@ -92,7 +144,7 @@ struct boss_volazj : public BossAI Initialize(); - _instance->DoStopTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, ACHIEV_QUICK_DEMISE_START_EVENT); + instance->DoStopTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, ACHIEV_QUICK_DEMISE_START_EVENT); // Visible for all players in insanity me->SetPhaseMask((1|16|32|64|128|256), true); @@ -113,21 +165,21 @@ struct boss_volazj : public BossAI void ScheduleTasks() override { scheduler.Schedule(8s, [this](TaskContext task) - { - DoCastVictim(SPELL_MIND_FLAY); - task.Repeat(20s); - }) - .Schedule(5s, [this](TaskContext task) - { - DoCastVictim(SPELL_SHADOW_BOLT_VOLLEY); - task.Repeat(); - }) - .Schedule(15s, [this](TaskContext task) - { - if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0)) - DoCast(target, SPELL_SHIVER); - task.Repeat(); - }); + { + DoCastVictim(SPELL_MIND_FLAY); + task.Repeat(20s); + }) + .Schedule(5s, [this](TaskContext task) + { + DoCastVictim(SPELL_SHADOW_BOLT_VOLLEY); + task.Repeat(); + }) + .Schedule(15s, [this](TaskContext task) + { + if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0)) + DoCast(target, SPELL_SHIVER); + task.Repeat(); + }); } // returns the percentage of health after taking the given damage. @@ -143,14 +195,19 @@ struct boss_volazj : public BossAI if (me->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE)) damage = 0; - if ((GetHealthPct(0) >= 66 && GetHealthPct(damage) < 66)|| - (GetHealthPct(0) >= 33 && GetHealthPct(damage) < 33)) + if ((GetHealthPct(0) >= 66 && GetHealthPct(damage) < 66) || (GetHealthPct(0) >= 33 && GetHealthPct(damage) < 33)) { me->InterruptNonMeleeSpells(false); DoCast(me, SPELL_INSANITY, false); } } + void JustSummoned(Creature* summon) override + { + summon->SetReactState(REACT_PASSIVE); + summons.Summon(summon); + } + void SpellHitTarget(WorldObject* target, SpellInfo const* spellInfo) override { if (spellInfo->Id == SPELL_INSANITY) @@ -173,18 +230,22 @@ struct boss_volazj : public BossAI target->CastSpell(target, SPELL_INSANITY_TARGET + _insanityHandled, true); // summon twisted party members for this target Map::PlayerList const& players = me->GetMap()->GetPlayers(); - for (Map::PlayerList::const_iterator i = players.begin(); i != players.end(); ++i) + for (auto i = players.begin(); i != players.end(); ++i) { Player* player = i->GetSource(); if (!player || !player->IsAlive()) continue; // Summon clone - if (Unit* summon = me->SummonCreature(NPC_TWISTED_VISAGE, me->GetPositionX(), me->GetPositionY(), me->GetPositionZ(), me->GetOrientation(), TEMPSUMMON_CORPSE_DESPAWN)) + if (TempSummon* summon = me->SummonCreature(NPC_TWISTED_VISAGE, me->GetPositionX(), me->GetPositionY(), me->GetPositionZ(), me->GetOrientation(), TEMPSUMMON_CORPSE_DESPAWN)) { // clone player->CastSpell(summon, SPELL_CLONE_PLAYER, true); + summon->GetAI()->SetData(DATA_TWISTED_VISAGE_PLAYER_CLASS, player->GetClass()); + summon->GetAI()->SetData(DATA_TWISTED_VISAGE_PLAYER_SPEC, Trinity::Helpers::Entity::GetPlayerSpecialization(player)); + summon->SetReactState(REACT_AGGRESSIVE); + DoZoneInCombat(summon); // set phase - summon->SetPhaseMask((1<<(4 + _insanityHandled)), true); + summon->SetPhaseMask((1 << (4 + _insanityHandled)), true); } } ++_insanityHandled; @@ -194,7 +255,7 @@ struct boss_volazj : public BossAI void ResetPlayersPhaseMask() { Map::PlayerList const& players = me->GetMap()->GetPlayers(); - for (Map::PlayerList::const_iterator i = players.begin(); i != players.end(); ++i) + for (auto i = players.begin(); i != players.end(); ++i) { Player* player = i->GetSource(); player->RemoveAurasDueToSpell(GetSpellForPhaseMask(player->GetPhaseMask())); @@ -207,7 +268,7 @@ struct boss_volazj : public BossAI Talk(SAY_AGGRO); DoCastSelf(SPELL_WHISPER_AGGRO); - _instance->DoStartTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, ACHIEV_QUICK_DEMISE_START_EVENT); + instance->DoStartTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, ACHIEV_QUICK_DEMISE_START_EVENT); } uint32 GetSpellForPhaseMask(uint32 phase) @@ -257,19 +318,16 @@ struct boss_volazj : public BossAI // Roll Insanity uint32 spell = GetSpellForPhaseMask(phase); uint32 spell2 = GetSpellForPhaseMask(nextPhase); - Map::PlayerList const& PlayerList = me->GetMap()->GetPlayers(); - if (!PlayerList.isEmpty()) + Map::PlayerList const& playerList = me->GetMap()->GetPlayers(); + for (auto itr = playerList.begin(); itr != playerList.end(); ++itr) { - for (Map::PlayerList::const_iterator i = PlayerList.begin(); i != PlayerList.end(); ++i) + if (Player* player = itr->GetSource()) { - if (Player* player = i->GetSource()) + if (player->HasAura(spell)) { - if (player->HasAura(spell)) - { - player->RemoveAurasDueToSpell(spell); - if (spell2) // if there is still some different mask cast spell for it - player->CastSpell(player, spell2, true); - } + player->RemoveAurasDueToSpell(spell); + if (spell2) // if there is still some different mask cast spell for it + player->CastSpell(player, spell2, true); } } } @@ -277,7 +335,6 @@ struct boss_volazj : public BossAI void UpdateAI(uint32 diff) override { - //Return since we have no target if (!UpdateVictim()) return; @@ -339,11 +396,381 @@ struct boss_volazj : public BossAI } private: - InstanceScript* _instance; - uint32 _insanityHandled; }; +struct npc_twisted_visage : public ScriptedAI +{ + npc_twisted_visage(Creature* creature) : ScriptedAI(creature), _playerClass(CLASS_NONE), _playerSpec(0) { } + + void Reset() override + { + DoCastSelf(SPELL_TWISTED_VISAGE_VISUAL, true); + + _scheduler.SetValidator([this] + { + return !me->HasUnitState(UNIT_STATE_CASTING); + }); + } + + void AttackStart(Unit* who) override + { + switch (_playerClass) + { + case CLASS_SHAMAN: + switch (_playerSpec) + { + case SPEC_SHAMAN_ELEMENTAL: + case SPEC_SHAMAN_RESTORATION: + ScriptedAI::AttackStartCaster(who, 25.0f); + break; + default: + break; + } + break; + case CLASS_DRUID: + switch (_playerSpec) + { + case SPEC_DRUID_BALANCE: + case SPEC_DRUID_RESTORATION: + ScriptedAI::AttackStartCaster(who, 25.0f); + break; + default: + break; + } + break; + case CLASS_PRIEST: + case CLASS_HUNTER: + case CLASS_MAGE: + case CLASS_WARLOCK: + ScriptedAI::AttackStartCaster(who, 25.0f); + break; + case CLASS_ROGUE: + ScriptedAI::AttackStart(who); + break; + default: + ScriptedAI::AttackStart(who); + break; + } + } + + void SetData(uint32 type, uint32 data) override + { + if (type == DATA_TWISTED_VISAGE_PLAYER_CLASS) + { + if (data > CLASS_NONE && data <= CLASS_DRUID) + _playerClass = data; + } + else if (type == DATA_TWISTED_VISAGE_PLAYER_SPEC && _playerClass != CLASS_NONE) + { + if (data < 3) + _playerSpec = data; + + switch (_playerClass) + { + case CLASS_WARRIOR: + switch (data) + { + case SPEC_WARRIOR_ARMS: + _scheduler.Schedule(3s, [this](TaskContext mortalStrike) + { + DoCastVictim(SPELL_TWISTED_VISAGE_MORTAL_STRIKE); + mortalStrike.Repeat(3s, 5s); + }).Schedule(5s, [this](TaskContext harmstring) + { + DoCastVictim(SPELL_TWISTED_VISAGE_HAMSTRING); + harmstring.Repeat(5s, 10s); + }); + break; + default: + case SPEC_WARRIOR_FURY: + _scheduler.Schedule(2s, [this](TaskContext intercept) + { + if (Unit* target = SelectTarget(SelectTargetMethod::MaxThreat, 0, -8.f)) + { + DoCastVictim(SPELL_TWISTED_VISAGE_INTERCEPT); + intercept.Repeat(12s); + } + else + intercept.Repeat(1s); + }).Schedule(3s, [this](TaskContext bloodthirst) + { + DoCastVictim(SPELL_TWISTED_VISAGE_BLOODTHIRST); + bloodthirst.Repeat(3s, 5s); + }); + break; + case SPEC_WARRIOR_PROTECTION: + _scheduler.Schedule(5s, [this](TaskContext thunderClap) + { + DoCastSelf(SPELL_TWISTED_VISAGE_THUNDER_CLAP); + thunderClap.Repeat(5s, 10s); + }).Schedule(3s, [this](TaskContext devastate) + { + DoCastVictim(SPELL_TWISTED_VISAGE_DEVASTATE); + devastate.Repeat(3s, 5s); + }); + break; + } + break; + case CLASS_PALADIN: + switch (data) + { + case SPEC_PALADIN_PROTECTION: + _scheduler.Schedule(5s, [this](TaskContext consecration) + { + DoCastSelf(SPELL_TWISTED_VISAGE_CONSECRATION); + consecration.Repeat(5s, 10s); + }).Schedule(2s, [this](TaskContext avengersShield) + { + DoCastVictim(SPELL_TWISTED_VISAGE_AVENGER__S_SHIELD); + avengersShield.Repeat(5s, 10s); + }); + break; + default: + case SPEC_PALADIN_RETRIBUTION: + _scheduler.Schedule(5s, [this](TaskContext consecration) + { + DoCastSelf(SPELL_TWISTED_VISAGE_CONSECRATION); + consecration.Repeat(5s, 10s); + }).Schedule(2s, [this](TaskContext /*sealCommand*/) + { + DoCastSelf(SPELL_TWISTED_VISAGE_SEAL_OF_COMMAND); + }).Schedule(3s, [this](TaskContext judgementLight) + { + DoCastVictim(SPELL_TWISTED_VISAGE_JUDGEMENT_OF_LIGHT); + judgementLight.Repeat(3s, 5s); + }); + break; + } + break; + case CLASS_HUNTER: + _scheduler.Schedule(2s, [this](TaskContext shoot) + { + DoCastVictim(SPELL_TWISTED_VISAGE_SHOOT); + shoot.Repeat(1s, 4s); + }).Schedule(5s, [this](TaskContext disengage) + { + if (Unit* target = SelectTarget(SelectTargetMethod::MaxThreat, 0, 4.f)) + { + DoCastVictim(SPELL_TWISTED_VISAGE_DISENGAGE); + disengage.Repeat(10s, 20s); + } + else + disengage.Repeat(1s); + }); + break; + case CLASS_ROGUE: + me->SetCanDualWield(true); + _scheduler.Schedule(5s, [this](TaskContext eviscerate) + { + DoCastVictim(SPELL_TWISTED_VISAGE_EVISCERATE); + eviscerate.Repeat(5s, 10s); + }).Schedule(2s, [this](TaskContext sinisterStrike) + { + DoCastVictim(SPELL_TWISTED_VISAGE_SINISTER_STRIKE); + sinisterStrike.Repeat(3s, 5s); + }); + break; + case CLASS_PRIEST: + switch (data) + { + case SPEC_PRIEST_SHADOW: + _scheduler.Schedule(5s, [this](TaskContext shadowWordPain) + { + DoCastVictim(SPELL_TWISTED_VISAGE_SHADOW_WORD_PAIN); + shadowWordPain.Repeat(5s, 10s); + }).Schedule(2s, [this](TaskContext mindFlay) + { + DoCastVictim(SPELL_TWISTED_VISAGE_MIND_FLAY); + mindFlay.Repeat(3s, 5s); + }); + break; + default: + _scheduler.Schedule(2s, [this](TaskContext renew) + { + if (Unit* target = DoSelectLowestHpFriendly(40.f)) + { + DoCast(target, SPELL_TWISTED_VISAGE_RENEW); + renew.Repeat(2s, 5s); + } + else + renew.Repeat(1s); + }).Schedule(4s, [this](TaskContext greaterHeal) + { + if (Unit* target = DoSelectLowestHpFriendly(40.f)) + { + DoCast(target, SPELL_TWISTED_VISAGE_GREATER_HEAL); + greaterHeal.Repeat(4s, 6s); + } + else + greaterHeal.Repeat(1s); + }); + break; + } + break; + case CLASS_DEATH_KNIGHT: + _scheduler.Schedule(5s, [this](TaskContext deathGrip) + { + if (Unit* target = SelectTarget(SelectTargetMethod::MaxThreat, 0, -3.f)) + { + DoCastVictim(SPELL_TWISTED_VISAGE_DEATH_GRIP); + deathGrip.Repeat(12s); + } + else + deathGrip.Repeat(1s); + }).Schedule(2s, [this](TaskContext plagueStrike) + { + DoCastVictim(SPELL_TWISTED_VISAGE_PLAGUE_STRIKE); + plagueStrike.Repeat(3s, 5s); + }); + break; + case CLASS_SHAMAN: + switch (data) + { + default: + case SPEC_SHAMAN_ELEMENTAL: + _scheduler.Schedule(5s, [this](TaskContext thunderstorm) + { + DoCastSelf(SPELL_TWISTED_VISAGE_THUNDERSTORM); + thunderstorm.Repeat(5s, 10s); + }).Schedule(2s, [this](TaskContext lightningBolt) + { + DoCastVictim(SPELL_TWISTED_VISAGE_LIGHTNING_BOLT); + lightningBolt.Repeat(3s, 5s); + }); + break; + case SPEC_SHAMAN_ENHANCEMENT: + _scheduler.Schedule(2s, [this](TaskContext earthShock) + { + DoCastVictim(SPELL_TWISTED_VISAGE_EARTH_SHOCK); + earthShock.Repeat(3s, 5s); + }); + break; + case SPEC_SHAMAN_RESTORATION: + _scheduler.Schedule(2s, [this](TaskContext earthShield) + { + if (Unit* target = DoSelectLowestHpFriendly(40.f)) + { + DoCast(target, SPELL_TWISTED_VISAGE_EARTH_SHIELD); + earthShield.Repeat(4s, 6s); + } + else + earthShield.Repeat(1s); + }).Schedule(4s, [this](TaskContext healingWave) + { + if (Unit* target = DoSelectLowestHpFriendly(40.f)) + { + DoCast(target, SPELL_TWISTED_VISAGE_HEALING_WEAVE); + healingWave.Repeat(4s, 6s); + } + else + healingWave.Repeat(1s); + }); + break; + } + break; + case CLASS_MAGE: + _scheduler.Schedule(5s, [this](TaskContext frostNova) + { + DoCastSelf(SPELL_TWISTED_VISAGE_FROST_NOVA); + frostNova.Repeat(5s, 10s); + }).Schedule(2s, [this](TaskContext fireball) + { + DoCastVictim(SPELL_TWISTED_VISAGE_FIREBALL); + fireball.Repeat(3s, 5s); + }); + break; + case CLASS_WARLOCK: + _scheduler.Schedule(2s, [this](TaskContext corruption) + { + DoCastVictim(SPELL_TWISTED_VISAGE_CORRUPTION); + corruption.Repeat(6s, 10s); + }).Schedule(3s, [this](TaskContext shadowBolt) + { + DoCastVictim(SPELL_TWISTED_VISAGE_SHADOW_BOLT); + shadowBolt.Repeat(3s, 5s); + }); + break; + case CLASS_DRUID: + switch (data) + { + case SPEC_DRUID_BALANCE: + _scheduler.Schedule(2s, [this](TaskContext moonfire) + { + DoCastVictim(SPELL_TWISTED_VISAGE_MOONFIRE); + moonfire.Repeat(3s, 5s); + }).Schedule(3s, [this](TaskContext wrath) + { + DoCastVictim(SPELL_TWISTED_VISAGE_WRATH); + wrath.Repeat(3s, 5s); + }); + break; + case SPEC_DRUID_FERAL: + _scheduler.Schedule(1ms, [this](TaskContext /*catForm*/) + { + DoCastSelf(SPELL_TWISTED_VISAGE_CAT_FORM); + }).Schedule(2s, [this](TaskContext mangle) + { + DoCastVictim(SPELL_TWISTED_VISAGE_MANGLE); + mangle.Repeat(3s, 5s); + }).Schedule(3s, [this](TaskContext rip) + { + DoCastVictim(SPELL_TWISTED_VISAGE_RIP); + rip.Repeat(3s, 5s); + }); + break; + default: + case SPEC_DRUID_RESTORATION: + _scheduler.Schedule(2s, [this](TaskContext lifebloom) + { + if (Unit* target = DoSelectLowestHpFriendly(40.f)) + { + DoCast(target, SPELL_TWISTED_VISAGE_LIFEBLOOM); + lifebloom.Repeat(4s, 6s); + } + else + lifebloom.Repeat(1s); + }).Schedule(4s, [this](TaskContext nourish) + { + if (Unit* target = DoSelectLowestHpFriendly(40.f)) + { + DoCast(target, SPELL_TWISTED_VISAGE_NOURISH); + nourish.Repeat(4s, 6s); + } + else + nourish.Repeat(1s); + }); + break; + } + break; + default: + break; + } + } + } + + void JustDied(Unit* /*killer*/) override + { + DoCastSelf(SPELL_TWISTED_VISAGE_DEATH, true); + } + + void UpdateAI(uint32 diff) override + { + if (!UpdateVictim()) + return; + + _scheduler.Update(diff, [this] + { + DoMeleeAttackIfReady(); + }); + } + +private: + TaskScheduler _scheduler; + uint32 _playerClass; + uint32 _playerSpec; +}; + /* 60291 - Volazj Whisper: Aggro 60292 - Volazj Whisper: Insanity 60293 - Volazj Whisper: Slay 01 @@ -400,5 +827,6 @@ class spell_volazj_whisper : public SpellScript void AddSC_boss_volazj() { RegisterAhnKahetCreatureAI(boss_volazj); + RegisterAhnKahetCreatureAI(npc_twisted_visage); RegisterSpellScript(spell_volazj_whisper); } |