mirror of
https://github.com/mod-playerbots/azerothcore-wotlk.git
synced 2026-01-21 12:47:07 +00:00
fix(Scripts/DB): Ahn'kahet rewrite (#3449)
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user