fix(Scripts/DB): Ahn'kahet rewrite (#3449)

This commit is contained in:
Andrius Peleckas
2021-08-07 17:10:32 +03:00
committed by GitHub
parent 5b057798e7
commit a81a619758
9 changed files with 2427 additions and 1368 deletions

View File

@@ -1,50 +1,56 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license: https://github.com/azerothcore/azerothcore-wotlk/blob/master/LICENSE-AGPL3
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it and/or modify it under version 2 of the License, or (at your option), any later version.
* Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/>
*/
#ifndef DEF_AHNKAHET_H
#define DEF_AHNKAHET_H
#define MAX_ENCOUNTER 5
#include "CreatureAIImpl.h"
#define AhnahetScriptName "instance_ahnkahet"
enum Data64
constexpr uint32 MAX_ENCOUNTER = 5;
enum AhnkahetData
{
DATA_ELDER_NADOX,
DATA_PRINCE_TALDARAM,
DATA_JEDOGA_SHADOWSEEKER,
DATA_HERALD_VOLAZJ,
DATA_AMANITAR,
// Main encounters
DATA_ELDER_NADOX = 0,
DATA_PRINCE_TALDARAM = 1,
DATA_JEDOGA_SHADOWSEEKER = 2,
DATA_HERALD_VOLAZJ = 3,
DATA_AMANITAR = 4,
// Other data
// Teldram encounter related
DATA_PRINCE_TALDARAM_PLATFORM,
DATA_TELDRAM_SPHERE1,
DATA_TELDRAM_SPHERE2,
};
enum Data
{
DATA_ELDER_NADOX_EVENT,
DATA_PRINCE_TALDARAM_EVENT,
DATA_JEDOGA_SHADOWSEEKER_EVENT,
DATA_HERALD_VOLAZJ_EVENT,
DATA_AMANITAR_EVENT,
DATA_SPHERE_EVENT,
DATA_NADOX_ACHIEVEMENT,
DATA_JEDOGA_ACHIEVEMENT,
};
enum Npc
enum AhnKahetCreatures
{
NPC_ELDER_NADOX = 29309,
NPC_PRINCE_TALDARAM = 29308,
NPC_JEDOGA_SHADOWSEEKER = 29310,
NPC_HERALD_JOLAZJ = 29311,
NPC_AMANITAR = 30258,
// Teldaram and Jedoga encounter related
NPC_JEDOGA_CONTROLLER = 30181,
};
//spells
enum AhnkahetSpells
{
SPELL_SHADOW_SICKLE = 56701, // Shadow Sickle Normal
SPELL_SHADOW_SICKLE_H = 59104 // Shadow Sickle Heroic
};
enum AhnkahetObjects
{
GO_TELDARAM_DOOR = 192236,
GO_TELDARAM_SPHERE1 = 193093,
GO_TELDARAM_SPHERE2 = 193094,
GO_TELDARAM_PLATFORM = 193564,
};
enum AhnKahetActions
{
ACTION_REMOVE_PRISON = -1
};
template <class AI, class T>
@@ -53,4 +59,4 @@ inline AI* GetAhnkahetAI(T* obj)
return GetInstanceAI<AI>(obj, AhnahetScriptName);
}
#endif
#endif // DEF_AHNKAHET_H

View File

