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
This commit is contained in:
ccrs
2021-08-19 03:16:46 +02:00
parent 32282b7326
commit 7360c2d156
2 changed files with 506 additions and 77 deletions

View File

@@ -0,0 +1 @@
UPDATE `creature_template` SET `ScriptName`='npc_twisted_visage' WHERE `entry`=30625;

View File

@@ -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,
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
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_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_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);
}