refactor(Scripts/AhnKahet): new script system (#9040)

This commit is contained in:
Kitzunu
2021-11-28 08:23:19 +01:00
committed by GitHub
parent 801a20fce2
commit 05a2d5baa8
7 changed files with 1619 additions and 1819 deletions
@@ -71,4 +71,7 @@ inline AI* GetAhnKahetAI(T* obj)
return GetInstanceAI<AI>(obj, AhnKahetScriptName); return GetInstanceAI<AI>(obj, AhnKahetScriptName);
} }
#define RegisterAhnKahetCreatureAI(ai_name) RegisterCreatureAIWithFactory(ai_name, GetAhnKahetAI)
#define RegisterAhnKahetGameObjectAI(ai_name) RegisterGameObjectAIWithFactory(ai_name, GetAhnKahetAI)
#endif // DEF_AHNKAHET_H #endif // DEF_AHNKAHET_H
@@ -99,288 +99,253 @@ Position const MushroomPositions[MAX_MUSHROOMS_COUNT] =
{ 398.2797f, -851.8694f, -68.84419f, 0.5759587f } { 398.2797f, -851.8694f, -68.84419f, 0.5759587f }
}; };
class boss_amanitar : public CreatureScript struct boss_amanitar : public BossAI
{ {
public: boss_amanitar(Creature* creature) : BossAI(creature, DATA_AMANITAR), mushroomsSummoned(false)
boss_amanitar() : CreatureScript("boss_amanitar")
{ {
creature->ApplySpellImmune(0, IMMUNITY_SCHOOL, SPELL_SCHOOL_MASK_NATURE, true);
creature->SetMeleeDamageSchool(SPELL_SCHOOL_NATURE);
} }
struct boss_amanitarAI : public BossAI void Reset() override
{ {
boss_amanitarAI(Creature* creature) : BossAI(creature, DATA_AMANITAR), mushroomsSummoned(false) _Reset();
_mushroomsDeque.clear();
mushroomsSummoned = false;
}
void EnterCombat(Unit* /*attacker*/) override
{
events.ScheduleEvent(EVENT_ROOTS, urand(5000, 9000));
events.ScheduleEvent(EVENT_BASH, urand(10000, 14000));
events.ScheduleEvent(EVENT_BOLT, urand(15000, 20000));
events.ScheduleEvent(EVENT_MINI, 1000);
events.ScheduleEvent(EVENT_RESPAWN, 40000, 60000);
}
void JustDied(Unit* /*Killer*/) override
{
_JustDied();
instance->DoRemoveAurasDueToSpellOnPlayers(SPELL_MINI);
}
void JustSummoned(Creature* summon) override
{
summons.Summon(summon);
}
void SummonedCreatureDies(Creature* summon, Unit* killer) override
{
_mushroomsDeque.push_back(summon->GetPosition());
BossAI::SummonedCreatureDies(summon, killer);
}
void EnterEvadeMode() override
{
instance->DoRemoveAurasDueToSpellOnPlayers(SPELL_MINI);
BossAI::EnterEvadeMode();
}
void ExecuteEvent(uint32 eventId) override
{
switch (eventId)
{ {
creature->ApplySpellImmune(0, IMMUNITY_SCHOOL, SPELL_SCHOOL_MASK_NATURE, true); case EVENT_RESPAWN:
creature->SetMeleeDamageSchool(SPELL_SCHOOL_NATURE); {
while (!_mushroomsDeque.empty())
{
SummonMushroom(_mushroomsDeque.front());
_mushroomsDeque.pop_front();
}
events.RepeatEvent(urand(40000, 60000));
break;
}
case EVENT_ROOTS:
{
if (Unit* pTarget = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true))
{
DoCast(pTarget, SPELL_ENTANGLING_ROOTS, false);
}
events.RepeatEvent(urand(10000, 15000));
break;
}
case EVENT_BASH:
{
DoCastVictim(SPELL_BASH, false);
events.RepeatEvent(urand(15000, 20000));
break;
}
case EVENT_BOLT:
{
if (Unit* pTarget = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true))
{
DoCast(pTarget, SPELL_VENOM_BOLT_VOLLEY, false);
}
events.RepeatEvent(urand(15000, 20000));
break;
}
case EVENT_REMOVE_MUSHROOM_POWER:
{
DoCastAOE(SPELL_REMOVE_MUSHROOM_POWER, true);
events.RescheduleEvent(EVENT_MINI, 1000);
break;
}
case EVENT_MINI:
{
if (!mushroomsSummoned)
{
mushroomsSummoned = true;
for (uint8 i = 0; i < MAX_MUSHROOMS_COUNT; ++i)
{
SummonMushroom(MushroomPositions[i]);
}
}
if (SelectTarget(SELECT_TARGET_RANDOM, 0, 0.0f, true, -SPELL_MINI))
{
DoCastSelf(SPELL_REMOVE_MUSHROOM_POWER, true);
DoCastAOE(SPELL_MINI);
events.RescheduleEvent(EVENT_REMOVE_MUSHROOM_POWER, 29000);
}
else
{
events.RepeatEvent(1000);
}
break;
}
}
}
private:
std::deque<Position> _mushroomsDeque;
bool mushroomsSummoned;
void SummonMushroom(Position const& pos)
{
me->SummonCreature(roll_chance_i(40) ? NPC_HEALTHY_MUSHROOM : NPC_POISONOUS_MUSHROOM, pos, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 4000);
}
};
struct npc_amanitar_mushrooms : public ScriptedAI
{
npc_amanitar_mushrooms(Creature* pCreature) : ScriptedAI(pCreature)
{
SetCombatMovement(false);
//TODO: this prolly needs to be done in database
pCreature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
pCreature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE);
pCreature->SetRegeneratingHealth(false);
}
// Disabled events
void EnterCombat(Unit* /*who*/) override {}
void AttackStart(Unit* /*victim*/) override {}
void EnterEvadeMode() override {}
void Reset() override
{
me->SetReactState(REACT_PASSIVE);
DoCastSelf(SPELL_PUTRID_MUSHROOM);
if (me->GetEntry() == NPC_POISONOUS_MUSHROOM)
{
DoCastSelf(SPELL_POISONOUS_MUSHROOM_VISUAL_AURA, true);
}
else
{
DoCastSelf(SPELL_HEALTHY_MUSHROOM_VISUAL_AURA, true);
} }
void Reset() override events.ScheduleEvent(EVENT_GROW, 800);
{
_Reset();
_mushroomsDeque.clear();
mushroomsSummoned = false;
}
void EnterCombat(Unit* /*attacker*/) override if (me->GetEntry() == NPC_POISONOUS_MUSHROOM)
{ {
events.ScheduleEvent(EVENT_ROOTS, urand(5000, 9000)); events.ScheduleEvent(EVENT_CHECK_PLAYER, 250);
events.ScheduleEvent(EVENT_BASH, urand(10000, 14000));
events.ScheduleEvent(EVENT_BOLT, urand(15000, 20000));
events.ScheduleEvent(EVENT_MINI, 1000);
events.ScheduleEvent(EVENT_RESPAWN, 40000, 60000);
} }
}
void JustDied(Unit* /*Killer*/) override void DamageTaken(Unit* /*attacker*/, uint32& damage, DamageEffectType /*damagetype*/, SpellSchoolMask /*damageSchoolMask*/) override
{
if (me->GetEntry() == NPC_HEALTHY_MUSHROOM && damage >= me->GetHealth())
{ {
_JustDied(); DoCastSelf(SPELL_HEALTHY_MUSHROOM_POTENT_FUNGUS, true);
instance->DoRemoveAurasDueToSpellOnPlayers(SPELL_MINI);
} }
}
void JustSummoned(Creature* summon) override void UpdateAI(uint32 diff) override
{ {
summons.Summon(summon); if (events.Empty())
} return;
void SummonedCreatureDies(Creature* summon, Unit* killer) override events.Update(diff);
{ while (uint32 const eventId = events.ExecuteEvent())
_mushroomsDeque.push_back(summon->GetPosition());
BossAI::SummonedCreatureDies(summon, killer);
}
void EnterEvadeMode() override
{
instance->DoRemoveAurasDueToSpellOnPlayers(SPELL_MINI);
BossAI::EnterEvadeMode();
}
void ExecuteEvent(uint32 eventId) override
{ {
switch (eventId) switch (eventId)
{ {
case EVENT_RESPAWN: case EVENT_GROW:
{ {
while (!_mushroomsDeque.empty()) DoCastSelf(SPELL_GROW);
{
SummonMushroom(_mushroomsDeque.front());
_mushroomsDeque.pop_front();
}
events.RepeatEvent(urand(40000, 60000));
break; break;
} }
case EVENT_ROOTS: case EVENT_CHECK_PLAYER:
{ {
if (Unit* pTarget = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true)) if (Player* plr = me->SelectNearestPlayer(2.0f))
{ {
DoCast(pTarget, SPELL_ENTANGLING_ROOTS, false); plr->RemoveAurasDueToSpell(SPELL_HEALTHY_MUSHROOM_POTENT_FUNGUS);
} DoCastSelf(SPELL_POISONOUS_MUSHROOM_VISUAL_AREA);
DoCastSelf(SPELL_POISONOUS_MUSHROOM_POISON_CLOUD);
events.RepeatEvent(urand(10000, 15000)); DoCastSelf(SPELL_SHRINK);
break; events.ScheduleEvent(EVENT_KILLSELF, 4000);
}
case EVENT_BASH:
{
DoCastVictim(SPELL_BASH, false);
events.RepeatEvent(urand(15000, 20000));
break;
}
case EVENT_BOLT:
{
if (Unit* pTarget = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true))
{
DoCast(pTarget, SPELL_VENOM_BOLT_VOLLEY, false);
}
events.RepeatEvent(urand(15000, 20000));
break;
}
case EVENT_REMOVE_MUSHROOM_POWER:
{
DoCastAOE(SPELL_REMOVE_MUSHROOM_POWER, true);
events.RescheduleEvent(EVENT_MINI, 1000);
break;
}
case EVENT_MINI:
{
if (!mushroomsSummoned)
{
mushroomsSummoned = true;
for (uint8 i = 0; i < MAX_MUSHROOMS_COUNT; ++i)
{
SummonMushroom(MushroomPositions[i]);
}
}
if (SelectTarget(SELECT_TARGET_RANDOM, 0, 0.0f, true, -SPELL_MINI))
{
DoCastSelf(SPELL_REMOVE_MUSHROOM_POWER, true);
DoCastAOE(SPELL_MINI);
events.RescheduleEvent(EVENT_REMOVE_MUSHROOM_POWER, 29000);
} }
else else
{ {
events.RepeatEvent(1000); events.RepeatEvent(250);
} }
break; break;
} }
} case EVENT_KILLSELF:
}
private:
std::deque<Position> _mushroomsDeque;
bool mushroomsSummoned;
void SummonMushroom(Position const& pos)
{
me->SummonCreature(roll_chance_i(40) ? NPC_HEALTHY_MUSHROOM : NPC_POISONOUS_MUSHROOM, pos, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 4000);
}
};
CreatureAI* GetAI(Creature* creature) const override
{
return GetAhnKahetAI<boss_amanitarAI>(creature);
}
};
class npc_amanitar_mushrooms : public CreatureScript
{
public:
npc_amanitar_mushrooms() : CreatureScript("npc_amanitar_mushrooms") { }
struct npc_amanitar_mushroomsAI : public ScriptedAI
{
npc_amanitar_mushroomsAI(Creature* pCreature) : ScriptedAI(pCreature)
{
SetCombatMovement(false);
//TODO: this prolly needs to be done in database
pCreature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
pCreature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE);
pCreature->SetRegeneratingHealth(false);
}
// Disabled events
void EnterCombat(Unit* /*who*/) override {}
void AttackStart(Unit* /*victim*/) override {}
void EnterEvadeMode() override {}
void Reset() override
{
me->SetReactState(REACT_PASSIVE);
DoCastSelf(SPELL_PUTRID_MUSHROOM);
if (me->GetEntry() == NPC_POISONOUS_MUSHROOM)
{
DoCastSelf(SPELL_POISONOUS_MUSHROOM_VISUAL_AURA, true);
}
else
{
DoCastSelf(SPELL_HEALTHY_MUSHROOM_VISUAL_AURA, true);
}
events.ScheduleEvent(EVENT_GROW, 800);
if (me->GetEntry() == NPC_POISONOUS_MUSHROOM)
{
events.ScheduleEvent(EVENT_CHECK_PLAYER, 250);
}
}
void DamageTaken(Unit* /*attacker*/, uint32& damage, DamageEffectType /*damagetype*/, SpellSchoolMask /*damageSchoolMask*/) override
{
if (me->GetEntry() == NPC_HEALTHY_MUSHROOM && damage >= me->GetHealth())
{
DoCastSelf(SPELL_HEALTHY_MUSHROOM_POTENT_FUNGUS, true);
}
}
void UpdateAI(uint32 diff) override
{
if (events.Empty())
return;
events.Update(diff);
while (uint32 const eventId = events.ExecuteEvent())
{
switch (eventId)
{ {
case EVENT_GROW: me->DisappearAndDie();
{ break;
DoCastSelf(SPELL_GROW);
break;
}
case EVENT_CHECK_PLAYER:
{
if (Player* plr = me->SelectNearestPlayer(2.0f))
{
plr->RemoveAurasDueToSpell(SPELL_HEALTHY_MUSHROOM_POTENT_FUNGUS);
DoCastSelf(SPELL_POISONOUS_MUSHROOM_VISUAL_AREA);
DoCastSelf(SPELL_POISONOUS_MUSHROOM_POISON_CLOUD);
DoCastSelf(SPELL_SHRINK);
events.ScheduleEvent(EVENT_KILLSELF, 4000);
}
else
{
events.RepeatEvent(250);
}
break;
}
case EVENT_KILLSELF:
{
me->DisappearAndDie();
break;
}
} }
} }
} }
private:
EventMap events;
};
CreatureAI* GetAI(Creature* creature) const override
{
return GetAhnKahetAI<npc_amanitar_mushroomsAI>(creature);
} }
private:
EventMap events;
}; };
// 57283 Remove Mushroom Power // 57283 Remove Mushroom Power
class spell_amanitar_remove_mushroom_power : public SpellScriptLoader class spell_amanitar_remove_mushroom_power : public AuraScript
{ {
public: PrepareAuraScript(spell_amanitar_remove_mushroom_power);
spell_amanitar_remove_mushroom_power() : SpellScriptLoader("spell_amanitar_remove_mushroom_power") { }
class spell_amanitar_remove_mushroom_power_AuraScript : public AuraScript void HandleApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
{ {
PrepareAuraScript(spell_amanitar_remove_mushroom_power_AuraScript); if (Unit* target = GetTarget())
void HandleApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
{ {
if (Unit* target = GetTarget()) target->RemoveAurasDueToSpell(SPELL_HEALTHY_MUSHROOM_POTENT_FUNGUS);
{
target->RemoveAurasDueToSpell(SPELL_HEALTHY_MUSHROOM_POTENT_FUNGUS);
}
} }
}
void Register() override void Register() override
{
OnEffectApply += AuraEffectApplyFn(spell_amanitar_remove_mushroom_power_AuraScript::HandleApply, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL);
}
};
AuraScript* GetAuraScript() const
{ {
return new spell_amanitar_remove_mushroom_power_AuraScript(); OnEffectApply += AuraEffectApplyFn(spell_amanitar_remove_mushroom_power::HandleApply, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL);
} }
}; };
void AddSC_boss_amanitar() void AddSC_boss_amanitar()
{ {
new boss_amanitar(); RegisterAhnKahetCreatureAI(boss_amanitar);
new npc_amanitar_mushrooms(); RegisterAhnKahetCreatureAI(npc_amanitar_mushrooms);
// Spells // Spells
new spell_amanitar_remove_mushroom_power(); RegisterSpellScript(spell_amanitar_remove_mushroom_power);
} }
@@ -69,336 +69,303 @@ enum Yells
EMOTE_HATCHES = 4 EMOTE_HATCHES = 4
}; };
class boss_elder_nadox : public CreatureScript struct boss_elder_nadox : public BossAI
{ {
public: boss_elder_nadox(Creature* creature) : BossAI(creature, DATA_PRINCE_TALDARAM),
boss_elder_nadox() : CreatureScript("boss_elder_nadox") { } guardianSummoned(false),
respectYourElders(true)
struct boss_elder_nadoxAI : public BossAI
{ {
boss_elder_nadoxAI(Creature* creature) : BossAI(creature, DATA_PRINCE_TALDARAM), }
guardianSummoned(false),
respectYourElders(true) void Reset() override
{
_Reset();
// Clear eggs data
swarmEggs.clear();
guardianEggs.clear();
previousSwarmEgg_GUID.Clear();
guardianSummoned = false;
respectYourElders = true;
}
void EnterCombat(Unit * /*who*/) override
{
_EnterCombat();
Talk(SAY_AGGRO);
events.ScheduleEvent(EVENT_SWARMER, 10000);
events.ScheduleEvent(EVENT_CHECK_HOME, 2000);
events.ScheduleEvent(EVENT_PLAGUE, urand(5000, 8000));
if (IsHeroic())
{ {
events.ScheduleEvent(EVENT_BROOD_RAGE, 5000);
} }
void Reset() override // Cache eggs
std::list<Creature*> eggs;
// Swarm eggs
me->GetCreatureListWithEntryInGrid(eggs, NPC_AHNKAHAR_SWARM_EGG, 250.0f);
if (!eggs.empty())
{ {
_Reset(); for (Creature* const egg : eggs)
// Clear eggs data
swarmEggs.clear();
guardianEggs.clear();
previousSwarmEgg_GUID.Clear();
guardianSummoned = false;
respectYourElders = true;
}
void EnterCombat(Unit * /*who*/) override
{
_EnterCombat();
Talk(SAY_AGGRO);
events.ScheduleEvent(EVENT_SWARMER, 10000);
events.ScheduleEvent(EVENT_CHECK_HOME, 2000);
events.ScheduleEvent(EVENT_PLAGUE, urand(5000, 8000));
if (IsHeroic())
{ {
events.ScheduleEvent(EVENT_BROOD_RAGE, 5000); if (egg)
}
// Cache eggs
std::list<Creature*> eggs;
// Swarm eggs
me->GetCreatureListWithEntryInGrid(eggs, NPC_AHNKAHAR_SWARM_EGG, 250.0f);
if (!eggs.empty())
{
for (Creature* const egg : eggs)
{ {
if (egg) swarmEggs.push_back(egg->GetGUID());
{
swarmEggs.push_back(egg->GetGUID());
}
}
}
eggs.clear();
// Guardian eggs
me->GetCreatureListWithEntryInGrid(eggs, NPC_AHNKAHAR_GUARDIAN_EGG, 250.0f);
if (!eggs.empty())
{
for (Creature* const egg : eggs)
{
if (egg)
{
guardianEggs.push_back(egg->GetGUID());
}
} }
} }
} }
void SummonedCreatureDies(Creature* summon, Unit* /*killer*/) override eggs.clear();
// Guardian eggs
me->GetCreatureListWithEntryInGrid(eggs, NPC_AHNKAHAR_GUARDIAN_EGG, 250.0f);
if (!eggs.empty())
{ {
if (summon->GetEntry() == NPC_AHNKAHAR_GUARDIAN) for (Creature* const egg : eggs)
{ {
respectYourElders = false; if (egg)
{
guardianEggs.push_back(egg->GetGUID());
}
}
}
}
void SummonedCreatureDies(Creature* summon, Unit* /*killer*/) override
{
if (summon->GetEntry() == NPC_AHNKAHAR_GUARDIAN)
{
respectYourElders = false;
}
}
void KilledUnit(Unit* victim) override
{
if (victim->GetTypeId() == TYPEID_PLAYER)
{
Talk(SAY_SLAY);
}
}
void JustDied(Unit* /*killer*/) override
{
_JustDied();
Talk(SAY_DEATH);
}
void DamageTaken(Unit* /*attacker*/, uint32& damage, DamageEffectType /*damageType*/, SpellSchoolMask /*school*/) override
{
if (!guardianSummoned && me->HealthBelowPctDamaged(55, damage))
{
SummonHelpers(false);
guardianSummoned = true;
}
}
uint32 GetData(uint32 type) const override
{
if (type == DATA_RESPECT_YOUR_ELDERS)
{
return respectYourElders ? 1 : 0;
}
return 0;
}
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
{
return;
}
events.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING))
{
return;
}
while (uint32 const eventId = events.ExecuteEvent())
{
switch (eventId)
{
case EVENT_BROOD_RAGE:
{
if (Creature* pSwarmer = me->FindNearestCreature(NPC_AHNKAHAR_SWARMER, 40, true))
DoCast(pSwarmer, SPELL_BROOD_RAGE_H, true);
events.RepeatEvent(10000);
break;
}
case EVENT_PLAGUE:
{
DoCastVictim(SPELL_BROOD_PLAGUE, false);
events.RepeatEvent(urand(12000, 17000));
break;
}
case EVENT_SWARMER:
{
SummonHelpers(true);
events.RepeatEvent(10000);
break;
}
case EVENT_CHECK_HOME:
{
if (!me->HasAura(SPELL_ENRAGE) && (me->GetPositionZ() < 24.0f || !me->GetHomePosition().IsInDist(me->GetPositionX(), me->GetPositionY(), me->GetPositionZ(), 110.0f)))
{
DoCastSelf(SPELL_ENRAGE, true);
}
break;
}
} }
} }
void KilledUnit(Unit* victim) override DoMeleeAttackIfReady();
{ }
if (victim->GetTypeId() == TYPEID_PLAYER)
{
Talk(SAY_SLAY);
}
}
void JustDied(Unit* /*killer*/) override private:
{ GuidList swarmEggs;
_JustDied(); GuidList guardianEggs;
Talk(SAY_DEATH); ObjectGuid previousSwarmEgg_GUID; // This will prevent casting summoning spells on same egg twice
} bool guardianSummoned;
bool respectYourElders;
void DamageTaken(Unit* /*attacker*/, uint32& damage, DamageEffectType /*damageType*/, SpellSchoolMask /*school*/) override void SummonHelpers(bool swarm)
{
if (swarm)
{ {
if (!guardianSummoned && me->HealthBelowPctDamaged(55, damage)) if (swarmEggs.empty())
{
SummonHelpers(false);
guardianSummoned = true;
}
}
uint32 GetData(uint32 type) const override
{
if (type == DATA_RESPECT_YOUR_ELDERS)
{
return respectYourElders ? 1 : 0;
}
return 0;
}
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
{ {
return; return;
} }
events.Update(diff); // Make a copy of guid list
GuidList swarmEggs2 = swarmEggs;
if (me->HasUnitState(UNIT_STATE_CASTING)) // Remove previous egg
if (previousSwarmEgg_GUID)
{
std::list<ObjectGuid>::iterator itr = std::find(swarmEggs2.begin(), swarmEggs2.end(), previousSwarmEgg_GUID);
if (itr != swarmEggs2.end())
{
swarmEggs2.erase(itr);
}
}
if (swarmEggs2.empty())
{ {
return; return;
} }
while (uint32 const eventId = events.ExecuteEvent()) previousSwarmEgg_GUID = Acore::Containers::SelectRandomContainerElement(swarmEggs2);
{
switch (eventId)
{
case EVENT_BROOD_RAGE:
{
if (Creature* pSwarmer = me->FindNearestCreature(NPC_AHNKAHAR_SWARMER, 40, true))
DoCast(pSwarmer, SPELL_BROOD_RAGE_H, true);
events.RepeatEvent(10000); if (Creature* egg = ObjectAccessor::GetCreature(*me, previousSwarmEgg_GUID))
break; {
} egg->CastSpell(egg, SPELL_SUMMON_SWARMERS, true, nullptr, nullptr, me->GetGUID());
case EVENT_PLAGUE:
{
DoCastVictim(SPELL_BROOD_PLAGUE, false);
events.RepeatEvent(urand(12000, 17000));
break;
}
case EVENT_SWARMER:
{
SummonHelpers(true);
events.RepeatEvent(10000);
break;
}
case EVENT_CHECK_HOME:
{
if (!me->HasAura(SPELL_ENRAGE) && (me->GetPositionZ() < 24.0f || !me->GetHomePosition().IsInDist(me->GetPositionX(), me->GetPositionY(), me->GetPositionZ(), 110.0f)))
{
DoCastSelf(SPELL_ENRAGE, true);
}
break;
}
}
} }
DoMeleeAttackIfReady(); if (roll_chance_f(33))
{
Talk(SAY_EGG_SAC);
}
} }
else
private:
GuidList swarmEggs;
GuidList guardianEggs;
ObjectGuid previousSwarmEgg_GUID; // This will prevent casting summoning spells on same egg twice
bool guardianSummoned;
bool respectYourElders;
void SummonHelpers(bool swarm)
{ {
if (swarm) if (guardianEggs.empty())
{ {
if (swarmEggs.empty()) return;
{
return;
}
// Make a copy of guid list
GuidList swarmEggs2 = swarmEggs;
// Remove previous egg
if (previousSwarmEgg_GUID)
{
std::list<ObjectGuid>::iterator itr = std::find(swarmEggs2.begin(), swarmEggs2.end(), previousSwarmEgg_GUID);
if (itr != swarmEggs2.end())
{
swarmEggs2.erase(itr);
}
}
if (swarmEggs2.empty())
{
return;
}
previousSwarmEgg_GUID = Acore::Containers::SelectRandomContainerElement(swarmEggs2);
if (Creature* egg = ObjectAccessor::GetCreature(*me, previousSwarmEgg_GUID))
{
egg->CastSpell(egg, SPELL_SUMMON_SWARMERS, true, nullptr, nullptr, me->GetGUID());
}
if (roll_chance_f(33))
{
Talk(SAY_EGG_SAC);
}
} }
else
ObjectGuid const& guardianEggGUID = Acore::Containers::SelectRandomContainerElement(guardianEggs);
if (Creature* egg = ObjectAccessor::GetCreature(*me, guardianEggGUID))
{ {
if (guardianEggs.empty()) egg->CastSpell(egg, SPELL_SUMMON_SWARM_GUARD, true, nullptr, nullptr, me->GetGUID());
{ }
return;
}
ObjectGuid const& guardianEggGUID = Acore::Containers::SelectRandomContainerElement(guardianEggs); Talk(EMOTE_HATCHES, me);
if (Creature* egg = ObjectAccessor::GetCreature(*me, guardianEggGUID))
{
egg->CastSpell(egg, SPELL_SUMMON_SWARM_GUARD, true, nullptr, nullptr, me->GetGUID());
}
Talk(EMOTE_HATCHES, me); if (roll_chance_f(33))
{
if (roll_chance_f(33)) Talk(SAY_EGG_SAC);
{
Talk(SAY_EGG_SAC);
}
} }
} }
};
CreatureAI* GetAI(Creature* creature) const override
{
return GetAhnKahetAI<boss_elder_nadoxAI>(creature);
} }
}; };
class npc_ahnkahar_nerubian : public CreatureScript struct npc_ahnkahar_nerubian : public ScriptedAI
{ {
public: npc_ahnkahar_nerubian(Creature* c) : ScriptedAI(c) { }
npc_ahnkahar_nerubian() : CreatureScript("npc_ahnkahar_nerubian") { }
struct npc_ahnkahar_nerubianAI : public ScriptedAI void Reset() override
{ {
npc_ahnkahar_nerubianAI(Creature* c) : ScriptedAI(c) { } DoCastSelf(me->GetEntry() == NPC_AHNKAHAR_GUARDIAN ? SPELL_GUARDIAN_AURA : SPELL_SWARMER_AURA, true);
uiSprintTimer = 10000;
void Reset() override
{
DoCastSelf(me->GetEntry() == NPC_AHNKAHAR_GUARDIAN ? SPELL_GUARDIAN_AURA : SPELL_SWARMER_AURA, true);
uiSprintTimer = 10000;
}
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
return;
if (uiSprintTimer <= diff)
{
DoCastSelf(SPELL_SPRINT, false);
uiSprintTimer = 15000;
}
else
uiSprintTimer -= diff;
DoMeleeAttackIfReady();
}
private:
uint32 uiSprintTimer;
};
CreatureAI* GetAI(Creature* creature) const override
{
return GetAhnKahetAI<npc_ahnkahar_nerubianAI>(creature);
} }
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
return;
if (uiSprintTimer <= diff)
{
DoCastSelf(SPELL_SPRINT, false);
uiSprintTimer = 15000;
}
else
uiSprintTimer -= diff;
DoMeleeAttackIfReady();
}
private:
uint32 uiSprintTimer;
}; };
class spell_ahn_kahet_swarmer_aura : public SpellScriptLoader class spell_ahn_kahet_swarmer_aura : public SpellScript
{ {
public: PrepareSpellScript(spell_ahn_kahet_swarmer_aura)
spell_ahn_kahet_swarmer_aura() : SpellScriptLoader("spell_ahn_kahet_swarmer_aura") { }
class spell_ahn_kahet_swarmer_aura_SpellScript : public SpellScript void CountTargets(std::list<WorldObject*>& targets)
{ {
PrepareSpellScript(spell_ahn_kahet_swarmer_aura_SpellScript) _targetCount = static_cast<uint32>(targets.size());
}
void CountTargets(std::list<WorldObject*>& targets) void HandleDummy(SpellEffIndex /*effIndex*/)
{
Unit* caster = GetCaster();
if (_targetCount)
{ {
_targetCount = static_cast<uint32>(targets.size()); if (Aura *aur = caster->GetAura(SPELL_SWARM))
}
void HandleDummy(SpellEffIndex /*effIndex*/)
{
Unit* caster = GetCaster();
if (_targetCount)
{ {
aur->SetStackAmount(static_cast<uint8>(_targetCount));
}
else if (_targetCount)
{
// TODO: move spell id to enum
caster->CastCustomSpell(SPELL_SWARM, SPELLVALUE_AURA_STACK, _targetCount, caster, true);
if (Aura *aur = caster->GetAura(SPELL_SWARM)) if (Aura *aur = caster->GetAura(SPELL_SWARM))
{ {
aur->SetStackAmount(static_cast<uint8>(_targetCount)); aur->SetStackAmount(static_cast<uint8>(_targetCount));
} }
else if (_targetCount)
{
// TODO: move spell id to enum
caster->CastCustomSpell(SPELL_SWARM, SPELLVALUE_AURA_STACK, _targetCount, caster, true);
if (Aura *aur = caster->GetAura(SPELL_SWARM))
{
aur->SetStackAmount(static_cast<uint8>(_targetCount));
}
}
}
else
{
caster->RemoveAurasDueToSpell(SPELL_SWARM);
} }
} }
else
uint32 _targetCount;
void Register() override
{ {
OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_ahn_kahet_swarmer_aura_SpellScript::CountTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ALLY); caster->RemoveAurasDueToSpell(SPELL_SWARM);
OnEffectHitTarget += SpellEffectFn(spell_ahn_kahet_swarmer_aura_SpellScript::HandleDummy, EFFECT_0, SPELL_EFFECT_DUMMY);
} }
}; }
SpellScript* GetSpellScript() const override uint32 _targetCount;
void Register() override
{ {
return new spell_ahn_kahet_swarmer_aura_SpellScript(); OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_ahn_kahet_swarmer_aura::CountTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ALLY);
OnEffectHitTarget += SpellEffectFn(spell_ahn_kahet_swarmer_aura::HandleDummy, EFFECT_0, SPELL_EFFECT_DUMMY);
} }
}; };
@@ -417,11 +384,11 @@ class achievement_respect_your_elders : public AchievementCriteriaScript
void AddSC_boss_elder_nadox() void AddSC_boss_elder_nadox()
{ {
// Creatures // Creatures
new boss_elder_nadox(); RegisterAhnKahetCreatureAI(boss_elder_nadox);
new npc_ahnkahar_nerubian(); RegisterAhnKahetCreatureAI(npc_ahnkahar_nerubian);
// Spells // Spells
new spell_ahn_kahet_swarmer_aura(); RegisterSpellScript(spell_ahn_kahet_swarmer_aura);
// Achievements // Achievements
new achievement_respect_your_elders(); new achievement_respect_your_elders();
@@ -86,380 +86,357 @@ enum Events
const std::array<uint32, MAX_INSANITY_TARGETS> InsanitySpells = { SPELL_INSANITY_PHASING_1, SPELL_INSANITY_PHASING_2, SPELL_INSANITY_PHASING_3, SPELL_INSANITY_PHASING_4, SPELL_INSANITY_PHASING_5 }; const std::array<uint32, MAX_INSANITY_TARGETS> InsanitySpells = { SPELL_INSANITY_PHASING_1, SPELL_INSANITY_PHASING_2, SPELL_INSANITY_PHASING_3, SPELL_INSANITY_PHASING_4, SPELL_INSANITY_PHASING_5 };
class boss_volazj : public CreatureScript struct boss_volazj : public BossAI
{ {
public: boss_volazj(Creature* pCreature) : BossAI(pCreature, DATA_HERALD_VOLAZJ),
boss_volazj() : CreatureScript("boss_volazj") { } insanityTimes(0),
insanityPhase(false)
{ }
struct boss_volazjAI : public BossAI void InitializeAI() override
{ {
boss_volazjAI(Creature* pCreature) : BossAI(pCreature, DATA_HERALD_VOLAZJ), BossAI::InitializeAI();
insanityTimes(0), // Visible for all players in insanity
insanityPhase(false) me->SetPhaseMask((1 | 16 | 32 | 64 | 128 | 256), true);
}
void Reset() override
{
_Reset();
insanityTimes = 0;
insanityPhase = false;
me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
me->SetControlled(false, UNIT_STATE_STUNNED);
ResetPlayersPhaseMask();
instance->DoStopTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, ACHIEV_QUICK_DEMISE_START_EVENT);
}
void EnterCombat(Unit* /*who*/) override
{
_EnterCombat();
events.ScheduleEvent(EVENT_HERALD_MIND_FLAY, 8000);
events.ScheduleEvent(EVENT_HERALD_SHADOW, 5000);
events.ScheduleEvent(EVENT_HERALD_SHIVER, 15000);
Talk(SAY_AGGRO);
DoCastSelf(SPELL_WHISPER_AGGRO);
instance->DoStartTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, ACHIEV_QUICK_DEMISE_START_EVENT);
me->SetInCombatWithZone();
}
void JustDied(Unit* /*killer*/) override
{
_JustDied();
me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
me->SetControlled(false, UNIT_STATE_STUNNED);
ResetPlayersPhaseMask();
switch (urand(0, 1))
{ {
case 0:
{
Talk(SAY_DEATH_1);
DoCastSelf(SPELL_WHISPER_DEATH_1, true);
break;
}
case 1:
{
Talk(SAY_DEATH_2);
DoCastSelf(SPELL_WHISPER_DEATH_2, true);
break;
}
} }
}
void InitializeAI() override void KilledUnit(Unit* victim) override
{
if (victim->GetTypeId() == TYPEID_PLAYER)
{ {
BossAI::InitializeAI(); switch (urand(0, 2))
// Visible for all players in insanity
me->SetPhaseMask((1 | 16 | 32 | 64 | 128 | 256), true);
}
void Reset() override
{
_Reset();
insanityTimes = 0;
insanityPhase = false;
me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
me->SetControlled(false, UNIT_STATE_STUNNED);
ResetPlayersPhaseMask();
instance->DoStopTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, ACHIEV_QUICK_DEMISE_START_EVENT);
}
void EnterCombat(Unit* /*who*/) override
{
_EnterCombat();
events.ScheduleEvent(EVENT_HERALD_MIND_FLAY, 8000);
events.ScheduleEvent(EVENT_HERALD_SHADOW, 5000);
events.ScheduleEvent(EVENT_HERALD_SHIVER, 15000);
Talk(SAY_AGGRO);
DoCastSelf(SPELL_WHISPER_AGGRO);
instance->DoStartTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, ACHIEV_QUICK_DEMISE_START_EVENT);
me->SetInCombatWithZone();
}
void JustDied(Unit* /*killer*/) override
{
_JustDied();
me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
me->SetControlled(false, UNIT_STATE_STUNNED);
ResetPlayersPhaseMask();
switch (urand(0, 1))
{ {
case 0: case 0:
{ {
Talk(SAY_DEATH_1); Talk(SAY_SLAY_1);
DoCastSelf(SPELL_WHISPER_DEATH_1, true); DoCastSelf(SPELL_WHISPER_SLAY_1);
break; break;
} }
case 1: case 1:
{ {
Talk(SAY_DEATH_2); Talk(SAY_SLAY_2);
DoCastSelf(SPELL_WHISPER_DEATH_2, true); DoCastSelf(SPELL_WHISPER_SLAY_2);
break;
}
case 2:
{
Talk(SAY_SLAY_3);
DoCastSelf(SPELL_WHISPER_SLAY_3);
break; break;
} }
} }
} }
}
void KilledUnit(Unit* victim) override void SetData(uint32 type, uint32 value) override
{
if (type == DATA_SET_INSANITY_PHASE)
{ {
if (victim->GetTypeId() == TYPEID_PLAYER) insanityPhase = (value != 0);
{ }
switch (urand(0, 2)) }
{
case 0: void DamageTaken(Unit* /*attacker*/, uint32& damage, DamageEffectType /*damagetype*/, SpellSchoolMask /*damageSchoolMask*/) override
{ {
Talk(SAY_SLAY_1); // Do not perform insanity recast if boss is casting Insanity already
DoCastSelf(SPELL_WHISPER_SLAY_1); if (me->FindCurrentSpellBySpellId(SPELL_INSANITY))
break; {
} return;
case 1:
{
Talk(SAY_SLAY_2);
DoCastSelf(SPELL_WHISPER_SLAY_2);
break;
}
case 2:
{
Talk(SAY_SLAY_3);
DoCastSelf(SPELL_WHISPER_SLAY_3);
break;
}
}
}
} }
void SetData(uint32 type, uint32 value) override // First insanity
if (insanityTimes == 0 && me->HealthBelowPctDamaged(66, damage))
{ {
if (type == DATA_SET_INSANITY_PHASE) DoCastSelf(SPELL_INSANITY, false);
{ ++insanityTimes;
insanityPhase = (value != 0); }
} // Second insanity
else if (insanityTimes == 1 && me->HealthBelowPctDamaged(33, damage))
{
me->InterruptNonMeleeSpells(false);
DoCastSelf(SPELL_INSANITY, false);
++insanityTimes;
}
}
void UpdateAI(uint32 diff) override
{
//Return since we have no target
if (!UpdateVictim())
{
return;
} }
void DamageTaken(Unit* /*attacker*/, uint32& damage, DamageEffectType /*damagetype*/, SpellSchoolMask /*damageSchoolMask*/) override if (insanityPhase)
{ {
// Do not perform insanity recast if boss is casting Insanity already if (!CheckPhaseMinions())
if (me->FindCurrentSpellBySpellId(SPELL_INSANITY))
{ {
return; return;
} }
// First insanity insanityPhase = false;
if (insanityTimes == 0 && me->HealthBelowPctDamaged(66, damage)) me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
{ me->SetControlled(false, UNIT_STATE_STUNNED);
DoCastSelf(SPELL_INSANITY, false); me->RemoveAurasDueToSpell(INSANITY_VISUAL);
++insanityTimes;
}
// Second insanity
else if (insanityTimes == 1 && me->HealthBelowPctDamaged(33, damage))
{
me->InterruptNonMeleeSpells(false);
DoCastSelf(SPELL_INSANITY, false);
++insanityTimes;
}
} }
void UpdateAI(uint32 diff) override events.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING))
{ {
//Return since we have no target return;
if (!UpdateVictim()) }
{
return;
}
if (insanityPhase) while (uint32 const eventId = events.ExecuteEvent())
{
switch (eventId)
{ {
if (!CheckPhaseMinions()) case EVENT_HERALD_MIND_FLAY:
{ {
return; DoCastVictim(SPELL_MIND_FLAY, false);
events.RepeatEvent(20000);
break;
} }
case EVENT_HERALD_SHADOW:
{
DoCastVictim(SPELL_SHADOW_BOLT_VOLLEY, false);
events.RepeatEvent(5000);
break;
}
case EVENT_HERALD_SHIVER:
{
if (Unit* pTarget = SelectTarget(SELECT_TARGET_RANDOM, 0, 0.0f, true))
{
DoCast(pTarget, SPELL_SHIVER, false);
}
insanityPhase = false; events.RepeatEvent(15000);
me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); break;
me->SetControlled(false, UNIT_STATE_STUNNED); }
me->RemoveAurasDueToSpell(INSANITY_VISUAL);
} }
events.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING)) if (me->HasUnitState(UNIT_STATE_CASTING))
{ {
return; return;
} }
while (uint32 const eventId = events.ExecuteEvent())
{
switch (eventId)
{
case EVENT_HERALD_MIND_FLAY:
{
DoCastVictim(SPELL_MIND_FLAY, false);
events.RepeatEvent(20000);
break;
}
case EVENT_HERALD_SHADOW:
{
DoCastVictim(SPELL_SHADOW_BOLT_VOLLEY, false);
events.RepeatEvent(5000);
break;
}
case EVENT_HERALD_SHIVER:
{
if (Unit* pTarget = SelectTarget(SELECT_TARGET_RANDOM, 0, 0.0f, true))
{
DoCast(pTarget, SPELL_SHIVER, false);
}
events.RepeatEvent(15000);
break;
}
}
if (me->HasUnitState(UNIT_STATE_CASTING))
{
return;
}
}
DoMeleeAttackIfReady();
} }
private: DoMeleeAttackIfReady();
uint8 insanityTimes; }
bool insanityPhase; // Indicates if boss enter to insanity phase
uint32 GetPlrInsanityAuraId(uint32 phaseMask) const private:
{ uint8 insanityTimes;
switch (phaseMask) bool insanityPhase; // Indicates if boss enter to insanity phase
{
case 16:
return SPELL_INSANITY_PHASING_1;
case 32:
return SPELL_INSANITY_PHASING_2;
case 64:
return SPELL_INSANITY_PHASING_3;
case 128:
return SPELL_INSANITY_PHASING_4;
case 256:
return SPELL_INSANITY_PHASING_5;
}
return 0; uint32 GetPlrInsanityAuraId(uint32 phaseMask) const
}
void ResetPlayersPhaseMask()
{
Map::PlayerList const& players = me->GetMap()->GetPlayers();
for (auto const& i : players)
{
if (Player* pPlayer = i.GetSource())
{
if (uint32 const insanityAura = GetPlrInsanityAuraId(pPlayer->GetPhaseMask()))
{
pPlayer->RemoveAurasDueToSpell(insanityAura);
}
}
}
}
bool CheckPhaseMinions()
{
summons.RemoveNotExisting();
if (summons.empty())
{
ResetPlayersPhaseMask();
return true;
}
uint32 phase = 1;
for (ObjectGuid const& summonGUID : summons)
{
if (Creature* summon = ObjectAccessor::GetCreature(*me, summonGUID))
{
phase |= summon->GetPhaseMask();
}
}
Map::PlayerList const& players = me->GetMap()->GetPlayers();
for (auto const& i : players)
{
Player* pPlayer = i.GetSource();
if (pPlayer && !(pPlayer->GetPhaseMask() & phase))
{
pPlayer->RemoveAurasDueToSpell(GetPlrInsanityAuraId(pPlayer->GetPhaseMask()));
}
}
return false;
}
};
CreatureAI* GetAI(Creature* creature) const override
{ {
return GetAhnKahetAI<boss_volazjAI>(creature); switch (phaseMask)
{
case 16:
return SPELL_INSANITY_PHASING_1;
case 32:
return SPELL_INSANITY_PHASING_2;
case 64:
return SPELL_INSANITY_PHASING_3;
case 128:
return SPELL_INSANITY_PHASING_4;
case 256:
return SPELL_INSANITY_PHASING_5;
}
return 0;
}
void ResetPlayersPhaseMask()
{
Map::PlayerList const& players = me->GetMap()->GetPlayers();
for (auto const& i : players)
{
if (Player* pPlayer = i.GetSource())
{
if (uint32 const insanityAura = GetPlrInsanityAuraId(pPlayer->GetPhaseMask()))
{
pPlayer->RemoveAurasDueToSpell(insanityAura);
}
}
}
}
bool CheckPhaseMinions()
{
summons.RemoveNotExisting();
if (summons.empty())
{
ResetPlayersPhaseMask();
return true;
}
uint32 phase = 1;
for (ObjectGuid const& summonGUID : summons)
{
if (Creature* summon = ObjectAccessor::GetCreature(*me, summonGUID))
{
phase |= summon->GetPhaseMask();
}
}
Map::PlayerList const& players = me->GetMap()->GetPlayers();
for (auto const& i : players)
{
Player* pPlayer = i.GetSource();
if (pPlayer && !(pPlayer->GetPhaseMask() & phase))
{
pPlayer->RemoveAurasDueToSpell(GetPlrInsanityAuraId(pPlayer->GetPhaseMask()));
}
}
return false;
} }
}; };
// 57496 Insanity // 57496 Insanity
class spell_herald_volzaj_insanity : public SpellScriptLoader class spell_herald_volzaj_insanity : public SpellScript
{ {
public: PrepareSpellScript(spell_herald_volzaj_insanity);
spell_herald_volzaj_insanity() : SpellScriptLoader("spell_herald_volzaj_insanity") { }
class spell_herald_volzaj_insanity_SpellScript : public SpellScript bool Load() override { return GetCaster()->GetTypeId() == TYPEID_UNIT; }
void HandleDummyEffect(std::list<WorldObject*>& targets)
{ {
PrepareSpellScript(spell_herald_volzaj_insanity_SpellScript); Unit* caster = GetCaster();
if (!caster)
bool Load() override { return GetCaster()->GetTypeId() == TYPEID_UNIT; }
void HandleDummyEffect(std::list<WorldObject*>& targets)
{ {
Unit* caster = GetCaster(); targets.clear();
if (!caster) return;
}
if (!targets.empty())
{
targets.remove_if([this](WorldObject* targetObj) -> bool
{ {
targets.clear(); return !targetObj || targetObj->GetTypeId() != TYPEID_PLAYER || !targetObj->ToPlayer()->IsInCombatWith(GetCaster()) ||
return; targetObj->GetDistance(GetCaster()) >= (MAX_VISIBILITY_DISTANCE * 2);
});
}
if (targets.empty())
{
return;
}
// Start channel visual and set self as unnattackable
caster->ToCreature()->AI()->Talk(SAY_INSANITY);
caster->CastSpell(caster, SPELL_WHISPER_INSANITY, true);
caster->RemoveAllAuras();
caster->CastSpell(caster, INSANITY_VISUAL, true);
caster->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
caster->SetControlled(true, UNIT_STATE_STUNNED);
// Handle phase effect
uint32 insanityCounter = 0;
std::list<WorldObject*>::const_iterator itr = targets.begin();
while (itr != targets.end() && insanityCounter < MAX_INSANITY_TARGETS)
{
WorldObject* targetObj = *itr;
if (!targetObj)
{
continue;
} }
if (!targets.empty()) Player* plrTarget = targetObj->ToPlayer();
// This should never happen, spell has attribute SPELL_ATTR3_ONLY_TARGET_PLAYERS
if (!plrTarget)
{ {
targets.remove_if([this](WorldObject* targetObj) -> bool continue;
{
return !targetObj || targetObj->GetTypeId() != TYPEID_PLAYER || !targetObj->ToPlayer()->IsInCombatWith(GetCaster()) ||
targetObj->GetDistance(GetCaster()) >= (MAX_VISIBILITY_DISTANCE * 2);
});
} }
if (targets.empty()) // phase mask
{ plrTarget->CastSpell(plrTarget, InsanitySpells.at(insanityCounter), true);
return;
}
// Start channel visual and set self as unnattackable // Summon clone
caster->ToCreature()->AI()->Talk(SAY_INSANITY); for (std::list<WorldObject*>::const_iterator itr2 = targets.begin(); itr2 != targets.end(); ++itr2)
caster->CastSpell(caster, SPELL_WHISPER_INSANITY, true);
caster->RemoveAllAuras();
caster->CastSpell(caster, INSANITY_VISUAL, true);
caster->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
caster->SetControlled(true, UNIT_STATE_STUNNED);
// Handle phase effect
uint32 insanityCounter = 0;
std::list<WorldObject*>::const_iterator itr = targets.begin();
while (itr != targets.end() && insanityCounter < MAX_INSANITY_TARGETS)
{ {
WorldObject* targetObj = *itr; // Should not make clone of current player target
if (!targetObj) Player const* plrClone = *itr2 ? (*itr2)->ToPlayer() : nullptr;
if (!plrClone || plrClone == plrTarget)
{ {
continue; continue;
} }
Player* plrTarget = targetObj->ToPlayer(); if (Unit* summon = caster->SummonCreature(NPC_TWISTED_VISAGE, plrClone->GetPosition(), TEMPSUMMON_CORPSE_DESPAWN, 0))
// This should never happen, spell has attribute SPELL_ATTR3_ONLY_TARGET_PLAYERS
if (!plrTarget)
{ {
continue; summon->AddThreat(plrTarget, 0.0f);
summon->SetInCombatWith(plrTarget);
plrTarget->SetInCombatWith(summon);
plrTarget->CastSpell(summon, SPELL_CLONE_PLAYER, true);
summon->SetPhaseMask(1 | (1 << (4 + insanityCounter)), true);
summon->SetUInt32Value(UNIT_FIELD_MINDAMAGE, plrClone->GetUInt32Value(UNIT_FIELD_MINDAMAGE));
summon->SetUInt32Value(UNIT_FIELD_MAXDAMAGE, plrClone->GetUInt32Value(UNIT_FIELD_MAXDAMAGE));
} }
// phase mask
plrTarget->CastSpell(plrTarget, InsanitySpells.at(insanityCounter), true);
// Summon clone
for (std::list<WorldObject*>::const_iterator itr2 = targets.begin(); itr2 != targets.end(); ++itr2)
{
// Should not make clone of current player target
Player const* plrClone = *itr2 ? (*itr2)->ToPlayer() : nullptr;
if (!plrClone || plrClone == plrTarget)
{
continue;
}
if (Unit* summon = caster->SummonCreature(NPC_TWISTED_VISAGE, plrClone->GetPosition(), TEMPSUMMON_CORPSE_DESPAWN, 0))
{
summon->AddThreat(plrTarget, 0.0f);
summon->SetInCombatWith(plrTarget);
plrTarget->SetInCombatWith(summon);
plrTarget->CastSpell(summon, SPELL_CLONE_PLAYER, true);
summon->SetPhaseMask(1 | (1 << (4 + insanityCounter)), true);
summon->SetUInt32Value(UNIT_FIELD_MINDAMAGE, plrClone->GetUInt32Value(UNIT_FIELD_MINDAMAGE));
summon->SetUInt32Value(UNIT_FIELD_MAXDAMAGE, plrClone->GetUInt32Value(UNIT_FIELD_MAXDAMAGE));
}
}
++insanityCounter;
++itr;
} }
}
void HandleAfterCast() ++insanityCounter;
{ ++itr;
GetCaster()->ToCreature()->AI()->SetData(DATA_SET_INSANITY_PHASE, 1);
} }
}
void Register() override void HandleAfterCast()
{
OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_herald_volzaj_insanity_SpellScript::HandleDummyEffect, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY);
AfterCast += SpellCastFn(spell_herald_volzaj_insanity_SpellScript::HandleAfterCast);
}
};
SpellScript* GetSpellScript() const override
{ {
return new spell_herald_volzaj_insanity_SpellScript(); GetCaster()->ToCreature()->AI()->SetData(DATA_SET_INSANITY_PHASE, 1);
}
void Register() override
{
OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_herald_volzaj_insanity::HandleDummyEffect, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY);
AfterCast += SpellCastFn(spell_herald_volzaj_insanity::HandleAfterCast);
} }
}; };
@@ -470,70 +447,59 @@ public:
// 60295 Volazj Whisper: Slay 03 // 60295 Volazj Whisper: Slay 03
// 60296 Volazj Whisper: Death 01 // 60296 Volazj Whisper: Death 01
// 60297 Volazj Whisper: Death 02 // 60297 Volazj Whisper: Death 02
class spell_volazj_whisper : public SpellScriptLoader class spell_volazj_whisper : public SpellScript
{ {
public: PrepareSpellScript(spell_volazj_whisper);
spell_volazj_whisper() : SpellScriptLoader("spell_volazj_whisper") { }
class spell_volazj_whisper_SpellScript : public SpellScript bool Validate(SpellInfo const* /*spell*/) override
{ {
PrepareSpellScript(spell_volazj_whisper_SpellScript); return ValidateSpellInfo(
bool Validate(SpellInfo const* /*spell*/) override
{ {
return ValidateSpellInfo( SPELL_WHISPER_AGGRO,
{ SPELL_WHISPER_INSANITY,
SPELL_WHISPER_AGGRO, SPELL_WHISPER_SLAY_1,
SPELL_WHISPER_INSANITY, SPELL_WHISPER_SLAY_2,
SPELL_WHISPER_SLAY_1, SPELL_WHISPER_SLAY_3,
SPELL_WHISPER_SLAY_2, SPELL_WHISPER_DEATH_1,
SPELL_WHISPER_SLAY_3, SPELL_WHISPER_DEATH_2
SPELL_WHISPER_DEATH_1, });
SPELL_WHISPER_DEATH_2 }
});
}
bool Load() override { return GetCaster()->GetTypeId() == TYPEID_UNIT; } bool Load() override { return GetCaster()->GetTypeId() == TYPEID_UNIT; }
void HandleScriptEffect(SpellEffIndex /* effIndex */) void HandleScriptEffect(SpellEffIndex /* effIndex */)
{
Unit* target = GetHitPlayer();
Creature* caster = GetCaster()->ToCreature();
if (!target || !caster)
{
return;
}
uint32 text = 0;
switch (GetSpellInfo()->Id)
{
case SPELL_WHISPER_AGGRO: text = WHISPER_AGGRO; break;
case SPELL_WHISPER_INSANITY: text = WHISPER_INSANITY; break;
case SPELL_WHISPER_SLAY_1: text = WHISPER_SLAY_1; break;
case SPELL_WHISPER_SLAY_2: text = WHISPER_SLAY_2; break;
case SPELL_WHISPER_SLAY_3: text = WHISPER_SLAY_3; break;
case SPELL_WHISPER_DEATH_1: text = WHISPER_DEATH_1; break;
case SPELL_WHISPER_DEATH_2: text = WHISPER_DEATH_2; break;
default: return;
}
caster->AI()->Talk(text, target);
}
void Register() override
{
OnEffectHitTarget += SpellEffectFn(spell_volazj_whisper_SpellScript::HandleScriptEffect, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT);
}
};
SpellScript* GetSpellScript() const override
{ {
return new spell_volazj_whisper_SpellScript(); Unit* target = GetHitPlayer();
Creature* caster = GetCaster()->ToCreature();
if (!target || !caster)
{
return;
}
uint32 text = 0;
switch (GetSpellInfo()->Id)
{
case SPELL_WHISPER_AGGRO: text = WHISPER_AGGRO; break;
case SPELL_WHISPER_INSANITY: text = WHISPER_INSANITY; break;
case SPELL_WHISPER_SLAY_1: text = WHISPER_SLAY_1; break;
case SPELL_WHISPER_SLAY_2: text = WHISPER_SLAY_2; break;
case SPELL_WHISPER_SLAY_3: text = WHISPER_SLAY_3; break;
case SPELL_WHISPER_DEATH_1: text = WHISPER_DEATH_1; break;
case SPELL_WHISPER_DEATH_2: text = WHISPER_DEATH_2; break;
default: return;
}
caster->AI()->Talk(text, target);
}
void Register() override
{
OnEffectHitTarget += SpellEffectFn(spell_volazj_whisper::HandleScriptEffect, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT);
} }
}; };
void AddSC_boss_volazj() void AddSC_boss_volazj()
{ {
new boss_volazj(); RegisterAhnKahetCreatureAI(boss_volazj);
new spell_herald_volzaj_insanity(); RegisterSpellScript(spell_herald_volzaj_insanity);
new spell_volazj_whisper(); RegisterSpellScript(spell_volazj_whisper);
} }
File diff suppressed because it is too large Load Diff
@@ -93,438 +93,415 @@ constexpr float DATA_GROUND_POSITION_Z = 11.308135f;
constexpr float DATA_SPHERE_DISTANCE = 25.0f; constexpr float DATA_SPHERE_DISTANCE = 25.0f;
#define DATA_SPHERE_ANGLE_OFFSET float(M_PI) / 2.0f #define DATA_SPHERE_ANGLE_OFFSET float(M_PI) / 2.0f
class npc_taldaram_flamesphere : public CreatureScript struct npc_taldaram_flamesphere : public NullCreatureAI
{ {
public: npc_taldaram_flamesphere(Creature *pCreature) : NullCreatureAI(pCreature),
npc_taldaram_flamesphere() : CreatureScript("npc_taldaram_flamesphere") { } instance(pCreature->GetInstanceScript()),
uiDespawnTimer(13000),
struct npc_taldaram_flamesphereAI : public NullCreatureAI moveTimer(0)
{ {
npc_taldaram_flamesphereAI(Creature *pCreature) : NullCreatureAI(pCreature), pCreature->SetReactState(REACT_PASSIVE);
instance(pCreature->GetInstanceScript()), }
uiDespawnTimer(13000),
moveTimer(0) void DoAction(int32 action) override
{
if (action == ACTION_SPHERE)
{ {
pCreature->SetReactState(REACT_PASSIVE); moveTimer = 3000;
}
}
void MovementInform(uint32 type, uint32 id) override
{
if (type == POINT_MOTION_TYPE && id == POINT_ORB)
{
me->DisappearAndDie();
}
}
void IsSummonedBy(Unit* /*summoner*/) override
{
// Replace sphere instantly if sphere is summoned after prince death
if (instance->GetBossState(DATA_PRINCE_TALDARAM) != IN_PROGRESS)
{
me->DespawnOrUnsummon();
return;
} }
void DoAction(int32 action) override DoCastSelf(SPELL_FLAME_SPHERE_SPAWN_EFFECT);
DoCastSelf(SPELL_FLAME_SPHERE_VISUAL);
// TODO: replace with DespawnOrUnsummon
uiDespawnTimer = 13000;
}
void JustDied(Unit* /*who*/) override
{
DoCastSelf(SPELL_FLAME_SPHERE_DEATH_EFFECT);
}
void UpdateAI(uint32 diff) override
{
if (moveTimer)
{ {
if (action == ACTION_SPHERE) if (moveTimer <= diff)
{ {
moveTimer = 3000; DoCastSelf(SPELL_FLAME_SPHERE_PERIODIC);
float angleOffset = 0.0f;
switch (me->GetEntry())
{
case NPC_FLAME_SPHERE_1:
break;
case NPC_FLAME_SPHERE_2:
angleOffset = DATA_SPHERE_ANGLE_OFFSET;
break;
case NPC_FLAME_SPHERE_3:
angleOffset = -DATA_SPHERE_ANGLE_OFFSET;
break;
default:
return;
}
float angle = me->GetAngle(&victimPos) + angleOffset;
float x = me->GetPositionX() + DATA_SPHERE_DISTANCE * cos(angle);
float y = me->GetPositionY() + DATA_SPHERE_DISTANCE * sin(angle);
me->GetMotionMaster()->MovePoint(POINT_ORB, x, y, me->GetPositionZ());
moveTimer = 0;
}
else
{
moveTimer -= diff;
} }
} }
void MovementInform(uint32 type, uint32 id) override if (uiDespawnTimer)
{ {
if (type == POINT_MOTION_TYPE && id == POINT_ORB) if (uiDespawnTimer <= diff)
{ {
me->DisappearAndDie(); me->DisappearAndDie();
uiDespawnTimer = 0;
} }
else
uiDespawnTimer -= diff;
} }
void IsSummonedBy(Unit* /*summoner*/) override
{
// Replace sphere instantly if sphere is summoned after prince death
if (instance->GetBossState(DATA_PRINCE_TALDARAM) != IN_PROGRESS)
{
me->DespawnOrUnsummon();
return;
}
DoCastSelf(SPELL_FLAME_SPHERE_SPAWN_EFFECT);
DoCastSelf(SPELL_FLAME_SPHERE_VISUAL);
// TODO: replace with DespawnOrUnsummon
uiDespawnTimer = 13000;
}
void JustDied(Unit* /*who*/) override
{
DoCastSelf(SPELL_FLAME_SPHERE_DEATH_EFFECT);
}
void UpdateAI(uint32 diff) override
{
if (moveTimer)
{
if (moveTimer <= diff)
{
DoCastSelf(SPELL_FLAME_SPHERE_PERIODIC);
float angleOffset = 0.0f;
switch (me->GetEntry())
{
case NPC_FLAME_SPHERE_1:
break;
case NPC_FLAME_SPHERE_2:
angleOffset = DATA_SPHERE_ANGLE_OFFSET;
break;
case NPC_FLAME_SPHERE_3:
angleOffset = -DATA_SPHERE_ANGLE_OFFSET;
break;
default:
return;
}
float angle = me->GetAngle(&victimPos) + angleOffset;
float x = me->GetPositionX() + DATA_SPHERE_DISTANCE * cos(angle);
float y = me->GetPositionY() + DATA_SPHERE_DISTANCE * sin(angle);
me->GetMotionMaster()->MovePoint(POINT_ORB, x, y, me->GetPositionZ());
moveTimer = 0;
}
else
{
moveTimer -= diff;
}
}
if (uiDespawnTimer)
{
if (uiDespawnTimer <= diff)
{
me->DisappearAndDie();
uiDespawnTimer = 0;
}
else
uiDespawnTimer -= diff;
}
}
void SetVictimPos(Position const& pos)
{
victimPos.Relocate(pos);
}
private:
Position victimPos;
InstanceScript* instance;
uint32 uiDespawnTimer;
uint32 moveTimer;
};
CreatureAI *GetAI(Creature *creature) const override
{
return GetAhnKahetAI<npc_taldaram_flamesphereAI>(creature);
} }
void SetVictimPos(Position const& pos)
{
victimPos.Relocate(pos);
}
private:
Position victimPos;
InstanceScript* instance;
uint32 uiDespawnTimer;
uint32 moveTimer;
}; };
class boss_taldaram : public CreatureScript struct boss_taldaram : public BossAI
{ {
public: boss_taldaram(Creature* pCreature) : BossAI(pCreature, DATA_PRINCE_TALDARAM),
boss_taldaram() : CreatureScript("boss_taldaram") vanishDamage(0)
{ {
} }
struct boss_taldaramAI : public BossAI void InitializeAI() override
{ {
boss_taldaramAI(Creature* pCreature) : BossAI(pCreature, DATA_PRINCE_TALDARAM), BossAI::InitializeAI();
vanishDamage(0)
{
}
void InitializeAI() override // Event not started
if (instance->GetData(DATA_TELDRAM_SPHERE1) != DONE || instance->GetData(DATA_TELDRAM_SPHERE2) != DONE)
{ {
BossAI::InitializeAI(); me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC | UNIT_FLAG_IMMUNE_TO_NPC);
me->SetDisableGravity(true);
// Event not started me->SetHover(true);
if (instance->GetData(DATA_TELDRAM_SPHERE1) != DONE || instance->GetData(DATA_TELDRAM_SPHERE2) != DONE) if (!me->HasAura(SPELL_BEAM_VISUAL))
{ {
me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC | UNIT_FLAG_IMMUNE_TO_NPC); DoCastSelf(SPELL_BEAM_VISUAL, true);
me->SetDisableGravity(true);
me->SetHover(true);
if (!me->HasAura(SPELL_BEAM_VISUAL))
{
DoCastSelf(SPELL_BEAM_VISUAL, true);
}
me->SummonCreatureGroup(SUMMON_GROUP_TRIGGERS);
return;
} }
if (instance->GetData(DATA_TELDRAM_SPHERE1) == DONE && instance->GetData(DATA_TELDRAM_SPHERE2) == DONE) me->SummonCreatureGroup(SUMMON_GROUP_TRIGGERS);
return;
}
if (instance->GetData(DATA_TELDRAM_SPHERE1) == DONE && instance->GetData(DATA_TELDRAM_SPHERE2) == DONE)
{
DoAction(ACTION_REMOVE_PRISON_AT_RESET);
}
}
void Reset() override
{
_Reset();
vanishDamage = 0;
vanishTarget_GUID.Clear();
}
void DoAction(int32 action) override
{
if (action == ACTION_REMOVE_PRISON || action == ACTION_REMOVE_PRISON_AT_RESET)
{
me->SetHomePosition(me->GetPositionX(), me->GetPositionY(), DATA_GROUND_POSITION_Z, me->GetOrientation());
instance->HandleGameObject(instance->GetGuidData(DATA_PRINCE_TALDARAM_PLATFORM), true);
if (action == ACTION_REMOVE_PRISON)
{ {
DoAction(ACTION_REMOVE_PRISON_AT_RESET); DoCastSelf(SPELL_HOVER_FALL);
me->GetMotionMaster()->Clear();
me->GetMotionMaster()->MoveLand(POINT_LAND, me->GetHomePosition(), 8.0f);
Talk(SAY_REMOVE_PRISON);
} }
} // Teleport instantly
else
void Reset() override
{
_Reset();
vanishDamage = 0;
vanishTarget_GUID.Clear();
}
void DoAction(int32 action) override
{
if (action == ACTION_REMOVE_PRISON || action == ACTION_REMOVE_PRISON_AT_RESET)
{
me->SetHomePosition(me->GetPositionX(), me->GetPositionY(), DATA_GROUND_POSITION_Z, me->GetOrientation());
instance->HandleGameObject(instance->GetGuidData(DATA_PRINCE_TALDARAM_PLATFORM), true);
if (action == ACTION_REMOVE_PRISON)
{
DoCastSelf(SPELL_HOVER_FALL);
me->GetMotionMaster()->Clear();
me->GetMotionMaster()->MoveLand(POINT_LAND, me->GetHomePosition(), 8.0f);
Talk(SAY_REMOVE_PRISON);
}
// Teleport instantly
else
{
me->SetDisableGravity(false);
me->SetHover(false);
me->RemoveAllAuras();
me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_IMMUNE_TO_PC | UNIT_FLAG_IMMUNE_TO_NPC | UNIT_FLAG_NOT_SELECTABLE);
me->UpdatePosition(me->GetHomePosition(), true);
}
summons.DespawnEntry(NPC_JEDOGA_CONTROLLER);
}
}
void MovementInform(uint32 type, uint32 id) override
{
if (type == EFFECT_MOTION_TYPE && id == POINT_LAND)
{ {
me->SetDisableGravity(false); me->SetDisableGravity(false);
me->SetHover(false); me->SetHover(false);
me->RemoveAllAuras(); me->RemoveAllAuras();
me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_IMMUNE_TO_PC | UNIT_FLAG_IMMUNE_TO_NPC | UNIT_FLAG_NOT_SELECTABLE); me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_IMMUNE_TO_PC | UNIT_FLAG_IMMUNE_TO_NPC | UNIT_FLAG_NOT_SELECTABLE);
me->UpdatePosition(me->GetHomePosition(), true);
} }
summons.DespawnEntry(NPC_JEDOGA_CONTROLLER);
} }
}
void DamageTaken(Unit* /*attacker*/, uint32& damage, DamageEffectType /*damageType*/, SpellSchoolMask /*school*/) override void MovementInform(uint32 type, uint32 id) override
{
if (type == EFFECT_MOTION_TYPE && id == POINT_LAND)
{ {
if (vanishTarget_GUID) me->SetDisableGravity(false);
{ me->SetHover(false);
if (me->FindCurrentSpellBySpellId(SPELL_EMBRACE_OF_THE_VAMPYR))
{
vanishDamage += damage;
if (vanishDamage >= DUNGEON_MODE<uint32>(MAX_EMBRACE_DMG, MAX_EMBRACE_DMG_H))
{
ScheduleCombatEvents();
me->CastStop();
vanishTarget_GUID.Clear();
vanishDamage = 0;
}
}
}
}
void JustDied(Unit* /*killer*/) override
{
_JustDied();
Talk(SAY_DEATH);
}
void KilledUnit(Unit* victim) override
{
if (victim->GetTypeId() != TYPEID_PLAYER)
{
return;
}
Talk(SAY_SLAY);
if (vanishTarget_GUID && victim->GetGUID() == vanishTarget_GUID)
{
vanishTarget_GUID.Clear();
vanishDamage = 0;
}
}
void EnterCombat(Unit* /*who*/) override
{
_EnterCombat();
Talk(SAY_AGGRO);
ScheduleCombatEvents();
me->RemoveAllAuras(); me->RemoveAllAuras();
me->InterruptNonMeleeSpells(true); me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_IMMUNE_TO_PC | UNIT_FLAG_IMMUNE_TO_NPC | UNIT_FLAG_NOT_SELECTABLE);
} }
}
void SpellHitTarget(Unit* /*target*/, const SpellInfo *spellInfo) override void DamageTaken(Unit* /*attacker*/, uint32& damage, DamageEffectType /*damageType*/, SpellSchoolMask /*school*/) override
{
if (vanishTarget_GUID)
{ {
if (spellInfo->Id == SPELL_CONJURE_FLAME_SPHERE) if (me->FindCurrentSpellBySpellId(SPELL_EMBRACE_OF_THE_VAMPYR))
{ {
summons.DoAction(ACTION_SPHERE); vanishDamage += damage;
if (vanishDamage >= DUNGEON_MODE<uint32>(MAX_EMBRACE_DMG, MAX_EMBRACE_DMG_H))
{
ScheduleCombatEvents();
me->CastStop();
vanishTarget_GUID.Clear();
vanishDamage = 0;
}
} }
} }
}
void JustSummoned(Creature* summon) override void JustDied(Unit* /*killer*/) override
{
_JustDied();
Talk(SAY_DEATH);
}
void KilledUnit(Unit* victim) override
{
if (victim->GetTypeId() != TYPEID_PLAYER)
{ {
summons.Summon(summon); return;
switch (summon->GetEntry()) }
Talk(SAY_SLAY);
if (vanishTarget_GUID && victim->GetGUID() == vanishTarget_GUID)
{
vanishTarget_GUID.Clear();
vanishDamage = 0;
}
}
void EnterCombat(Unit* /*who*/) override
{
_EnterCombat();
Talk(SAY_AGGRO);
ScheduleCombatEvents();
me->RemoveAllAuras();
me->InterruptNonMeleeSpells(true);
}
void SpellHitTarget(Unit* /*target*/, const SpellInfo *spellInfo) override
{
if (spellInfo->Id == SPELL_CONJURE_FLAME_SPHERE)
{
summons.DoAction(ACTION_SPHERE);
}
}
void JustSummoned(Creature* summon) override
{
summons.Summon(summon);
switch (summon->GetEntry())
{
case NPC_FLAME_SPHERE_1:
case NPC_FLAME_SPHERE_2:
case NPC_FLAME_SPHERE_3:
{ {
case NPC_FLAME_SPHERE_1: if (npc_taldaram_flamesphere* summonAI = dynamic_cast<npc_taldaram_flamesphere*>(summon->AI()))
case NPC_FLAME_SPHERE_2:
case NPC_FLAME_SPHERE_3:
{ {
if (npc_taldaram_flamesphere::npc_taldaram_flamesphereAI* summonAI = dynamic_cast<npc_taldaram_flamesphere::npc_taldaram_flamesphereAI*>(summon->AI())) summonAI->SetVictimPos(victimSperePos);
}
break;
}
case NPC_JEDOGA_CONTROLLER:
{
summon->CastSpell(nullptr, SPELL_BEAM_VISUAL);
break;
}
}
}
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
{
return;
}
events.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING))
{
return;
}
while (uint32 const eventId = events.ExecuteEvent())
{
switch (eventId)
{
case EVENT_PRINCE_BLOODTHIRST:
{
DoCastSelf(SPELL_BLOODTHIRST);
events.RepeatEvent(10000);
break;
}
case EVENT_PRINCE_FLAME_SPHERES:
{
if (Unit* victim = me->GetVictim())
{ {
summonAI->SetVictimPos(victimSperePos); DoCast(victim, SPELL_CONJURE_FLAME_SPHERE);
victimSperePos = *victim;
} }
if (!events.GetNextEventTime(EVENT_PRINCE_VANISH))
{
events.RescheduleEvent(EVENT_PRINCE_VANISH, 14000);
}
else
{
// Make sure that Vanish won't get triggered at same time as sphere summon
events.DelayEvents(4000);
}
events.RepeatEvent(15000);
break; break;
} }
case NPC_JEDOGA_CONTROLLER: case EVENT_PRINCE_VANISH:
{ {
summon->CastSpell(nullptr, SPELL_BEAM_VISUAL); //Count alive players
uint8 count = 0;
std::list<HostileReference*> const t_list = me->getThreatMgr().getThreatList();
if (!t_list.empty())
{
for (HostileReference const* reference : t_list)
{
if (reference)
{
Unit const* pTarget = ObjectAccessor::GetUnit(*me, reference->getUnitGuid());
if (pTarget && pTarget->GetTypeId() == TYPEID_PLAYER && pTarget->IsAlive())
{
++count;
}
}
}
}
// He only vanishes if there are 3 or more alive players
if (count > 2)
{
Talk(SAY_VANISH);
DoCastSelf(SPELL_VANISH, false);
if (Unit* pEmbraceTarget = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true))
{
vanishTarget_GUID = pEmbraceTarget->GetGUID();
}
events.CancelEvent(EVENT_PRINCE_FLAME_SPHERES);
events.CancelEvent(EVENT_PRINCE_BLOODTHIRST);
events.ScheduleEvent(EVENT_PRINCE_VANISH_RUN, 2499);
}
break;
}
case EVENT_PRINCE_VANISH_RUN:
{
if (Unit* _vanishTarget = ObjectAccessor::GetUnit(*me, vanishTarget_GUID))
{
vanishDamage = 0;
DoCast(_vanishTarget, SPELL_SHADOWSTEP);
me->CastSpell(_vanishTarget, SPELL_EMBRACE_OF_THE_VAMPYR, false);
me->RemoveAura(SPELL_VANISH);
}
events.ScheduleEvent(EVENT_PRINCE_RESCHEDULE, 20000);
break;
}
case EVENT_PRINCE_RESCHEDULE:
{
ScheduleCombatEvents();
break; break;
} }
} }
}
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
{
return;
}
events.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING)) if (me->HasUnitState(UNIT_STATE_CASTING))
{ {
return; return;
} }
while (uint32 const eventId = events.ExecuteEvent())
{
switch (eventId)
{
case EVENT_PRINCE_BLOODTHIRST:
{
DoCastSelf(SPELL_BLOODTHIRST);
events.RepeatEvent(10000);
break;
}
case EVENT_PRINCE_FLAME_SPHERES:
{
if (Unit* victim = me->GetVictim())
{
DoCast(victim, SPELL_CONJURE_FLAME_SPHERE);
victimSperePos = *victim;
}
if (!events.GetNextEventTime(EVENT_PRINCE_VANISH))
{
events.RescheduleEvent(EVENT_PRINCE_VANISH, 14000);
}
else
{
// Make sure that Vanish won't get triggered at same time as sphere summon
events.DelayEvents(4000);
}
events.RepeatEvent(15000);
break;
}
case EVENT_PRINCE_VANISH:
{
//Count alive players
uint8 count = 0;
std::list<HostileReference*> const t_list = me->getThreatMgr().getThreatList();
if (!t_list.empty())
{
for (HostileReference const* reference : t_list)
{
if (reference)
{
Unit const* pTarget = ObjectAccessor::GetUnit(*me, reference->getUnitGuid());
if (pTarget && pTarget->GetTypeId() == TYPEID_PLAYER && pTarget->IsAlive())
{
++count;
}
}
}
}
// He only vanishes if there are 3 or more alive players
if (count > 2)
{
Talk(SAY_VANISH);
DoCastSelf(SPELL_VANISH, false);
if (Unit* pEmbraceTarget = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true))
{
vanishTarget_GUID = pEmbraceTarget->GetGUID();
}
events.CancelEvent(EVENT_PRINCE_FLAME_SPHERES);
events.CancelEvent(EVENT_PRINCE_BLOODTHIRST);
events.ScheduleEvent(EVENT_PRINCE_VANISH_RUN, 2499);
}
break;
}
case EVENT_PRINCE_VANISH_RUN:
{
if (Unit* _vanishTarget = ObjectAccessor::GetUnit(*me, vanishTarget_GUID))
{
vanishDamage = 0;
DoCast(_vanishTarget, SPELL_SHADOWSTEP);
me->CastSpell(_vanishTarget, SPELL_EMBRACE_OF_THE_VAMPYR, false);
me->RemoveAura(SPELL_VANISH);
}
events.ScheduleEvent(EVENT_PRINCE_RESCHEDULE, 20000);
break;
}
case EVENT_PRINCE_RESCHEDULE:
{
ScheduleCombatEvents();
break;
}
}
if (me->HasUnitState(UNIT_STATE_CASTING))
{
return;
}
}
if (me->IsVisible())
{
DoMeleeAttackIfReady();
}
} }
private: if (me->IsVisible())
Position victimSperePos;
ObjectGuid vanishTarget_GUID;
uint32 vanishDamage;
void ScheduleCombatEvents()
{ {
events.Reset(); DoMeleeAttackIfReady();
events.RescheduleEvent(EVENT_PRINCE_FLAME_SPHERES, 10000);
events.RescheduleEvent(EVENT_PRINCE_BLOODTHIRST, 10000);
vanishTarget_GUID.Clear();
vanishDamage = 0;
} }
}; }
CreatureAI* GetAI(Creature* creature) const override private:
Position victimSperePos;
ObjectGuid vanishTarget_GUID;
uint32 vanishDamage;
void ScheduleCombatEvents()
{ {
return GetAhnKahetAI<boss_taldaramAI>(creature); events.Reset();
events.RescheduleEvent(EVENT_PRINCE_FLAME_SPHERES, 10000);
events.RescheduleEvent(EVENT_PRINCE_BLOODTHIRST, 10000);
vanishTarget_GUID.Clear();
vanishDamage = 0;
} }
}; };
// TODO: Turn into new script type when Gossips have been updated
class go_prince_taldaram_sphere : public GameObjectScript class go_prince_taldaram_sphere : public GameObjectScript
{ {
public: public:
go_prince_taldaram_sphere() : GameObjectScript("go_prince_taldaram_sphere") { } go_prince_taldaram_sphere() : GameObjectScript("go_prince_taldaram_sphere") {}
bool OnGossipHello(Player* pPlayer, GameObject *go) override bool OnGossipHello(Player* pPlayer, GameObject* go) override
{ {
if (pPlayer && pPlayer->IsInCombat()) if (pPlayer && pPlayer->IsInCombat())
{ {
return true; return true;
} }
InstanceScript *pInstance = go->GetInstanceScript(); InstanceScript* pInstance = go->GetInstanceScript();
if (!pInstance) if (!pInstance)
{ {
return true; return true;
@@ -550,83 +527,61 @@ public:
}; };
// 55931 - Conjure Flame Sphere // 55931 - Conjure Flame Sphere
class spell_prince_taldaram_conjure_flame_sphere : public SpellScriptLoader class spell_prince_taldaram_conjure_flame_sphere : public SpellScript
{ {
public: PrepareSpellScript(spell_prince_taldaram_conjure_flame_sphere);
spell_prince_taldaram_conjure_flame_sphere() : SpellScriptLoader("spell_prince_taldaram_conjure_flame_sphere") { }
class spell_prince_taldaram_conjure_flame_sphere_SpellScript : public SpellScript bool Validate(SpellInfo const* /*spellInfo*/) override
{ {
PrepareSpellScript(spell_prince_taldaram_conjure_flame_sphere_SpellScript); return ValidateSpellInfo({SPELL_FLAME_SPHERE_SUMMON_1, SPELL_FLAME_SPHERE_SUMMON_2, SPELL_FLAME_SPHERE_SUMMON_3});
}
bool Validate(SpellInfo const* /*spellInfo*/) override void HandleScript(SpellEffIndex /*effIndex*/)
{
return ValidateSpellInfo({SPELL_FLAME_SPHERE_SUMMON_1, SPELL_FLAME_SPHERE_SUMMON_2, SPELL_FLAME_SPHERE_SUMMON_3});
}
void HandleScript(SpellEffIndex /*effIndex*/)
{
Unit* caster = GetCaster();
if (!caster || caster->isDead())
{
return;
}
caster->CastSpell(caster, SPELL_FLAME_SPHERE_SUMMON_1, false, nullptr, nullptr, caster->GetGUID());
if (caster->GetMap()->IsHeroic())
{
caster->CastSpell(caster, SPELL_FLAME_SPHERE_SUMMON_2, false, nullptr, nullptr, caster->GetGUID());
caster->CastSpell(caster, SPELL_FLAME_SPHERE_SUMMON_3, false, nullptr, nullptr, caster->GetGUID());
}
}
void Register() override
{
OnEffectHitTarget += SpellEffectFn(spell_prince_taldaram_conjure_flame_sphere_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_DUMMY);
}
};
SpellScript* GetSpellScript() const override
{ {
return new spell_prince_taldaram_conjure_flame_sphere_SpellScript(); Unit* caster = GetCaster();
if (!caster || caster->isDead())
{
return;
}
caster->CastSpell(caster, SPELL_FLAME_SPHERE_SUMMON_1, false, nullptr, nullptr, caster->GetGUID());
if (caster->GetMap()->IsHeroic())
{
caster->CastSpell(caster, SPELL_FLAME_SPHERE_SUMMON_2, false, nullptr, nullptr, caster->GetGUID());
caster->CastSpell(caster, SPELL_FLAME_SPHERE_SUMMON_3, false, nullptr, nullptr, caster->GetGUID());
}
}
void Register() override
{
OnEffectHitTarget += SpellEffectFn(spell_prince_taldaram_conjure_flame_sphere::HandleScript, EFFECT_0, SPELL_EFFECT_DUMMY);
} }
}; };
// 55895, 59511, 59512 - Flame Sphere Summon // 55895, 59511, 59512 - Flame Sphere Summon
class spell_prince_taldaram_flame_sphere_summon : public SpellScriptLoader class spell_prince_taldaram_flame_sphere_summon : public SpellScript
{ {
public: PrepareSpellScript(spell_prince_taldaram_flame_sphere_summon);
spell_prince_taldaram_flame_sphere_summon() : SpellScriptLoader("spell_prince_taldaram_flame_sphere_summon") { }
class spell_prince_taldaram_flame_sphere_summon_SpellScript : public SpellScript void SetDest(SpellDestination& dest)
{ {
PrepareSpellScript(spell_prince_taldaram_flame_sphere_summon_SpellScript); dest._position.m_positionZ = DATA_GROUND_POSITION_Z + 5.5f;
}
void SetDest(SpellDestination& dest) void Register() override
{ {
dest._position.m_positionZ = DATA_GROUND_POSITION_Z + 5.5f; OnDestinationTargetSelect += SpellDestinationTargetSelectFn(spell_prince_taldaram_flame_sphere_summon::SetDest, EFFECT_0, TARGET_DEST_CASTER);
} }
void Register() override
{
OnDestinationTargetSelect += SpellDestinationTargetSelectFn(spell_prince_taldaram_flame_sphere_summon_SpellScript::SetDest, EFFECT_0, TARGET_DEST_CASTER);
}
};
SpellScript* GetSpellScript() const override
{
return new spell_prince_taldaram_flame_sphere_summon_SpellScript();
}
}; };
void AddSC_boss_taldaram() void AddSC_boss_taldaram()
{ {
new npc_taldaram_flamesphere(); RegisterAhnKahetCreatureAI(npc_taldaram_flamesphere);
new boss_taldaram(); RegisterAhnKahetCreatureAI(boss_taldaram);
new go_prince_taldaram_sphere(); new go_prince_taldaram_sphere();
// Spells // Spells
new spell_prince_taldaram_conjure_flame_sphere(); RegisterSpellScript(spell_prince_taldaram_conjure_flame_sphere);
new spell_prince_taldaram_flame_sphere_summon(); RegisterSpellScript(spell_prince_taldaram_flame_sphere_summon);
} }
@@ -257,34 +257,23 @@ public:
// 56702 Shadow Sickle // 56702 Shadow Sickle
// 59103 Shadow Sickle // 59103 Shadow Sickle
class spell_shadow_sickle_periodic_damage : public SpellScriptLoader class spell_shadow_sickle_periodic_damage : public AuraScript
{ {
public: PrepareAuraScript(spell_shadow_sickle_periodic_damage);
spell_shadow_sickle_periodic_damage() : SpellScriptLoader("spell_shadow_sickle_periodic_damage") { }
class spell_shadow_sickle_periodic_damage_AuraScript : public AuraScript void HandlePeriodic(AuraEffect const* /*aurEff*/)
{ {
PrepareAuraScript(spell_shadow_sickle_periodic_damage_AuraScript); GetCaster()->CastSpell(nullptr, SPELL_SHADOW_SICKLE);
}
void HandlePeriodic(AuraEffect const* /*aurEff*/) void Register() override
{
GetCaster()->CastSpell(nullptr, SPELL_SHADOW_SICKLE);
}
void Register() override
{
OnEffectPeriodic += AuraEffectPeriodicFn(spell_shadow_sickle_periodic_damage_AuraScript::HandlePeriodic, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL);
}
};
AuraScript* GetAuraScript() const override
{ {
return new spell_shadow_sickle_periodic_damage_AuraScript(); OnEffectPeriodic += AuraEffectPeriodicFn(spell_shadow_sickle_periodic_damage::HandlePeriodic, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL);
} }
}; };
void AddSC_instance_ahnkahet() void AddSC_instance_ahnkahet()
{ {
new instance_ahnkahet; new instance_ahnkahet;
new spell_shadow_sickle_periodic_damage(); RegisterSpellScript(spell_shadow_sickle_periodic_damage);
} }