@@ -2,9 +2,11 @@
* Originally written by Xinef - Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license: https://github.com/azerothcore/azerothcore-wotlk/blob/master/LICENSE-AGPL3
*/
#include "ahnkahet.h"
#include "ScriptedCreature.h"
#include "ScriptMgr.h"
#include "ScriptedCreature.h"
#include "ahnkahet.h"
#include "Player.h"
#include "SpellScript.h"
enum Spells
{
@@ -12,10 +14,17 @@ enum Spells
SPELL_ENTANGLING_ROOTS = 57095,
SPELL_MINI = 57055,
SPELL_VENOM_BOLT_VOLLEY = 57088,
SPELL_REMOVE_MUSHROOM_POWER = 57283,
// Mushroom
SPELL_HEALTHY_MUSHROOM_POTENT_FUNGUS = 56648,
SPELL_POISONOUS_MUSHROOM_POISON_CLOUD = 57061,
SPELL_POISONOUS_MUSHROOM_VISUAL_AURA = 56741,
SPELL_POISONOUS_MUSHROOM_VISUAL_AREA = 61566, // Self
SPELL_HEALTHY_MUSHROOM_VISUAL_AURA = 56740,
SPELL_PUTRID_MUSHROOM = 31690,
SPELL_GROW = 57059,
SPELL_SHRINK = 31691,
};
enum Creatures
@@ -26,138 +35,192 @@ enum Creatures
enum Events
{
EVENT_AMANITAR_SPAWN = 1,
EVENT_AMANITAR_ROOTS = 2,
EVENT_AMANITAR_BASH = 3,
EVENT_AMANITAR_BOLT = 4,
EVENT_AMANITAR_MINI = 5
// Boss
EVENT_RESPAWN = 1,
EVENT_ROOTS,
EVENT_BASH,
EVENT_BOLT,
EVENT_REMOVE_MUSHROOM_POWER,
EVENT_MINI,
// Mushroom
EVENT_GROW,
EVENT_CHECK_PLAYER,
EVENT_KILLSELF,
};
constexpr uint8 MAX_MUSHROOMS_COUNT = 32;
Position const MushroomPositions[MAX_MUSHROOMS_COUNT] =
{
{ 373.4807f, -856.5301f, -74.30518f, 0.2094395f },
{ 358.4792f, -879.3193f, -75.9463f, 5.166174f },
{ 356.5531f, -846.3022f, -72.1796f, 3.193953f },
{ 332.369f, -846.081f, -74.30516f, 4.834562f },
{ 360.2234f, -862.055f, -75.22755f, 1.658063f },
{ 351.7189f, -890.9619f, -76.54617f, 1.064651f },
{ 345.8126f, -869.1772f, -77.17728f, 1.361357f },
{ 367.5179f, -884.0129f, -77.32881f, 4.276057f },
{ 370.6044f, -868.4305f, -74.19881f, 0.8901179f },
{ 381.3156f, -873.2377f, -74.82656f, 1.099557f },
{ 371.5869f, -873.8141f, -74.72424f, 1.082104f },
{ 340.4079f, -891.6375f, -74.99128f, 1.134464f },
{ 368.21f, -851.5953f, -73.99741f, 4.694936f },
{ 328.7047f, -853.9812f, -75.51253f, 0.5759587f },
{ 366.4145f, -876.39f, -75.52739f, 5.253441f },
{ 380.1362f, -861.4344f, -73.45917f, 3.787364f },
{ 373.3007f, -888.8057f, -79.03593f, 5.602507f },
{ 348.3599f, -848.0839f, -73.54117f, 1.745329f },
{ 352.5586f, -882.6624f, -75.68202f, 3.822271f },
{ 357.8967f, -871.179f, -75.77553f, 2.443461f },
{ 360.1034f, -842.3351f, -71.08852f, 4.34587f },
{ 348.1334f, -861.5244f, -74.61307f, 2.565634f },
{ 401.4896f, -866.7059f, -73.22395f, 0.8901179f },
{ 360.1683f, -889.1515f, -76.74798f, 3.612832f },
{ 350.1828f, -907.7313f, -74.94678f, 5.044002f },
{ 340.6278f, -856.5973f, -74.23862f, 4.415683f },
{ 366.4849f, -859.7621f, -74.82679f, 1.500983f },
{ 359.1482f, -853.3346f, -74.47543f, 5.654867f },
{ 374.9992f, -879.0921f, -75.56115f, 1.867502f },
{ 339.5252f, -850.4612f, -74.45442f, 4.764749f },
{ 337.0534f, -864.002f, -75.72749f, 4.642576f },
{ 398.2797f, -851.8694f, -68.84419f, 0.5759587f }
};
class boss_amanitar : public CreatureScript
{
public:
boss_amanitar() : CreatureScript("boss_amanitar") { }
struct boss_amanitarAI : public ScriptedAI
boss_amanitar() : CreatureScript("boss_amanitar")
{
boss_amanitarAI(Creature* c) : ScriptedAI(c), summons(me)
{
pInstance = c->GetInstanceScript();
}
}
InstanceScript* pInstance;
EventMap events;
SummonList summons;
struct boss_amanitarAI : public BossAI
{
boss_amanitarAI(Creature *creature) : BossAI(creature, DATA_AMANITAR), mushroomsSummoned(false)
{
creature->ApplySpellImmune(0, IMMUNITY_SCHOOL, SPELL_SCHOOL_MASK_NATURE, true);
creature->SetMeleeDamageSchool(SPELL_SCHOOL_NATURE);
}
void Reset() override
{
events.Reset();
summons.DespawnAll();
me->SetMeleeDamageSchool(SPELL_SCHOOL_NATURE);
_Reset();
_mushroomsDeque.clear();
mushroomsSummoned = false;
}
if (pInstance)
{
pInstance->SetData(DATA_AMANITAR_EVENT, NOT_STARTED);
pInstance->DoRemoveAurasDueToSpellOnPlayers(SPELL_MINI);
}
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
{
summons.DespawnAll();
if (pInstance)
_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)
{
pInstance->SetData(DATA_AMANITAR_EVENT, DONE);
pInstance->DoRemoveAurasDueToSpellOnPlayers(SPELL_MINI);
case EVENT_RESPAWN:
{
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;
}
}
}
void EnterCombat(Unit* /*who*/) override
private:
std::deque<Position> _mushroomsDeque;
bool mushroomsSummoned;
void SummonMushroom(Position const& pos)
{
if (pInstance)
pInstance->SetData(DATA_AMANITAR_EVENT, IN_PROGRESS);
events.ScheduleEvent(EVENT_AMANITAR_ROOTS, urand(5000, 9000));
events.ScheduleEvent(EVENT_AMANITAR_BASH, urand(10000, 14000));
events.ScheduleEvent(EVENT_AMANITAR_BOLT, urand(15000, 20000));
events.ScheduleEvent(EVENT_AMANITAR_MINI, 30000);
events.ScheduleEvent(EVENT_AMANITAR_SPAWN, 0);
}
void JustSummoned(Creature* cr) override { summons.Summon(cr); }
void SpawnAdds()
{
summons.DespawnAll();
Position center;
center.Relocate(362.6f, -870, -75);
for (uint8 i = 0; i < 25; ++i)
{
float orientation = 2 * rand_norm() * M_PI;
float x = center.GetPositionX() + i * 2 * cos(orientation);
float y = center.GetPositionY() + i * 2 * sin(orientation);
me->SummonCreature(NPC_POISONOUS_MUSHROOM, x, y, me->GetMap()->GetHeight(x, y, MAX_HEIGHT));
}
for (uint8 i = 0; i < 25; ++i)
{
float orientation = 2 * rand_norm() * M_PI;
float x = center.GetPositionX() + i * 2 * cos(orientation);
float y = center.GetPositionY() + i * 2 * sin(orientation);
me->SummonCreature(NPC_HEALTHY_MUSHROOM, x, y, me->GetMap()->GetHeight(x, y, MAX_HEIGHT));
}
}
void UpdateAI(uint32 diff) override
{
//Return since we have no target
if (!UpdateVictim())
return;
events.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
switch (events.ExecuteEvent())
{
case EVENT_AMANITAR_SPAWN:
{
SpawnAdds();
events.RepeatEvent(urand(35000, 40000));
break;
}
case EVENT_AMANITAR_ROOTS:
{
if (Unit* pTarget = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true))
me->CastSpell(pTarget, SPELL_ENTANGLING_ROOTS, false);
events.RepeatEvent(urand(15000, 20000));
break;
}
case EVENT_AMANITAR_BASH:
{
me->CastSpell(me->GetVictim(), SPELL_BASH, false);
events.RepeatEvent(urand(15000, 20000));
break;
}
case EVENT_AMANITAR_BOLT:
{
if (Unit* pTarget = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true))
me->CastSpell(pTarget, SPELL_VENOM_BOLT_VOLLEY, false);
events.RepeatEvent(urand(15000, 20000));
break;
}
case EVENT_AMANITAR_MINI:
{
me->CastSpell(me, SPELL_MINI, false);
events.RepeatEvent(30000);
break;
}
}
DoMeleeAttackIfReady();
me->SummonCreature(roll_chance_i(40) ? NPC_HEALTHY_MUSHROOM : NPC_POISONOUS_MUSHROOM, pos, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 4000);
}
};
@@ -174,61 +237,94 @@ public:
struct npc_amanitar_mushroomsAI : public ScriptedAI
{
npc_amanitar_mushroomsAI(Creature* c) : ScriptedAI(c)
npc_amanitar_mushroomsAI(Creature* pCreature) : ScriptedAI(pCreature)
{
SetCombatMovement(false);
me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE);
}
uint32 Timer;
void Reset() override
{
me->CastSpell(me, 31690, true);
Timer = 0;
if (me->GetEntry() == NPC_POISONOUS_MUSHROOM)
{
me->CastSpell(me, SPELL_POISONOUS_MUSHROOM_VISUAL_AURA, true);
me->CastSpell(me, SPELL_POISONOUS_MUSHROOM_POISON_CLOUD, false);
}
else
me->CastSpell(me, SPELL_HEALTHY_MUSHROOM_VISUAL_AURA, true);
}
void JustDied(Unit* killer) override
{
if (!killer)
return;
if (me->GetEntry() == NPC_HEALTHY_MUSHROOM)
{
if (killer->HasAura(SPELL_MINI))
{
killer->RemoveAurasDueToSpell(SPELL_MINI);
}
else
{
DoCast(killer, SPELL_HEALTHY_MUSHROOM_POTENT_FUNGUS);
}
}
//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 (me->GetEntry() == NPC_POISONOUS_MUSHROOM)
if (events.Empty())
return;
events.Update(diff);
while (uint32 const eventId = events.ExecuteEvent())
{
Timer += diff;
if (Timer >= 7000)
switch (eventId)
{
me->CastSpell(me, SPELL_POISONOUS_MUSHROOM_POISON_CLOUD, false);
Timer = 0;
case EVENT_GROW:
{
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
@@ -237,8 +333,41 @@ public:
}
};
// 57283 Remove Mushroom Power
class spell_amanitar_remove_mushroom_power : public SpellScriptLoader
{
public:
spell_amanitar_remove_mushroom_power() : SpellScriptLoader("spell_amanitar_remove_mushroom_power") { }
class spell_amanitar_remove_mushroom_power_AuraScript : public AuraScript
{
PrepareAuraScript(spell_amanitar_remove_mushroom_power_AuraScript);
void HandleApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
{
if (Unit* target = GetTarget())
{
target->RemoveAurasDueToSpell(SPELL_HEALTHY_MUSHROOM_POTENT_FUNGUS);
}
}
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();
}
};
void AddSC_boss_amanitar()
{
new boss_amanitar;
new npc_amanitar_mushrooms;
new boss_amanitar();
new npc_amanitar_mushrooms();
// Spells
new spell_amanitar_remove_mushroom_power();
}

View File

@@ -2,27 +2,28 @@
* Originally written by Xinef - Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license: https://github.com/azerothcore/azerothcore-wotlk/blob/master/LICENSE-AGPL3
*/
#include "ahnkahet.h"
#include "ScriptedCreature.h"
#include "ScriptMgr.h"
#include "ScriptedCreature.h"
#include "ahnkahet.h"
#include "SpellAuras.h"
#include "SpellScript.h"
#include "Containers.h"
enum Misc
{
// ACTIONS
ACTION_GUARDIAN_DIED = 1,
DATA_RESPECT_YOUR_ELDERS = 1,
};
enum Spells
{
// NADOX
SPELL_BROOD_PLAGUE = 56130,
SPELL_BROOD_PLAGUE_H = 59467,
SPELL_BROOD_RAGE_H = 59465,
SPELL_ENRAGE = 26662, // Enraged if too far away from home
//SPELL_SUMMON_SWARMERS = 56119, //2x 30178 -- 2x every 10secs, spell works fine but i need specific coords
//SPELL_SUMMON_SWARM_GUARD = 56120, //1x 30176 -- at 50%hp, spell works fine but i need specific coords
SPELL_BROOD_RAGE_H = 59465, // Only in heroic
SPELL_ENRAGE = 26662, // Enraged if too far away from home
SPELL_SUMMON_SWARMERS = 56119, // 2x NPC_AHNKAHAR_SWARMER
SPELL_SUMMON_SWARM_GUARD = 56120, // 1x NPC_AHNKAHAR_GUARDIAN_ENTRY -- at 50%hp
SPELL_SWARM = 56281,
// ADDS
SPELL_SPRINT = 56354,
@@ -33,26 +34,26 @@ enum Spells
enum Creatures
{
NPC_AHNKAHAR_SWARMER = 30178,
NPC_AHNKAHAR_GUARDIAN_ENTRY = 30176,
NPC_AHNKAHAR_GUARDIAN = 30176,
NPC_AHNKAHAR_SWARM_EGG = 30172,
NPC_AHNKAHAR_GUARDIAN_EGG = 30173,
};
enum Events
{
EVENT_CHECK_HEALTH = 1,
EVENT_CHECK_HOME = 2,
EVENT_PLAGUE = 3,
EVENT_BROOD_RAGE = 4,
EVENT_SWARMER = 5,
EVENT_SUMMON_GUARD = 6,
EVENT_CHECK_HOME = 1,
EVENT_PLAGUE,
EVENT_BROOD_RAGE,
EVENT_SWARMER,
};
enum Yells
{
SAY_AGGRO = 0,
SAY_SLAY = 1,
SAY_DEATH = 2,
SAY_EGG_SAC = 3,
EMOTE_HATCHES = 4
SAY_AGGRO = 0,
SAY_SLAY = 1,
SAY_DEATH = 2,
SAY_EGG_SAC = 3,
EMOTE_HATCHES = 4
};
class boss_elder_nadox : public CreatureScript
@@ -60,163 +61,231 @@ class boss_elder_nadox : public CreatureScript
public:
boss_elder_nadox() : CreatureScript("boss_elder_nadox") { }
struct boss_elder_nadoxAI : public ScriptedAI
struct boss_elder_nadoxAI : public BossAI
{
boss_elder_nadoxAI(Creature* c) : ScriptedAI(c), summons(me)
boss_elder_nadoxAI(Creature* creature) : BossAI(creature, DATA_PRINCE_TALDARAM),
guardianSummoned(false),
respectYourElders(true)
{
pInstance = c->GetInstanceScript();
}
EventMap events;
InstanceScript* pInstance;
SummonList summons;
void SummonHelpers(bool swarm)
{
Creature* cr;
if (swarm)
{
if ((cr = me->SummonCreature(NPC_AHNKAHAR_SWARMER, 640.425f, -919.544f, 25.8701f, 2.56563f)))
summons.Summon(cr);
if ((cr = me->SummonCreature(NPC_AHNKAHAR_SWARMER, 655.891f, -930.445f, 25.6978f, 3.64774f)))
summons.Summon(cr);
}
else
{
if ((cr = me->SummonCreature(NPC_AHNKAHAR_GUARDIAN_ENTRY, 658.677f, -934.332f, 25.6978f, 3.03687f)))
summons.Summon(cr);
}
}
void Reset() override
{
events.Reset();
summons.DespawnAll();
_Reset();
if (pInstance)
// 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())
{
pInstance->SetData(DATA_ELDER_NADOX_EVENT, NOT_STARTED);
pInstance->SetData(DATA_NADOX_ACHIEVEMENT, true);
events.ScheduleEvent(EVENT_BROOD_RAGE, 5000);
}
// 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());
}
}
}
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 EnterCombat(Unit* /*who*/) override
void SummonedCreatureDies(Creature* summon, Unit* /*killer*/) override
{
Talk(SAY_AGGRO);
events.ScheduleEvent(EVENT_CHECK_HEALTH, 1000);
events.ScheduleEvent(EVENT_SWARMER, 10000);
events.ScheduleEvent(EVENT_CHECK_HOME, 2000);
events.ScheduleEvent(EVENT_PLAGUE, 5000 + rand() % 3000);
events.ScheduleEvent(EVENT_BROOD_RAGE, 5000);
if (pInstance)
pInstance->SetData(DATA_ELDER_NADOX_EVENT, IN_PROGRESS);
}
void DoAction(int32 param) override
{
if (param == ACTION_GUARDIAN_DIED)
if (summon->GetEntry() == NPC_AHNKAHAR_GUARDIAN)
{
if (pInstance)
pInstance->SetData(DATA_NADOX_ACHIEVEMENT, false);
respectYourElders = false;
}
}
void KilledUnit(Unit* victim) override
{
if (victim->GetTypeId() == TYPEID_PLAYER)
{
Talk(SAY_SLAY);
}
}
void JustDied(Unit* /*killer*/) override
{
events.Reset();
summons.DespawnAll();
_JustDied();
Talk(SAY_DEATH);
if (pInstance)
pInstance->SetData(DATA_ELDER_NADOX_EVENT, DONE);
}
void JustSummoned(Creature* cr) override
void DamageTaken(Unit* /*attacker*/, uint32& damage, DamageEffectType /*damageType*/, SpellSchoolMask /*school*/) override
{
if (cr)
if (!guardianSummoned && me->HealthBelowPctDamaged(55, damage))
{
if (cr->GetEntry() == NPC_AHNKAHAR_GUARDIAN_ENTRY )
Talk(SAY_EGG_SAC);
summons.Summon(cr);
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;
switch ( events.ExecuteEvent() )
if (me->HasUnitState(UNIT_STATE_CASTING))
{
case EVENT_CHECK_HEALTH:
{
events.RepeatEvent(1000);
if (HealthBelowPct(50))
{
events.CancelEvent(EVENT_CHECK_HEALTH);
events.ScheduleEvent(EVENT_SUMMON_GUARD, 100);
}
break;
}
case EVENT_SUMMON_GUARD:
{
Talk(EMOTE_HATCHES, me);
SummonHelpers(false);
break;
}
case EVENT_BROOD_RAGE:
return;
}
while (uint32 const eventId = events.ExecuteEvent())
{
switch (eventId)
{
case EVENT_BROOD_RAGE:
{
if (Creature* pSwarmer = me->FindNearestCreature(NPC_AHNKAHAR_SWARMER, 40, true))
me->CastSpell(pSwarmer, SPELL_BROOD_RAGE_H, true);
DoCast(pSwarmer, SPELL_BROOD_RAGE_H, true);
events.RepeatEvent(10000);
break;
}
case EVENT_PLAGUE:
case EVENT_PLAGUE:
{
me->CastSpell(me->GetVictim(), DUNGEON_MODE(SPELL_BROOD_PLAGUE, SPELL_BROOD_PLAGUE_H), false);
events.RepeatEvent(12000 + rand() % 5000);
DoCastVictim(SPELL_BROOD_PLAGUE, false);
events.RepeatEvent(urand(12000, 17000));
break;
}
case EVENT_SWARMER:
case EVENT_SWARMER:
{
SummonHelpers(true);
events.RepeatEvent(10000);
break;
}
case EVENT_CHECK_HOME:
case EVENT_CHECK_HOME:
{
if (me->HasAura(SPELL_ENRAGE))
break;
if (me->GetPositionZ() < 24)
if (!me->HasAura(SPELL_ENRAGE) && (me->GetPositionZ() < 24.0f || !me->GetHomePosition().IsInDist(me->GetPositionX(), me->GetPositionY(), me->GetPositionZ(), 110.0f)))
{
me->CastSpell(me, SPELL_ENRAGE, true);
break;
DoCastSelf(SPELL_ENRAGE, true);
}
events.RepeatEvent(2000);
break;
}
}
}
DoMeleeAttackIfReady();
}
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 (swarmEggs.empty())
{
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
{
if (guardianEggs.empty())
{
return;
}
ObjectGuid const& guardianEggGUID = Acore::Containers::SelectRandomContainerElement(guardianEggs);
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))
{
Talk(SAY_EGG_SAC);
}
}
}
};
CreatureAI* GetAI(Creature* creature) const override
@@ -234,32 +303,12 @@ public:
{
npc_ahnkahar_nerubianAI(Creature* c) : ScriptedAI(c) { }
uint32 uiSprintTimer;
void Reset() override
{
if (me->GetEntry() == NPC_AHNKAHAR_GUARDIAN_ENTRY)
me->CastSpell(me, SPELL_GUARDIAN_AURA, true);
else // Swarmers
me->CastSpell(me, SPELL_SWARMER_AURA, true);
if (me->GetEntry() == NPC_AHNKAHAR_SWARMER || me->GetEntry() == NPC_AHNKAHAR_GUARDIAN_ENTRY)
me->SetInCombatWithZone();
DoCastSelf(me->GetEntry() == NPC_AHNKAHAR_GUARDIAN ? SPELL_GUARDIAN_AURA : SPELL_SWARMER_AURA, true);
uiSprintTimer = 10000;
}
void JustDied(Unit* /*killer*/) override
{
if (me->GetEntry() == NPC_AHNKAHAR_GUARDIAN_ENTRY)
{
if (InstanceScript* pInstance = me->GetInstanceScript())
if (Creature* nadox = ObjectAccessor::GetCreature(*me, pInstance->GetGuidData(DATA_ELDER_NADOX)))
nadox->AI()->DoAction(ACTION_GUARDIAN_DIED);
me->RemoveAllAuras();
}
}
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
@@ -267,7 +316,7 @@ public:
if (uiSprintTimer <= diff)
{
me->CastSpell(me, SPELL_SPRINT, false);
DoCastSelf(SPELL_SPRINT, false);
uiSprintTimer = 15000;
}
else
@@ -275,6 +324,9 @@ public:
DoMeleeAttackIfReady();
}
private:
uint32 uiSprintTimer;
};
CreatureAI* GetAI(Creature* creature) const override
@@ -292,39 +344,41 @@ public:
{
PrepareSpellScript(spell_ahn_kahet_swarmer_aura_SpellScript)
void CountTargets(std::list<WorldObject*>& targets)
{
_targetCount = static_cast<uint32>(targets.size());
}
void HandleDummy(SpellEffIndex /*effIndex*/)
{
Unit* caster = GetCaster();
std::list<Creature*> swarm, swarm2;
caster->GetCreaturesWithEntryInRange(swarm, 40.0f, 30338);
caster->GetCreaturesWithEntryInRange(swarm2, 40.0f, 30178);
int32 aliveCount = -1; // minus self
std::list<Creature*>::const_iterator itr;
for (itr = swarm.begin(); itr != swarm.end(); ++itr)
if ((*itr)->IsAlive())
aliveCount++;
for (itr = swarm2.begin(); itr != swarm2.end(); ++itr)
if ((*itr)->IsAlive())
aliveCount++;
if (Aura* aur = caster->GetAura(56281))
if (_targetCount)
{
if (aliveCount > 0)
aur->SetStackAmount(aliveCount);
else
aur->Remove();
if (Aura *aur = caster->GetAura(SPELL_SWARM))
{
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 if (aliveCount > 0)
else
{
caster->CastCustomSpell(caster, 56281, &aliveCount, &aliveCount, &aliveCount, true);
if (Aura* aur = caster->GetAura(56281))
aur->SetStackAmount(aliveCount);
caster->RemoveAurasDueToSpell(SPELL_SWARM);
}
}
uint32 _targetCount;
void Register() override
{
OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_ahn_kahet_swarmer_aura_SpellScript::CountTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ALLY);
OnEffectHitTarget += SpellEffectFn(spell_ahn_kahet_swarmer_aura_SpellScript::HandleDummy, EFFECT_0, SPELL_EFFECT_DUMMY);
}
};
@@ -335,9 +389,27 @@ public:
}
};
// 7317 - Respect Your Elders (2038)
class achievement_respect_your_elders : public AchievementCriteriaScript
{
public:
achievement_respect_your_elders() : AchievementCriteriaScript("achievement_respect_your_elders") { }
bool OnCheck(Player* /*player*/, Unit* target, uint32 /*criteria_id*/) override
{
return target && target->GetAI()->GetData(DATA_RESPECT_YOUR_ELDERS);
}
};
void AddSC_boss_elder_nadox()
{
// Creatures
new boss_elder_nadox();
new npc_ahnkahar_nerubian();
// Spells
new spell_ahn_kahet_swarmer_aura();
// Achievements
new achievement_respect_your_elders();
}

View File

@@ -2,21 +2,19 @@
* Originally written by Xinef - Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license: https://github.com/azerothcore/azerothcore-wotlk/blob/master/LICENSE-AGPL3
*/
#include "ScriptMgr.h"
#include "ScriptedCreature.h"
#include "ahnkahet.h"
#include "Player.h"
#include "ScriptedCreature.h"
#include "ScriptMgr.h"
#include "SpellInfo.h"
#include "SpellScript.h"
enum Spells
{
// BASIC FIGHT
SPELL_MIND_FLAY = 57941,
SPELL_MIND_FLAY_H = 59974,
SPELL_SHADOW_BOLT_VOLLEY = 57942,
SPELL_SHADOW_BOLT_VOLLEY_H = 59975,
SPELL_SHIVER = 57949,
SPELL_SHIVER_H = 59978,
// INSANITY
SPELL_INSANITY = 57496, //Dummy
@@ -27,169 +25,283 @@ enum Spells
SPELL_INSANITY_PHASING_2 = 57509,
SPELL_INSANITY_PHASING_3 = 57510,
SPELL_INSANITY_PHASING_4 = 57511,
SPELL_INSANITY_PHASING_5 = 57512
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
};
enum Yells
enum Texts
{
SAY_AGGRO = 0,
SAY_SLAY = 1,
SAY_DEATH = 2,
SAY_PHASE = 3
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 Misc
{
NPC_TWISTED_VISAGE = 30625,
ACHIEV_QUICK_DEMISE_START_EVENT = 20382,
MAX_INSANITY_TARGETS = 5,
DATA_SET_INSANITY_PHASE = 1,
};
enum Events
{
EVENT_HERALD_MIND_FLAY = 1,
EVENT_HERALD_SHADOW = 2,
EVENT_HERALD_SHIVER = 3,
EVENT_HERALD_HEALTH = 4,
EVENT_HERALD_SHADOW,
EVENT_HERALD_SHIVER,
};
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
{
public:
boss_volazj() : CreatureScript("boss_volazj") { }
struct boss_volazjAI : public ScriptedAI
struct boss_volazjAI : public BossAI
{
boss_volazjAI(Creature* pCreature) : ScriptedAI(pCreature), summons(me)
boss_volazjAI(Creature* pCreature) : BossAI(pCreature, DATA_HERALD_VOLAZJ),
insanityTimes(0),
insanityPhase(false)
{
pInstance = pCreature->GetInstanceScript();
}
InstanceScript* pInstance;
EventMap events;
SummonList summons;
uint8 insanityTimes;
uint8 insanityHandled;
void InitializeAI() override
{
BossAI::InitializeAI();
// Visible for all players in insanity
me->SetPhaseMask((1 | 16 | 32 | 64 | 128 | 256), true);
}
void Reset() override
{
events.Reset();
summons.DespawnAll();
insanityTimes = insanityHandled = 0;
_Reset();
insanityTimes = 0;
insanityPhase = false;
// Visible for all players in insanity
me->SetPhaseMask((1 | 16 | 32 | 64 | 128 | 256), true);
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();
if (pInstance)
switch (urand(0, 1))
{
pInstance->SetData(DATA_HERALD_VOLAZJ, NOT_STARTED);
pInstance->DoStopTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, ACHIEV_QUICK_DEMISE_START_EVENT);
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 SpellHitTarget(Unit* pTarget, const SpellInfo* spell) override
void KilledUnit(Unit* victim) override
{
if (spell->Id == SPELL_INSANITY)
if (victim->GetTypeId() == TYPEID_PLAYER)
{
// Not good target or too many players
if (pTarget->GetTypeId() != TYPEID_PLAYER || insanityHandled > 4)
return;
// First target - start channel visual and set self as unnattackable
if (!insanityHandled)
switch (urand(0, 2))
{
me->RemoveAllAuras();
me->CastSpell(me, INSANITY_VISUAL, true);
me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
me->SetControlled(true, UNIT_STATE_STUNNED);
case 0:
{
Talk(SAY_SLAY_1);
DoCastSelf(SPELL_WHISPER_SLAY_1);
break;
}
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
{
if (type == DATA_SET_INSANITY_PHASE)
{
insanityPhase = (value != 0);
}
}
void DamageTaken(Unit* /*attacker*/, uint32& damage, DamageEffectType /*damagetype*/, SpellSchoolMask /*damageSchoolMask*/) override
{
// Do not perform insanity recast if boss is casting Insanity already
if (me->FindCurrentSpellBySpellId(SPELL_INSANITY))
{
return;
}
// First insanity
if (insanityTimes == 0 && me->HealthBelowPctDamaged(66, damage))
{
DoCastSelf(SPELL_INSANITY, false);
++insanityTimes;
}
// 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;
}
if (insanityPhase)
{
if (!CheckPhaseMinions())
{
return;
}
// phase mask
pTarget->CastSpell(pTarget, SPELL_INSANITY_TARGET + insanityHandled, true);
insanityPhase = false;
me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
me->SetControlled(false, UNIT_STATE_STUNNED);
me->RemoveAurasDueToSpell(INSANITY_VISUAL);
}
// 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)
events.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING))
{
return;
}
while (uint32 const eventId = events.ExecuteEvent())
{
switch (eventId)
{
Player* plr = i->GetSource();
if (!plr || !plr->IsAlive() || pTarget->GetGUID() == plr->GetGUID())
continue;
// Summon clone
if (Unit* summon = me->SummonCreature(NPC_TWISTED_VISAGE, plr->GetPositionX(), plr->GetPositionY(), plr->GetPositionZ(), plr->GetOrientation(), TEMPSUMMON_CORPSE_DESPAWN, 0))
case EVENT_HERALD_MIND_FLAY:
{
summon->AddThreat(pTarget, 0.0f);
summon->SetInCombatWith(pTarget);
pTarget->SetInCombatWith(summon);
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);
}
plr->CastSpell(summon, SPELL_CLONE_PLAYER, true);
summon->SetPhaseMask(1 | (1 << (4 + insanityHandled)), true);
summon->SetUInt32Value(UNIT_FIELD_MINDAMAGE, plr->GetUInt32Value(UNIT_FIELD_MINDAMAGE));
summon->SetUInt32Value(UNIT_FIELD_MAXDAMAGE, plr->GetUInt32Value(UNIT_FIELD_MAXDAMAGE));
events.RepeatEvent(15000);
break;
}
}
++insanityHandled;
if (me->HasUnitState(UNIT_STATE_CASTING))
{
return;
}
}
DoMeleeAttackIfReady();
}
private:
uint8 insanityTimes;
bool insanityPhase; // Indicates if boss enter to insanity phase
uint32 GetPlrInsanityAuraId(uint32 phaseMask) const
{
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 (Map::PlayerList::const_iterator i = players.begin(); i != players.end(); ++i)
for (auto const& i : players)
{
if (Player* pPlayer = i->GetSource())
if (uint32 spellId = GetSpellForPhaseMask(pPlayer->GetPhaseMask()))
pPlayer->RemoveAurasDueToSpell(spellId);
if (Player* pPlayer = i.GetSource())
{
if (uint32 const insanityAura = GetPlrInsanityAuraId(pPlayer->GetPhaseMask()))
{
pPlayer->RemoveAurasDueToSpell(insanityAura);
}
}
}
}
void EnterCombat(Unit* /*who*/) override
{
events.ScheduleEvent(EVENT_HERALD_MIND_FLAY, 8000);
events.ScheduleEvent(EVENT_HERALD_SHADOW, 5000);
events.ScheduleEvent(EVENT_HERALD_SHIVER, 15000);
events.ScheduleEvent(EVENT_HERALD_HEALTH, 1000);
Talk(SAY_AGGRO);
if (pInstance)
{
pInstance->SetData(DATA_HERALD_VOLAZJ, IN_PROGRESS);
pInstance->DoStartTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, ACHIEV_QUICK_DEMISE_START_EVENT);
}
me->SetInCombatWithZone();
}
void JustSummoned(Creature* summon) override { summons.Summon(summon); }
uint32 GetSpellForPhaseMask(uint32 phase)
{
uint32 spell = 0;
switch (phase)
{
case 16:
spell = SPELL_INSANITY_PHASING_1;
break;
case 32:
spell = SPELL_INSANITY_PHASING_2;
break;
case 64:
spell = SPELL_INSANITY_PHASING_3;
break;
case 128:
spell = SPELL_INSANITY_PHASING_4;
break;
case 256:
spell = SPELL_INSANITY_PHASING_5;
break;
}
return spell;
}
bool CheckPhaseMinions()
{
summons.RemoveNotExisting();
@@ -199,105 +311,27 @@ public:
return true;
}
uint16 phase = 1;
for (ObjectGuid const& guid : summons)
uint32 phase = 1;
for (ObjectGuid const& summonGUID : summons)
{
if (Creature* summon = ObjectAccessor::GetCreature(*me, guid))
if (Creature* summon = ObjectAccessor::GetCreature(*me, summonGUID))
{
phase |= summon->GetPhaseMask();
}
}
Map::PlayerList const& players = me->GetMap()->GetPlayers();
for (Map::PlayerList::const_iterator i = players.begin(); i != players.end(); ++i)
for (auto const& i : players)
{
if (Player* pPlayer = i->GetSource())
if ((pPlayer->GetPhaseMask() & phase) == 0)
pPlayer->RemoveAurasDueToSpell(GetSpellForPhaseMask(pPlayer->GetPhaseMask()));
Player* pPlayer = i.GetSource();
if (pPlayer && !(pPlayer->GetPhaseMask() & phase))
{
pPlayer->RemoveAurasDueToSpell(GetPlrInsanityAuraId(pPlayer->GetPhaseMask()));
}
}
return false;
}
void UpdateAI(uint32 diff) override
{
//Return since we have no target
if (!UpdateVictim())
return;
if (insanityHandled)
{
if (!CheckPhaseMinions())
return;
insanityHandled = 0;
me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
me->SetControlled(false, UNIT_STATE_STUNNED);
me->RemoveAurasDueToSpell(INSANITY_VISUAL);
}
events.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
switch (events.ExecuteEvent())
{
case EVENT_HERALD_HEALTH:
{
if (insanityTimes == 0 && me->GetHealthPct() <= 66)
{
me->CastSpell(me, SPELL_INSANITY, false);
insanityTimes++;
}
else if (insanityTimes == 1 && me->GetHealthPct() <= 33)
{
me->CastSpell(me, SPELL_INSANITY, false);
insanityTimes++;
}
events.RepeatEvent(1000);
break;
}
case EVENT_HERALD_MIND_FLAY:
{
me->CastSpell(me->GetVictim(), IsHeroic() ? SPELL_MIND_FLAY_H : SPELL_MIND_FLAY, false);
events.RepeatEvent(20000);
break;
}
case EVENT_HERALD_SHADOW:
{
me->CastSpell(me->GetVictim(), IsHeroic() ? SPELL_SHADOW_BOLT_VOLLEY_H : SPELL_SHADOW_BOLT_VOLLEY, false);
events.RepeatEvent(5000);
break;
}
case EVENT_HERALD_SHIVER:
{
if (Unit* pTarget = SelectTarget(SELECT_TARGET_RANDOM, 0))
me->CastSpell(pTarget, IsHeroic() ? SPELL_SHIVER_H : SPELL_SHIVER, false);
events.RepeatEvent(15000);
break;
}
}
DoMeleeAttackIfReady();
}
void JustDied(Unit* /*killer*/) override
{
Talk(SAY_DEATH);
if (pInstance)
pInstance->SetData(DATA_HERALD_VOLAZJ, DONE);
me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
me->SetControlled(false, UNIT_STATE_STUNNED);
summons.DespawnAll();
ResetPlayersPhaseMask();
}
void KilledUnit(Unit* /*victim*/) override
{
Talk(SAY_SLAY);
}
};
CreatureAI* GetAI(Creature* creature) const override
@@ -306,7 +340,187 @@ public:
}
};
// 57496 Insanity
class spell_herald_volzaj_insanity : public SpellScriptLoader
{
public:
spell_herald_volzaj_insanity() : SpellScriptLoader("spell_herald_volzaj_insanity") { }
class spell_herald_volzaj_insanity_SpellScript : public SpellScript
{
PrepareSpellScript(spell_herald_volzaj_insanity_SpellScript);
bool Load() override { return GetCaster()->GetTypeId() == TYPEID_UNIT; }
void HandleDummyEffect(std::list<WorldObject*>& targets)
{
Unit* caster = GetCaster();
if (!caster)
{
targets.clear();
return;
}
if (!targets.empty())
{
targets.remove_if([this](WorldObject* targetObj) -> bool
{
return !targetObj || targetObj->GetTypeId() != TYPEID_PLAYER || !targetObj->ToPlayer()->IsInCombatWith(GetCaster()) ||
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;
}
Player* plrTarget = targetObj->ToPlayer();
// This should never happen, spell has attribute SPELL_ATTR3_ONLY_TARGET_PLAYERS
if (!plrTarget)
{
continue;
}
// 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()
{
GetCaster()->ToCreature()->AI()->SetData(DATA_SET_INSANITY_PHASE, 1);
}
void Register() override
{
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();
}
};
// 60291 Volazj Whisper: Aggro
// 60292 Volazj Whisper: Insanity
// 60293 Volazj Whisper: Slay 01
// 60294 Volazj Whisper: Slay 02
// 60295 Volazj Whisper: Slay 03
// 60296 Volazj Whisper: Death 01
// 60297 Volazj Whisper: Death 02
class spell_volazj_whisper : public SpellScriptLoader
{
public:
spell_volazj_whisper() : SpellScriptLoader("spell_volazj_whisper") { }
class spell_volazj_whisper_SpellScript : public SpellScript
{
PrepareSpellScript(spell_volazj_whisper_SpellScript);
bool Validate(SpellInfo const* /*spell*/) override
{
return ValidateSpellInfo(
{
SPELL_WHISPER_AGGRO,
SPELL_WHISPER_INSANITY,
SPELL_WHISPER_SLAY_1,
SPELL_WHISPER_SLAY_2,
SPELL_WHISPER_SLAY_3,
SPELL_WHISPER_DEATH_1,
SPELL_WHISPER_DEATH_2
});
}
bool Load() override { return GetCaster()->GetTypeId() == TYPEID_UNIT; }
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();
}
};
void AddSC_boss_volazj()
{
new boss_volazj();
new spell_herald_volzaj_insanity();
new spell_volazj_whisper();
}

View File

@@ -2,256 +2,494 @@
* Originally written by Xinef - Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license: https://github.com/azerothcore/azerothcore-wotlk/blob/master/LICENSE-AGPL3
*/
#include "ahnkahet.h"
#include "ScriptedCreature.h"
#include "ScriptMgr.h"
#include "ScriptedCreature.h"
#include "ahnkahet.h"
#include "SpellInfo.h"
#include "SpellScript.h"
#include "Player.h"
#include "PassiveAI.h"
enum Spells
{
SPELL_BLOODTHIRST = 55968, //Trigger Spell + add aura
SPELL_CONJURE_FLAME_SPHERE = 55931,
SPELL_FLAME_SPHERE_SPAWN_EFFECT = 55891,
SPELL_FLAME_SPHERE_SUMMON_1 = 55895, // 1x 30106
SPELL_FLAME_SPHERE_SUMMON_2 = 59511, // 1x 31686
SPELL_FLAME_SPHERE_SUMMON_3 = 59512, // 1x 31687
SPELL_FLAME_SPHERE_VISUAL = 55928,
SPELL_FLAME_SPHERE_PERIODIC = 55926,
SPELL_FLAME_SPHERE_PERIODIC_H = 59508,
SPELL_FLAME_SPHERE_DEATH_EFFECT = 55947,
SPELL_BEAM_VISUAL = 60342,
SPELL_EMBRACE_OF_THE_VAMPYR = 55959,
SPELL_EMBRACE_OF_THE_VAMPYR_H = 59513,
SPELL_VANISH = 55964,
CREATURE_FLAME_SPHERE = 30106,
CREATURE_FLAME_SPHERE_1 = 31686,
CREATURE_FLAME_SPHERE_2 = 31687,
SPELL_SHADOWSTEP = 55966,
SPELL_HOVER_FALL = 60425
};
#define SPELL_EMBRACE_OF_THE_VAMPYR DUNGEON_MODE(55959, 59513)
enum Spheres
{
NPC_FLAME_SPHERE_1 = 30106,
NPC_FLAME_SPHERE_2 = 31686,
NPC_FLAME_SPHERE_3 = 31687,
};
enum Misc
{
DATA_EMBRACE_DMG = 20000,
DATA_EMBRACE_DMG_H = 40000,
DATA_SPHERE_DISTANCE = 30,
ACTION_FREE = 1,
ACTION_SPHERE = 2,
MAX_EMBRACE_DMG = 20000,
MAX_EMBRACE_DMG_H = 40000,
SUMMON_GROUP_TRIGGERS = 0,
};
enum Actions
{
ACTION_REMOVE_PRISON_AT_RESET = 1,
ACTION_SPHERE,
};
enum Event
{
EVENT_PRINCE_FLAME_SPHERES = 1,
EVENT_PRINCE_VANISH = 2,
EVENT_PRINCE_BLOODTHIRST = 3,
EVENT_PRINCE_VANISH_RUN = 4,
EVENT_PRINCE_RESCHEDULE = 5,
EVENT_PRINCE_VANISH,
EVENT_PRINCE_BLOODTHIRST,
EVENT_PRINCE_VANISH_RUN,
EVENT_PRINCE_RESCHEDULE,
};
#define DATA_GROUND_POSITION_Z 11.4f
enum Yells
{
SAY_1 = 0,
SAY_WARNING = 1,
SAY_AGGRO = 2,
SAY_SLAY = 3,
SAY_DEATH = 4,
SAY_FEED = 5,
SAY_VANISH = 6,
SAY_SPHERE_ACTIVATED = 0,
SAY_REMOVE_PRISON = 1,
SAY_AGGRO = 2,
SAY_SLAY = 3,
SAY_DEATH = 4,
SAY_FEED = 5,
SAY_VANISH = 6,
};
enum Points
{
POINT_LAND = 1,
POINT_ORB,
};
constexpr float DATA_GROUND_POSITION_Z = 11.308135f;
constexpr float DATA_SPHERE_DISTANCE = 25.0f;
#define DATA_SPHERE_ANGLE_OFFSET float(M_PI) / 2.0f
class npc_taldaram_flamesphere : public CreatureScript
{
public:
npc_taldaram_flamesphere() : CreatureScript("npc_taldaram_flamesphere") { }
struct npc_taldaram_flamesphereAI : public NullCreatureAI
{
npc_taldaram_flamesphereAI(Creature *pCreature) : NullCreatureAI(pCreature),
instance(pCreature->GetInstanceScript()),
uiDespawnTimer(13000),
moveTimer(0)
{
pCreature->SetReactState(REACT_PASSIVE);
}
void DoAction(int32 action) override
{
if (action == ACTION_SPHERE)
{
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;
}
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);
}
};
class boss_taldaram : public CreatureScript
{
public:
boss_taldaram() : CreatureScript("boss_taldaram") { }
struct boss_taldaramAI : public ScriptedAI
boss_taldaram() : CreatureScript("boss_taldaram")
{
boss_taldaramAI(Creature* c) : ScriptedAI(c), summons(me)
}
struct boss_taldaramAI : public BossAI
{
boss_taldaramAI(Creature* pCreature) : BossAI(pCreature, DATA_PRINCE_TALDARAM),
vanishDamage(0)
{
pInstance = c->GetInstanceScript();
}
InstanceScript* pInstance;
EventMap events;
SummonList summons;
ObjectGuid vanishTarget;
uint32 vanishDamage;
void InitializeAI() override
{
BossAI::InitializeAI();
// Event not started
if (instance->GetData(DATA_TELDRAM_SPHERE1) != DONE || instance->GetData(DATA_TELDRAM_SPHERE2) != DONE)
{
me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC | UNIT_FLAG_IMMUNE_TO_NPC);
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)
{
DoAction(ACTION_REMOVE_PRISON_AT_RESET);
}
}
void Reset() override
{
if (me->GetPositionZ() > 15.0f)
me->CastSpell(me, SPELL_BEAM_VISUAL, true);
_Reset();
events.Reset();
summons.DespawnAll();
vanishDamage = 0;
vanishTarget.Clear();
if (pInstance)
{
pInstance->SetData(DATA_PRINCE_TALDARAM_EVENT, NOT_STARTED);
// Event not started
if (pInstance->GetData(DATA_SPHERE_EVENT) == DONE)
DoAction(ACTION_FREE);
}
vanishTarget_GUID.Clear();
}
void DoAction(int32 param) override
void DoAction(int32 action) override
{
if (param == ACTION_FREE)
if (action == ACTION_REMOVE_PRISON || action == ACTION_REMOVE_PRISON_AT_RESET)
{
me->RemoveAllAuras();
me->SetUnitMovementFlags(MOVEMENTFLAG_WALKING);
me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE);
me->SetHomePosition(me->GetPositionX(), me->GetPositionY(), DATA_GROUND_POSITION_Z, me->GetOrientation());
me->UpdatePosition(me->GetPositionX(), me->GetPositionY(), DATA_GROUND_POSITION_Z, me->GetOrientation(), true);
instance->HandleGameObject(instance->GetGuidData(DATA_PRINCE_TALDARAM_PLATFORM), true);
if (pInstance)
pInstance->HandleGameObject(pInstance->GetGuidData(DATA_PRINCE_TALDARAM_PLATFORM), true);
}
}
void EnterCombat(Unit* /*who*/) override
{
if (pInstance)
pInstance->SetData(DATA_PRINCE_TALDARAM_EVENT, IN_PROGRESS);
Talk(SAY_AGGRO);
ScheduleEvents();
me->RemoveAllAuras();
me->InterruptNonMeleeSpells(true);
}
void ScheduleEvents()
{
events.Reset();
events.ScheduleEvent(EVENT_PRINCE_FLAME_SPHERES, 10000);
events.ScheduleEvent(EVENT_PRINCE_BLOODTHIRST, 10000);
vanishTarget.Clear();
vanishDamage = 0;
}
void SpellHitTarget(Unit*, const SpellInfo* spellInfo) override
{
if (spellInfo->Id == SPELL_CONJURE_FLAME_SPHERE)
summons.DoAction(ACTION_SPHERE);
}
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
return;
events.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
switch (events.ExecuteEvent())
{
case EVENT_PRINCE_BLOODTHIRST:
{
me->CastSpell(me->GetVictim(), SPELL_BLOODTHIRST, false);
events.RepeatEvent(10000);
break;
}
case EVENT_PRINCE_FLAME_SPHERES:
{
me->CastSpell(me->GetVictim(), SPELL_CONJURE_FLAME_SPHERE, false);
events.RescheduleEvent(EVENT_PRINCE_VANISH, 14000);
Creature* cr;
if ((cr = me->SummonCreature(CREATURE_FLAME_SPHERE, me->GetPositionX(), me->GetPositionY(), me->GetPositionZ() + 5.0f, 0.0f, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 10 * IN_MILLISECONDS)))
summons.Summon(cr);
if (me->GetMap()->IsHeroic())
{
if ((cr = me->SummonCreature(CREATURE_FLAME_SPHERE_1, me->GetPositionX(), me->GetPositionY(), me->GetPositionZ() + 5.0f, 0.0f, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 10 * IN_MILLISECONDS)))
summons.Summon(cr);
if ((cr = me->SummonCreature(CREATURE_FLAME_SPHERE_2, me->GetPositionX(), me->GetPositionY(), me->GetPositionZ() + 5.0f, 0.0f, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 10 * IN_MILLISECONDS)))
summons.Summon(cr);
}
events.RepeatEvent(15000);
break;
}
case EVENT_PRINCE_VANISH:
{
//Count alive players
uint8 count = 0;
Unit* pTarget;
std::list<HostileReference*> t_list = me->getThreatManager().getThreatList();
for (std::list<HostileReference*>::const_iterator itr = t_list.begin(); itr != t_list.end(); ++itr)
{
pTarget = ObjectAccessor::GetUnit(*me, (*itr)->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);
me->CastSpell(me, SPELL_VANISH, false);
events.CancelEvent(EVENT_PRINCE_FLAME_SPHERES);
events.CancelEvent(EVENT_PRINCE_BLOODTHIRST);
events.ScheduleEvent(EVENT_PRINCE_VANISH_RUN, 2499);
if (Unit* pEmbraceTarget = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true))
vanishTarget = pEmbraceTarget->GetGUID();
}
break;
}
case EVENT_PRINCE_VANISH_RUN:
{
if (Unit* vT = ObjectAccessor::GetUnit(*me, vanishTarget))
{
me->UpdatePosition(vT->GetPositionX(), vT->GetPositionY(), vT->GetPositionZ(), me->GetAngle(vT), true);
me->CastSpell(vT, SPELL_EMBRACE_OF_THE_VAMPYR, false);
me->RemoveAura(SPELL_VANISH);
}
events.ScheduleEvent(EVENT_PRINCE_RESCHEDULE, 20000);
break;
}
case EVENT_PRINCE_RESCHEDULE:
{
ScheduleEvents();
break;
}
}
if (me->IsVisible())
DoMeleeAttackIfReady();
}
void DamageTaken(Unit*, uint32& damage, DamageEffectType, SpellSchoolMask) override
{
if (vanishTarget)
{
vanishDamage += damage;
if (vanishDamage > (uint32) DUNGEON_MODE(DATA_EMBRACE_DMG, DATA_EMBRACE_DMG_H))
if (action == ACTION_REMOVE_PRISON)
{
ScheduleEvents();
me->CastStop();
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->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);
}
}
void DamageTaken(Unit* /*attacker*/, uint32& damage, DamageEffectType /*damageType*/, SpellSchoolMask /*school*/) override
{
if (vanishTarget_GUID)
{
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
{
summons.DespawnAll();
_JustDied();
Talk(SAY_DEATH);
if (pInstance)
pInstance->SetData(DATA_PRINCE_TALDARAM_EVENT, DONE);
}
void KilledUnit(Unit* victim) override
{
if (urand(0, 1))
if (victim->GetTypeId() != TYPEID_PLAYER)
{
return;
if (vanishTarget && victim->GetGUID() == vanishTarget)
ScheduleEvents();
}
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:
{
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())
{
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->getThreatManager().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:
Position victimSperePos;
ObjectGuid vanishTarget_GUID;
uint32 vanishDamage;
void ScheduleCombatEvents()
{
events.Reset();
events.RescheduleEvent(EVENT_PRINCE_FLAME_SPHERES, 10000);
events.RescheduleEvent(EVENT_PRINCE_BLOODTHIRST, 10000);
vanishTarget_GUID.Clear();
vanishDamage = 0;
}
};
@@ -261,101 +499,121 @@ public:
}
};
class npc_taldaram_flamesphere : public CreatureScript
{
public:
npc_taldaram_flamesphere() : CreatureScript("npc_taldaram_flamesphere") { }
struct npc_taldaram_flamesphereAI : public ScriptedAI
{
npc_taldaram_flamesphereAI(Creature* c) : ScriptedAI(c)
{
}
uint32 uiDespawnTimer;
void DoAction(int32 param) override
{
if (param == ACTION_SPHERE)
{
me->CastSpell(me, me->GetMap()->IsHeroic() ? SPELL_FLAME_SPHERE_PERIODIC_H : SPELL_FLAME_SPHERE_PERIODIC, true);
float angle = rand_norm() * 2 * M_PI;
float x = me->GetPositionX() + static_cast<float>(DATA_SPHERE_DISTANCE) * cos(angle);
float y = me->GetPositionY() + static_cast<float>(DATA_SPHERE_DISTANCE) * sin(angle);
me->GetMotionMaster()->MovePoint(0, x, y, me->GetPositionZ());
}
}
void MovementInform(uint32 /*type*/, uint32 id) override
{
if (id == 0)
me->DisappearAndDie();
}
void Reset() override
{
me->CastSpell(me, SPELL_FLAME_SPHERE_SPAWN_EFFECT, true);
me->CastSpell(me, SPELL_FLAME_SPHERE_VISUAL, true);
uiDespawnTimer = 13 * IN_MILLISECONDS;
}
void EnterCombat(Unit* /*who*/) override {}
void MoveInLineOfSight(Unit* /*who*/) override {}
void JustDied(Unit* /*who*/) override
{
me->CastSpell(me, SPELL_FLAME_SPHERE_DEATH_EFFECT, true);
}
void UpdateAI(uint32 diff) override
{
if (uiDespawnTimer <= diff)
me->DisappearAndDie();
else
uiDespawnTimer -= diff;
}
};
CreatureAI* GetAI(Creature* creature) const override
{
return GetAhnkahetAI<npc_taldaram_flamesphereAI>(creature);
}
};
class go_prince_taldaram_sphere : public GameObjectScript
{
public:
go_prince_taldaram_sphere() : GameObjectScript("go_prince_taldaram_sphere") { }
bool OnGossipHello(Player* /*pPlayer*/, GameObject* go) override
bool OnGossipHello(Player* pPlayer, GameObject *go) override
{
InstanceScript* pInstance = go->GetInstanceScript();
if (!pInstance)
return false;
Creature* pPrinceTaldaram = ObjectAccessor::GetCreature(*go, pInstance->GetGuidData(DATA_PRINCE_TALDARAM));
if (pPrinceTaldaram && pPrinceTaldaram->IsAlive())
if (pPlayer && pPlayer->IsInCombat())
{
go->SetFlag(GAMEOBJECT_FLAGS, GO_FLAG_NOT_SELECTABLE);
go->SetGoState(GO_STATE_ACTIVE);
return true;
}
if (pInstance->GetData(DATA_SPHERE_EVENT) == NOT_STARTED)
InstanceScript *pInstance = go->GetInstanceScript();
if (!pInstance)
{
return true;
}
go->SetFlag(GAMEOBJECT_FLAGS, GO_FLAG_NOT_SELECTABLE);
go->SetGoState(GO_STATE_ACTIVE);
uint32 const objectIndex = go->GetEntry() == GO_TELDARAM_SPHERE1 ? DATA_TELDRAM_SPHERE1 : DATA_TELDRAM_SPHERE2;
if (pInstance->GetData(objectIndex) == NOT_STARTED)
{
Creature* taldaram = ObjectAccessor::GetCreature(*go, pInstance->GetGuidData(DATA_PRINCE_TALDARAM));
if (taldaram && taldaram->IsAlive())
{
pInstance->SetData(DATA_SPHERE_EVENT, DONE);
return true;
taldaram->AI()->Talk(SAY_SPHERE_ACTIVATED);
}
pPrinceTaldaram->AI()->DoAction(ACTION_FREE);
pInstance->SetData(objectIndex, DONE);
}
return true;
}
};
// 55931 - Conjure Flame Sphere
class spell_prince_taldaram_conjure_flame_sphere : public SpellScriptLoader
{
public:
spell_prince_taldaram_conjure_flame_sphere() : SpellScriptLoader("spell_prince_taldaram_conjure_flame_sphere") { }
class spell_prince_taldaram_conjure_flame_sphere_SpellScript : public SpellScript
{
PrepareSpellScript(spell_prince_taldaram_conjure_flame_sphere_SpellScript);
bool Validate(SpellInfo const* /*spellInfo*/) override
{
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();
}
};
// 55895, 59511, 59512 - Flame Sphere Summon
class spell_prince_taldaram_flame_sphere_summon : public SpellScriptLoader
{
public:
spell_prince_taldaram_flame_sphere_summon() : SpellScriptLoader("spell_prince_taldaram_flame_sphere_summon") { }
class spell_prince_taldaram_flame_sphere_summon_SpellScript : public SpellScript
{
PrepareSpellScript(spell_prince_taldaram_flame_sphere_summon_SpellScript);
void SetDest(SpellDestination& dest)
{
dest._position.m_positionZ = DATA_GROUND_POSITION_Z + 5.5f;
}
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()
{
new boss_taldaram();
new npc_taldaram_flamesphere();
new boss_taldaram();
new go_prince_taldaram_sphere();
// Spells
new spell_prince_taldaram_conjure_flame_sphere();
new spell_prince_taldaram_flame_sphere_summon();
}

View File

@@ -1,39 +0,0 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license: http://github.com/azerothcore/azerothcore-wotlk/LICENSE-GPL2
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef DEF_AHNKAHET_H
#define DEF_AHNKAHET_H
#define DATA_ELDER_NADOX 1
#define DATA_PRINCE_TALDARAM 2
#define DATA_JEDOGA_SHADOWSEEKER 3
#define DATA_HERALD_VOLAZJ 4
#define DATA_AMANITAR 5
#define DATA_ELDER_NADOX_EVENT 6
#define DATA_PRINCE_TALDARAM_EVENT 7
#define DATA_JEDOGA_SHADOWSEEKER_EVENT 8
#define DATA_HERALD_VOLAZJ_EVENT 9
#define DATA_AMANITAR_EVENT 10
#define DATA_SPHERE1 11
#define DATA_SPHERE2 12
#define DATA_SPHERE1_EVENT 13
#define DATA_SPHERE2_EVENT 14
#define DATA_PRINCE_TALDARAM_PLATFORM 15
#endif

View File

@@ -2,205 +2,173 @@
* Originally written by Xinef - Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license: https://github.com/azerothcore/azerothcore-wotlk/blob/master/LICENSE-AGPL3
*/
#include "ScriptMgr.h"
#include "ScriptedCreature.h"
#include "ahnkahet.h"
#include "Player.h"
#include "ScriptedCreature.h"
#include "ScriptMgr.h"
#include "SpellScript.h"
#include <array>
class instance_ahnkahet : public InstanceMapScript
{
public:
instance_ahnkahet() : InstanceMapScript("instance_ahnkahet", 619) { }
instance_ahnkahet() : InstanceMapScript(AhnahetScriptName, 619) { }
struct instance_ahnkahet_InstanceScript : public InstanceScript
{
instance_ahnkahet_InstanceScript(Map* pMap) : InstanceScript(pMap) {Initialize();};
ObjectGuid Elder_Nadox;
ObjectGuid Prince_Taldaram;
ObjectGuid Jedoga_Shadowseeker;
ObjectGuid Herald_Volazj;
ObjectGuid Amanitar;
ObjectGuid Prince_TaldaramPlatform;
ObjectGuid Prince_TaldaramGate;
uint32 m_auiEncounter[MAX_ENCOUNTER];
uint32 spheres;
bool nadoxAchievement;
bool jedogaAchievement;
void Initialize() override
instance_ahnkahet_InstanceScript(Map* pMap) : InstanceScript(pMap), canSaveBossStates(false)
{
memset(&m_auiEncounter, 0, sizeof(m_auiEncounter));
spheres = NOT_STARTED;
nadoxAchievement = false;
jedogaAchievement = false;
}
bool IsEncounterInProgress() const override
{
for (uint8 i = 0; i < MAX_ENCOUNTER; ++i)
if (m_auiEncounter[i] == IN_PROGRESS) return true;
return false;
SetBossNumber(MAX_ENCOUNTER);
teldaramSpheres.fill(NOT_STARTED);
}
void OnCreatureCreate(Creature* pCreature) override
{
switch(pCreature->GetEntry())
switch (pCreature->GetEntry())
{
case NPC_ELDER_NADOX:
Elder_Nadox = pCreature->GetGUID();
elderNadox_GUID = pCreature->GetGUID();
break;
case NPC_PRINCE_TALDARAM:
Prince_Taldaram = pCreature->GetGUID();
princeTaldaram_GUID = pCreature->GetGUID();
break;
case NPC_JEDOGA_SHADOWSEEKER:
Jedoga_Shadowseeker = pCreature->GetGUID();
jedogaShadowseeker_GUID = pCreature->GetGUID();
break;
case NPC_HERALD_JOLAZJ:
Herald_Volazj = pCreature->GetGUID();
heraldVolazj_GUID = pCreature->GetGUID();
break;
case NPC_AMANITAR:
Amanitar = pCreature->GetGUID();
amanitar_GUID = pCreature->GetGUID();
break;
}
}
void OnGameObjectCreate(GameObject* pGo) override
{
switch(pGo->GetEntry())
switch (pGo->GetEntry())
{
case 193564:
Prince_TaldaramPlatform = pGo->GetGUID();
if (m_auiEncounter[1] == DONE)
case GO_TELDARAM_PLATFORM:
{
taldaramPlatform_GUID = pGo->GetGUID();
if (IsAllSpheresActivated() || GetBossState(DATA_PRINCE_TALDARAM) == DONE)
{
HandleGameObject(ObjectGuid::Empty, true, pGo);
}
break;
case 193093:
if (spheres == DONE)
}
case GO_TELDARAM_SPHERE1:
case GO_TELDARAM_SPHERE2:
{
if (teldaramSpheres.at(pGo->GetEntry() == GO_TELDARAM_SPHERE1 ? 0 : 1) == DONE || GetBossState(DATA_PRINCE_TALDARAM) == DONE)
{
pGo->SetGoState(GO_STATE_ACTIVE);
pGo->SetFlag(GAMEOBJECT_FLAGS, GO_FLAG_NOT_SELECTABLE);
}
else
pGo->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_NOT_SELECTABLE);
break;
case 193094:
if (spheres == DONE)
{
pGo->SetGoState(GO_STATE_ACTIVE);
pGo->SetFlag(GAMEOBJECT_FLAGS, GO_FLAG_NOT_SELECTABLE);
}
else
pGo->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_NOT_SELECTABLE);
}
break;
case 192236:
Prince_TaldaramGate = pGo->GetGUID(); // Web gate past Prince Taldaram
if (m_auiEncounter[1] == DONE)
}
case GO_TELDARAM_DOOR:
{
taldaramGate_GUID = pGo->GetGUID(); // Web gate past Prince Taldaram
if (GetBossState(DATA_PRINCE_TALDARAM) == DONE)
{
HandleGameObject(ObjectGuid::Empty, true, pGo);
}
break;
}
}
}
ObjectGuid GetGuidData(uint32 identifier) const override
bool SetBossState(uint32 type, EncounterState state) override
{
switch(identifier)
if (!InstanceScript::SetBossState(type, state))
{
case DATA_ELDER_NADOX:
return Elder_Nadox;
case DATA_PRINCE_TALDARAM:
return Prince_Taldaram;
case DATA_JEDOGA_SHADOWSEEKER:
return Jedoga_Shadowseeker;
case DATA_HERALD_VOLAZJ:
return Herald_Volazj;
case DATA_AMANITAR:
return Amanitar;
case DATA_PRINCE_TALDARAM_PLATFORM:
return Prince_TaldaramPlatform;
return false;
}
return ObjectGuid::Empty;
}
bool CheckAchievementCriteriaMeet(uint32 criteria_id, Player const* /*source*/, Unit const* /*target*/, uint32 /*miscvalue1*/) override
{
switch(criteria_id)
if (type == DATA_PRINCE_TALDARAM && state == DONE)
{
case 7317: // Respect Your Elders (2038)
return nadoxAchievement;
case 7359: // Volunteer Work (2056)
return jedogaAchievement;
HandleGameObject(taldaramGate_GUID, true);
}
return false;
if (canSaveBossStates)
{
SaveToDB();
}
return true;
}
void SetData(uint32 type, uint32 data) override
{
switch(type)
if (type == DATA_TELDRAM_SPHERE1 || type == DATA_TELDRAM_SPHERE2)
{
case DATA_HERALD_VOLAZJ_EVENT:
case DATA_AMANITAR_EVENT:
case DATA_ELDER_NADOX_EVENT:
case DATA_JEDOGA_SHADOWSEEKER_EVENT:
m_auiEncounter[type] = data;
break;
case DATA_PRINCE_TALDARAM_EVENT:
if (data == DONE)
HandleGameObject(Prince_TaldaramGate, true);
m_auiEncounter[type] = data;
break;
case DATA_SPHERE_EVENT:
spheres = data;
break;
case DATA_NADOX_ACHIEVEMENT:
nadoxAchievement = (bool)data;
return;
case DATA_JEDOGA_ACHIEVEMENT:
jedogaAchievement = (bool)data;
return;
}
if (data == DONE)
teldaramSpheres[type == DATA_TELDRAM_SPHERE1 ? 0 : 1] = data;
SaveToDB();
if (IsAllSpheresActivated())
{
HandleGameObject(taldaramPlatform_GUID, true, nullptr);
Creature* teldaram = instance->GetCreature(princeTaldaram_GUID);
if (teldaram && teldaram->IsAlive())
{
teldaram->AI()->DoAction(ACTION_REMOVE_PRISON);
}
}
}
}
uint32 GetData(uint32 type) const override
{
switch(type)
switch (type)
{
case DATA_ELDER_NADOX_EVENT:
case DATA_PRINCE_TALDARAM_EVENT:
case DATA_JEDOGA_SHADOWSEEKER_EVENT:
case DATA_HERALD_VOLAZJ:
case DATA_AMANITAR_EVENT:
return m_auiEncounter[type];
case DATA_SPHERE_EVENT:
return spheres;
case DATA_TELDRAM_SPHERE1:
return teldaramSpheres.at(0);
case DATA_TELDRAM_SPHERE2:
return teldaramSpheres.at(1);
}
return 0;
}
ObjectGuid GetGuidData(uint32 type) const override
{
switch (type)
{
case DATA_ELDER_NADOX:
return elderNadox_GUID;
case DATA_PRINCE_TALDARAM:
return princeTaldaram_GUID;
case DATA_JEDOGA_SHADOWSEEKER:
return jedogaShadowseeker_GUID;
case DATA_HERALD_VOLAZJ:
return heraldVolazj_GUID;
case DATA_AMANITAR:
return amanitar_GUID;
}
return ObjectGuid::Empty;
}
std::string GetSaveData() override
{
OUT_SAVE_INST_DATA;
std::ostringstream saveStream;
saveStream << "A K " << m_auiEncounter[0] << ' ' << m_auiEncounter[1] << ' '
<< m_auiEncounter[2] << ' ' << m_auiEncounter[3] << ' ' << m_auiEncounter[4] << ' '
<< spheres;
// Encounter states
saveStream << "A K " << GetBossSaveData();
// Extra data
saveStream << teldaramSpheres[0] << ' ' << teldaramSpheres[1];
OUT_SAVE_INST_DATA_COMPLETE;
return saveStream.str();
@@ -217,29 +185,55 @@ public:
OUT_LOAD_INST_DATA(in);
char dataHead1, dataHead2;
uint32 data0, data1, data2, data3, data4, data5;
std::istringstream loadStream(in);
loadStream >> dataHead1 >> dataHead2 >> data0 >> data1 >> data2 >> data3 >> data4 >> data5;
loadStream >> dataHead1 >> dataHead2;
if (dataHead1 == 'A' && dataHead2 == 'K')
{
m_auiEncounter[0] = data0;
m_auiEncounter[1] = data1;
m_auiEncounter[2] = data2;
m_auiEncounter[3] = data3;
m_auiEncounter[4] = data4;
// Encounter states
for (uint8 i = 0; i < MAX_ENCOUNTER; ++i)
if (m_auiEncounter[i] == IN_PROGRESS)
m_auiEncounter[i] = NOT_STARTED;
{
uint32 tmpState;
loadStream >> tmpState;
if (tmpState == IN_PROGRESS || tmpState > SPECIAL)
{
tmpState = NOT_STARTED;
}
spheres = data5;
SetBossState(i, EncounterState(tmpState));
}
// Extra data
loadStream >> teldaramSpheres[0] >> teldaramSpheres[1];
}
else
{
OUT_LOAD_INST_DATA_FAIL;
return;
}
else OUT_LOAD_INST_DATA_FAIL;
canSaveBossStates = true;
OUT_LOAD_INST_DATA_COMPLETE;
}
private:
ObjectGuid elderNadox_GUID;
ObjectGuid princeTaldaram_GUID;
ObjectGuid jedogaShadowseeker_GUID;
ObjectGuid heraldVolazj_GUID;
ObjectGuid amanitar_GUID;
// Teldaram related
ObjectGuid taldaramPlatform_GUID;
ObjectGuid taldaramGate_GUID;
std::array<uint32, 2> teldaramSpheres; // Used to identify activation status for sphere activation
bool canSaveBossStates; // Indicates that it is safe to trigger SaveToDB call in SetBossState
bool IsAllSpheresActivated() const
{
return teldaramSpheres.at(0) == DONE && teldaramSpheres.at(1) == DONE;
}
};
InstanceScript* GetInstanceScript(InstanceMap* map) const override
@@ -248,6 +242,8 @@ public:
}
};
// 56702 Shadow Sickle
// 59103 Shadow Sickle
class spell_shadow_sickle_periodic_damage : public SpellScriptLoader
{
public:
@@ -259,22 +255,7 @@ public:
void HandlePeriodic(AuraEffect const* /*aurEff*/)
{
PreventDefaultAction();
if (Unit* caster = GetCaster())
{
std::list<Player*> PlayerList;
PlayerList.clear();
Map::PlayerList const& players = caster->GetMap()->GetPlayers();
for (Map::PlayerList::const_iterator itr = players.begin(); itr != players.end(); ++itr)
if (Player* player = itr->GetSource()->ToPlayer())
if (player->IsWithinDist(caster, 40.0f) && player->IsAlive()) // SPELL_SHADOW_SICKLE_H & SPELL_SHADOW_SICKLE range is 40 yards
PlayerList.push_back(player);
if (!PlayerList.empty())
caster->CastSpell(Acore::Containers::SelectRandomContainerElement(PlayerList), caster->GetMap()->IsHeroic() ? SPELL_SHADOW_SICKLE_H : SPELL_SHADOW_SICKLE, true);
}
GetCaster()->CastSpell(nullptr, SPELL_SHADOW_SICKLE);
}
void Register() override