fix(Scripts/BRD): Magmus, Emperor, Priestess, Arena improvements (#8102)

This commit is contained in:
patou01
2021-12-16 12:14:29 +01:00
committed by GitHub
parent 886ea162e8
commit 9b3b61139a
14 changed files with 1203 additions and 332 deletions

View File

@@ -23,16 +23,18 @@
#include "ScriptedGossip.h"
#include "WorldSession.h"
enum ShadowforgeBrazier
enum IronhandData
{
SAY_MAGMUS_BRAZIER_LIT = 0
IRONHAND_FLAMES_TIMER = 16000,
IRONHAND_FLAMES_TIMER_RAND = 3000,
IRONHAND_N_GROUPS = 3,
SPELL_GOUT_OF_FLAMES = 15529
};
//go_shadowforge_brazier
class go_shadowforge_brazier : public GameObjectScript
{
public:
go_shadowforge_brazier() : GameObjectScript("go_shadowforge_brazier") { }
go_shadowforge_brazier() : GameObjectScript("go_shadowforge_brazier") {}
bool OnGossipHello(Player* /*player*/, GameObject* go) override
{
@@ -46,68 +48,101 @@ public:
return false;
}
// Check if the opposite brazier is lit - if it is, open the gates.
if ((go->GetGUID() == northBrazier->GetGUID() && southBrazier->GetGoState() == GO_STATE_ACTIVE)
|| (go->GetGUID() == southBrazier->GetGUID() && northBrazier->GetGoState() == GO_STATE_ACTIVE))
// should only happen on first brazier
if (instance->GetData(TYPE_LYCEUM) == NOT_STARTED)
{
if (instance->GetData(TYPE_LYCEUM) == IN_PROGRESS)
{
instance->SetData(TYPE_LYCEUM, DONE);
}
else
{
instance->SetData(TYPE_LYCEUM, IN_PROGRESS);
}
if (Creature* magmus = ObjectAccessor::GetCreature(*go, instance->GetGuidData(DATA_MAGMUS)))
{
if (magmus->IsAlive())
{
magmus->AI()->Talk(SAY_MAGMUS_BRAZIER_LIT);
}
}
instance->HandleGameObject(instance->GetGuidData(DATA_GOLEM_DOOR_N), true);
instance->HandleGameObject(instance->GetGuidData(DATA_GOLEM_DOOR_S), true);
instance->SetData(TYPE_LYCEUM, IN_PROGRESS);
}
// Check if the opposite brazier is lit - if it is, open the gates.
if ((go->GetGUID() == northBrazier->GetGUID() && southBrazier->GetGoState() == GO_STATE_ACTIVE) || (go->GetGUID() == southBrazier->GetGUID() && northBrazier->GetGoState() == GO_STATE_ACTIVE))
{
instance->SetData(TYPE_LYCEUM, DONE);
}
return false;
}
return false;
};
};
class ironhand_guardian : public CreatureScript
{
public:
ironhand_guardian() : CreatureScript("brd_ironhand_guardian") {}
CreatureAI* GetAI(Creature* creature) const override
{
return GetBlackrockDepthsAI<ironhand_guardianAI>(creature);
}
struct ironhand_guardianAI : public CreatureAI
{
ironhand_guardianAI(Creature* creature) : CreatureAI(creature) {}
bool flames_enabled = false;
void SetData(uint32 id, uint32 value) override
{
if (id == 0)
{
if (value == 0 || value == 1)
{
flames_enabled = (bool) (value);
events.ScheduleEvent(SPELL_GOUT_OF_FLAMES, urand(1, IRONHAND_N_GROUPS) * IRONHAND_FLAMES_TIMER / IRONHAND_N_GROUPS);
}
}
}
void UpdateAI(uint32 diff) override
{
events.Update(diff);
if (flames_enabled)
{
if (me->HasUnitState(UNIT_STATE_CASTING))
{
return;
}
while (uint32 eventId = events.ExecuteEvent())
{
switch (eventId)
{
case SPELL_GOUT_OF_FLAMES:
DoCast(SPELL_GOUT_OF_FLAMES);
events.RescheduleEvent(SPELL_GOUT_OF_FLAMES, urand(IRONHAND_FLAMES_TIMER - IRONHAND_FLAMES_TIMER_RAND, IRONHAND_FLAMES_TIMER + IRONHAND_FLAMES_TIMER_RAND));
break;
default:
break;
}
}
}
}
EventMap events;
};
};
enum eChallenge
struct Wave
{
QUEST_THE_CHALLENGE = 9015,
GO_BANNER_OF_PROVOCATION = 181058,
GO_ARENA_SPOILS = 181074,
NPC_GRIMSTONE = 10096,
NPC_THELDREN = 16059,
uint32 entry;
uint32 amount;
};
uint32 theldrenTeam[] =
static Wave RingMobs[] = // different amounts based on the type
{
16053, 16055, 16050, 16051, 16049, 16052, 16054, 16058
};
uint32 RingMob[] =
{
8925, // Dredge Worm
8926, // Deep Stinger
8927, // Dark Screecher
8928, // Burrowing Thundersnout
8933, // Cave Creeper
8932, // Borer Beetle
};
{NPC_DREDGE_WORM, 3},
{NPC_DEEP_STINGER, 3},
{NPC_DARK_SCREECHER, 3},
{NPC_THUNDERSNOUT, 2},
{NPC_CAVE_CREEPER, 3},
{NPC_BORER_BEETLE, 6}};
uint32 RingBoss[] =
{
9027, // Gorosh
9028, // Grizzle
9029, // Eviscerator
9030, // Ok'thor
9031, // Anub'shiah
9032, // Hedrum
NPC_GOROSH,
NPC_GRIZZLE,
NPC_EVISCERATOR,
NPC_OKTHOR,
NPC_ANUBSHIAH,
NPC_HEDRUM
};
class at_ring_of_law : public AreaTriggerScript
@@ -119,13 +154,18 @@ public:
{
if (InstanceScript* instance = player->GetInstanceScript())
{
time_t now = time(nullptr);
if (instance->GetData(TYPE_RING_OF_LAW) == IN_PROGRESS || instance->GetData(TYPE_RING_OF_LAW) == DONE)
{
return false;
}
if (now - instance->GetData(DATA_TIME_RING_FAIL) < 2 * 60) // in case of wipe, so people can rez.
{
return false;
}
instance->SetData(TYPE_RING_OF_LAW, IN_PROGRESS);
player->SummonCreature(NPC_GRIMSTONE, 625.559f, -205.618f, -52.735f, 2.609f, TEMPSUMMON_DEAD_DESPAWN, 0);
return false;
return true;
}
return false;
}
@@ -157,9 +197,11 @@ public:
npc_grimstoneAI(Creature* creature) : npc_escortAI(creature), summons(me)
{
instance = creature->GetInstanceScript();
MobSpawnId = rand() % 6;
MobSpawnId = instance ? instance->GetData(DATA_ARENA_MOBS) : urand(0, 5);
BossSpawnId = instance ? instance->GetData(DATA_ARENA_BOSS) : urand(0, 5);
eventPhase = 0;
eventTimer = 1000;
resetTimer = 0;
theldrenEvent = false;
summons.DespawnAll();
}
@@ -169,7 +211,9 @@ public:
uint8 eventPhase;
uint32 eventTimer;
uint32 resetTimer;
uint8 MobSpawnId;
uint8 BossSpawnId;
bool theldrenEvent;
void Reset() override
@@ -189,7 +233,10 @@ public:
summons.Despawn(summon);
// All Summons killed, next phase
if (summons.empty())
{
resetTimer = 0;
eventTimer = 5000;
}
}
void WaypointReached(uint32 waypointId) override
@@ -243,7 +290,45 @@ public:
me->SummonCreature(theldrenTeam[i], 644.300f, -175.989f, -53.739f, 3.418f, TEMPSUMMON_DEAD_DESPAWN, 0);
}
else
me->SummonCreature(RingBoss[rand() % 6], 644.300f, -175.989f, -53.739f, 3.418f, TEMPSUMMON_DEAD_DESPAWN, 0);
me->SummonCreature(RingBoss[BossSpawnId], 644.300f, -175.989f, -53.739f, 3.418f, TEMPSUMMON_DEAD_DESPAWN, 0);
resetTimer = 30000;
}
bool updateReset(uint32 diff)
{
// as long as the summoned creatures have someone to attack, we reset the timer.
// once they don't find anyone, the timer will count down until it is smaller than diff and reset.
bool doReset = false;
if (resetTimer > 0)
{
for (const auto& sum : summons)
{
if (Creature* creature = ObjectAccessor::GetCreature(*me, sum))
{
if (creature->IsAlive() && creature->GetVictim())
{
resetTimer = 30000;
break; // only need to find one.
}
}
}
resetTimer -= diff;
if (resetTimer <= diff)
{
doReset = true;
}
}
return doReset;
}
void SpawnWave(uint32 mobId)
{
for (uint32 i = 0; i < RingMobs[mobId].amount; i++)
{
me->SummonCreature(RingMobs[mobId].entry, 608.960f + 0.4f * i, -235.322f, -53.907f, 1.857f, TEMPSUMMON_DEAD_DESPAWN, 0);
}
resetTimer = 30000;
}
void UpdateEscortAI(uint32 diff) override
@@ -251,6 +336,17 @@ public:
if (!instance)
return;
// reset if our mobs don't have a target.
if (updateReset(diff))
{
summons.DespawnAll();
HandleGameObject(DATA_ARENA4, true);
HandleGameObject(DATA_ARENA3, false);
HandleGameObject(DATA_ARENA2, false);
HandleGameObject(DATA_ARENA1, false);
instance->SetData(TYPE_RING_OF_LAW, FAIL);
}
if (eventTimer)
{
if (eventTimer <= diff)
@@ -277,35 +373,30 @@ public:
case 4:
SetEscortPaused(false);
me->SetVisible(false);
me->SummonCreature(RingMob[MobSpawnId], 608.960f, -235.322f, -53.907f, 1.857f, TEMPSUMMON_DEAD_DESPAWN, 0);
eventTimer = 8000;
SpawnWave(MobSpawnId); // wave 1
eventTimer = 15000;
break;
case 5:
me->SummonCreature(RingMob[MobSpawnId], 608.960f, -235.322f, -53.907f, 1.857f, TEMPSUMMON_DEAD_DESPAWN, 0);
me->SummonCreature(RingMob[MobSpawnId], 608.960f, -235.322f, -53.907f, 1.857f, TEMPSUMMON_DEAD_DESPAWN, 0);
eventTimer = 8000;
SpawnWave(MobSpawnId); // wave 2
eventTimer = 0; // will be set from SummonedCreatureDies
break;
case 6:
me->SummonCreature(RingMob[MobSpawnId], 608.960f, -235.322f, -53.907f, 1.857f, TEMPSUMMON_DEAD_DESPAWN, 0);
eventTimer = 0;
break;
case 7:
me->SetVisible(true);
HandleGameObject(DATA_ARENA1, false);
Talk(SAY_TEXT6);
SetEscortPaused(false);
eventTimer = 0;
break;
case 8:
case 7:
HandleGameObject(DATA_ARENA2, true);
eventTimer = 5000;
break;
case 9:
case 8:
me->SetVisible(false);
SummonBoss();
eventTimer = 0;
break;
case 10:
case 9:
if (theldrenEvent)
{
if (GameObject* go = me->SummonGameObject(GO_ARENA_SPOILS, 596.48f, -187.91f, -54.14f, 4.9f, 0.0f, 0.0f, 0.0f, 0.0f, 300))
@@ -614,4 +705,5 @@ void AddSC_blackrock_depths()
new npc_phalanx();
new npc_lokhtos_darkbargainer();
new npc_rocknot();
new ironhand_guardian();
}

View File

@@ -21,6 +21,13 @@
#include "CreatureAIImpl.h"
#define BRDScriptName "instance_blackrock_depths"
enum FactionIds
{
FACTION_NEUTRAL = 674,
FACTION_HOSTILE = 754,
FACTION_FRIEND = 35
};
enum BRDBosses
{
BOSS_AMBASSADOR_FLAMELASH = 0,
@@ -56,22 +63,86 @@ enum DataTypes
DATA_SF_BRAZIER_N = 25,
DATA_SF_BRAZIER_S = 26,
DATA_MOIRA = 27,
DATA_PRIESTESS = 28,
DATA_OPEN_COFFER_DOORS = 30,
DATA_GOLEM_LORD_ARGELMACH_INIT = 31,
DATA_GOLEM_LORD_ARGELMACH_ADDS = 32,
DATA_MAGMUS = 33,
DATA_COREN = 34
DATA_COREN = 34,
DATA_ANUBSHIAH,
DATA_EVISCERATOR,
DATA_GOROSH,
DATA_GRIZZLE,
DATA_HEDRUM,
DATA_OKTHOR,
DATA_TIME_RING_FAIL,
DATA_ARENA_MOBS,
DATA_ARENA_BOSS
};
enum CreatureIds
enum Creatures
{
NPC_MAGMUS = 9938
NPC_EMPEROR = 9019,
NPC_PHALANX = 9502,
NPC_ANGERREL = 9035,
NPC_DOPEREL = 9040,
NPC_HATEREL = 9034,
NPC_VILEREL = 9036,
NPC_SEETHREL = 9038,
NPC_GLOOMREL = 9037,
NPC_DOOMREL = 9039,
NPC_MOIRA = 8929,
NPC_PRIESTESS = 10076,
NPC_WATCHMAN_DOOMGRIP = 9476,
NPC_WEAPON_TECHNICIAN = 8920,
NPC_DOOMFORGE_ARCANASMITH = 8900,
NPC_RAGEREAVER_GOLEM = 8906,
NPC_WRATH_HAMMER_CONSTRUCT = 8907,
NPC_GOLEM_LORD_ARGELMACH = 8983,
NPC_COREN_DIREBREW = 23872,
NPC_IRONHAND_GUARDIAN = 8982,
NPC_ARENA_SPECTATOR = 8916,
NPC_SHADOWFORGE_PEASANT = 8896,
NPC_SHADOWFORCE_CITIZEN = 8902,
NPC_SHADOWFORGE_SENATOR = 8904,
NPC_MAGMUS = 9938,
NPC_DREDGE_WORM = 8925,
NPC_DEEP_STINGER = 8926,
NPC_DARK_SCREECHER = 8927,
NPC_THUNDERSNOUT = 8928,
NPC_BORER_BEETLE = 8932,
NPC_CAVE_CREEPER = 8933,
NPC_GOROSH = 9027,
NPC_GRIZZLE = 9028,
NPC_EVISCERATOR = 9029,
NPC_OKTHOR = 9030,
NPC_ANUBSHIAH = 9031,
NPC_HEDRUM = 9032
};
enum eChallenge
{
QUEST_THE_CHALLENGE = 9015,
GO_BANNER_OF_PROVOCATION = 181058,
GO_ARENA_SPOILS = 181074,
NPC_GRIMSTONE = 10096,
NPC_THELDREN = 16059,
};
const uint32 theldrenTeam[] = {16053, 16055, 16050, 16051, 16049, 16052, 16054, 16058};
template <class AI, class T>
inline AI* GetBlackrockDepthsAI(T* obj)
{

View File

@@ -21,11 +21,20 @@
enum Spells
{
SPELL_SHADOWBOLT = 17228,
SPELL_CURSEOFTONGUES = 15470,
SPELL_CURSEOFWEAKNESS = 17227,
SPELL_DEMONARMOR = 11735,
SPELL_ENVELOPINGWEB = 15471
SPELL_SHADOWBOLT = 15472,
SPELL_CURSE_TONGUES = 15470,
SPELL_CURSE_WEAKNESS = 12493,
SPELL_DEMON_ARMOR = 13787,
SPELL_ENVELOPING_WEB = 15471
};
enum Timers
{
TIMER_SHADOWBOLT = 7000,
TIMER_CURSE_TONGUES = 24000,
TIMER_CURSE_WEAKNESS = 12000,
TIMER_DEMON_ARMOR = 3000, // virtually only cast once
TIMER_ENVELOPING_WEB = 16000
};
class boss_anubshiah : public CreatureScript
@@ -38,75 +47,68 @@ public:
return GetBlackrockDepthsAI<boss_anubshiahAI>(creature);
}
struct boss_anubshiahAI : public ScriptedAI
struct boss_anubshiahAI : public BossAI
{
boss_anubshiahAI(Creature* creature) : ScriptedAI(creature) { }
boss_anubshiahAI(Creature* creature) : BossAI(creature, DATA_ANUBSHIAH) { }
uint32 ShadowBolt_Timer;
uint32 CurseOfTongues_Timer;
uint32 CurseOfWeakness_Timer;
uint32 DemonArmor_Timer;
uint32 EnvelopingWeb_Timer;
void Reset() override
void EnterCombat(Unit* /*who*/) override
{
ShadowBolt_Timer = 7000;
CurseOfTongues_Timer = 24000;
CurseOfWeakness_Timer = 12000;
DemonArmor_Timer = 3000;
EnvelopingWeb_Timer = 16000;
_EnterCombat();
events.ScheduleEvent(SPELL_SHADOWBOLT, 0.2 * (int)TIMER_SHADOWBOLT);
events.ScheduleEvent(SPELL_CURSE_TONGUES, 0.2 * (int)TIMER_CURSE_TONGUES);
events.ScheduleEvent(SPELL_CURSE_WEAKNESS, 0.2 * (int)TIMER_CURSE_WEAKNESS);
events.ScheduleEvent(SPELL_DEMON_ARMOR, 0.2 * (int)TIMER_DEMON_ARMOR);
events.ScheduleEvent(SPELL_ENVELOPING_WEB, 0.2 * (int)TIMER_ENVELOPING_WEB);
}
void EnterCombat(Unit* /*who*/) override { }
void UpdateAI(uint32 diff) override
{
//Return since we have no target
if (!UpdateVictim())
{
return;
//ShadowBolt_Timer
if (ShadowBolt_Timer <= diff)
{
DoCastVictim(SPELL_SHADOWBOLT);
ShadowBolt_Timer = 7000;
}
else ShadowBolt_Timer -= diff;
events.Update(diff);
//CurseOfTongues_Timer
if (CurseOfTongues_Timer <= diff)
if (me->HasUnitState(UNIT_STATE_CASTING))
{
if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true))
DoCast(target, SPELL_CURSEOFTONGUES);
CurseOfTongues_Timer = 18000;
return;
}
else CurseOfTongues_Timer -= diff;
//CurseOfWeakness_Timer
if (CurseOfWeakness_Timer <= diff)
while (uint32 eventId = events.ExecuteEvent())
{
DoCastVictim(SPELL_CURSEOFWEAKNESS);
CurseOfWeakness_Timer = 45000;
switch (eventId)
{
case SPELL_SHADOWBOLT:
DoCastVictim(SPELL_SHADOWBOLT);
events.ScheduleEvent(SPELL_SHADOWBOLT, urand(TIMER_SHADOWBOLT - 2000, TIMER_SHADOWBOLT + 2000));
break;
case SPELL_CURSE_TONGUES:
if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true))
{
DoCast(target, SPELL_CURSE_TONGUES);
}
events.ScheduleEvent(SPELL_CURSE_TONGUES, urand(TIMER_CURSE_TONGUES - 2000, TIMER_CURSE_TONGUES + 2000));
break;
case SPELL_CURSE_WEAKNESS:
if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true))
{
DoCast(target, SPELL_CURSE_WEAKNESS);
}
events.ScheduleEvent(SPELL_CURSE_WEAKNESS, urand(TIMER_CURSE_WEAKNESS - 2000, TIMER_CURSE_WEAKNESS + 2000));
break;
case SPELL_DEMON_ARMOR:
DoCast(me, SPELL_DEMON_ARMOR);
events.ScheduleEvent(SPELL_DEMON_ARMOR, TIMER_DEMON_ARMOR);
break;
case SPELL_ENVELOPING_WEB:
if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true))
DoCast(target, SPELL_ENVELOPING_WEB);
events.ScheduleEvent(SPELL_ENVELOPING_WEB, urand(TIMER_ENVELOPING_WEB - 2000, TIMER_ENVELOPING_WEB + 2000));
break;
default:
break;
}
}
else CurseOfWeakness_Timer -= diff;
//DemonArmor_Timer
if (DemonArmor_Timer <= diff)
{
DoCast(me, SPELL_DEMONARMOR);
DemonArmor_Timer = 300000;
}
else DemonArmor_Timer -= diff;
//EnvelopingWeb_Timer
if (EnvelopingWeb_Timer <= diff)
{
if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true))
DoCast(target, SPELL_ENVELOPINGWEB);
EnvelopingWeb_Timer = 12000;
}
else EnvelopingWeb_Timer -= diff;
DoMeleeAttackIfReady();
}
};

View File

@@ -21,16 +21,19 @@
enum Yells
{
SAY_AGGRO = 0,
SAY_SLAY = 1
YELL_SENATORS_ALIVE = 0,
YELL_SENATORS_DEAD = 1,
SAY_SLAY = 2
};
enum Spells
{
SPELL_HANDOFTHAURISSAN = 17492,
SPELL_AVATAROFFLAME = 15636
SPELL_HANDOFTHAURISSAN = 17492,
SPELL_AVATAROFFLAME = 15636
};
#define DATA_PERCENT_DEAD_SENATORS 0
class boss_emperor_dagran_thaurissan : public CreatureScript
{
public:
@@ -41,29 +44,27 @@ public:
return GetBlackrockDepthsAI<boss_draganthaurissanAI>(creature);
}
struct boss_draganthaurissanAI : public ScriptedAI
struct boss_draganthaurissanAI : public BossAI
{
boss_draganthaurissanAI(Creature* creature) : ScriptedAI(creature)
{
instance = me->GetInstanceScript();
}
uint32 hasYelled = 0;
uint32 SenatorYells[5] = {3, 4, 5, 6, 7}; // IDs in creature_text database
InstanceScript* instance;
uint32 HandOfThaurissan_Timer;
uint32 AvatarOfFlame_Timer;
//uint32 Counter;
void Reset() override
{
HandOfThaurissan_Timer = 4000;
AvatarOfFlame_Timer = 25000;
//Counter= 0;
}
boss_draganthaurissanAI(Creature* creature) : BossAI(creature, DATA_EMPEROR){}
void EnterCombat(Unit* /*who*/) override
{
Talk(SAY_AGGRO);
if (hasYelled != 5)
{
Talk(YELL_SENATORS_ALIVE);
}
else
{
Talk(YELL_SENATORS_DEAD);
}
me->CallForHelp(VISIBLE_RANGE);
events.ScheduleEvent(SPELL_HANDOFTHAURISSAN, urand(4000, 7000));
events.ScheduleEvent(SPELL_AVATAROFFLAME, urand(10000, 12000));
}
void KilledUnit(Unit* /*victim*/) override
@@ -71,11 +72,27 @@ public:
Talk(SAY_SLAY);
}
void SetData(uint32 type, uint32 data) override
{
if (type == DATA_PERCENT_DEAD_SENATORS)
{
if (data >= 20 * (hasYelled + 1)) // map the 5 yells to %. Yell after 20,40,60,80,100%
{
if (hasYelled < 5)
{
Talk(SenatorYells[hasYelled]);
}
hasYelled++;
}
}
}
void JustDied(Unit* /*killer*/) override
{
if (Creature* Moira = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_MOIRA)))
{
Moira->AI()->EnterEvadeMode();
Moira->AI()->Talk(0);
Moira->SetFaction(FACTION_FRIENDLY);
}
}
@@ -86,33 +103,28 @@ public:
if (!UpdateVictim())
return;
if (HandOfThaurissan_Timer <= diff)
events.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
while (uint32 eventId = events.ExecuteEvent())
{
if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0))
DoCast(target, SPELL_HANDOFTHAURISSAN);
//3 Hands of Thaurissan will be cast
//if (Counter < 3)
//{
// HandOfThaurissan_Timer = 1000;
// ++Counter;
//}
//else
//{
HandOfThaurissan_Timer = 5000;
//Counter = 0;
//}
switch (eventId)
{
case SPELL_HANDOFTHAURISSAN:
DoCast(SelectTarget(SELECT_TARGET_RANDOM), SPELL_HANDOFTHAURISSAN);
//DoCastVictim(SPELL_HANDOFTHAURISSAN);
events.ScheduleEvent(SPELL_HANDOFTHAURISSAN, urand(4000, 7000));
break;
case SPELL_AVATAROFFLAME:
DoCastSelf(SPELL_AVATAROFFLAME);
events.ScheduleEvent(SPELL_AVATAROFFLAME, urand(23000, 27000));
break;
default:
break;
}
}
else HandOfThaurissan_Timer -= diff;
//AvatarOfFlame_Timer
if (AvatarOfFlame_Timer <= diff)
{
DoCastVictim(SPELL_AVATAROFFLAME);
AvatarOfFlame_Timer = 18000;
}
else AvatarOfFlame_Timer -= diff;
DoMeleeAttackIfReady();
}
};

View File

@@ -0,0 +1,110 @@
/*
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by the
* Free Software Foundation; either version 3 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 Affero General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "blackrock_depths.h"
#include "ScriptedCreature.h"
#include "ScriptMgr.h"
enum Spells
{
SPELL_SHADOWBOLT_VOLLEY = 15245,
SPELL_REND = 14331,
SPELL_SHIELD = 7121
};
enum Timers
{
TIMER_SHADOWBOLT_VOLLEY = 7000,
TIMER_REND = 20000,
TIMER_SHIELD = 12000
};
class boss_eviscerator : public CreatureScript
{
public:
boss_eviscerator() : CreatureScript("boss_eviscerator") {}
CreatureAI* GetAI(Creature* creature) const override
{
return GetBlackrockDepthsAI<boss_evisceratorAI>(creature);
}
struct boss_evisceratorAI : public BossAI
{
boss_evisceratorAI(Creature* creature) : BossAI(creature, DATA_EVISCERATOR) {}
bool SpellShieldReady = false;
void EnterCombat(Unit* /*who*/) override
{
_EnterCombat();
events.ScheduleEvent(SPELL_SHADOWBOLT_VOLLEY, 0.2 * (int)TIMER_SHADOWBOLT_VOLLEY);
events.ScheduleEvent(SPELL_REND, 0.2 * (int) TIMER_REND);
events.ScheduleEvent(SPELL_SHIELD, 0.2 * (int) TIMER_SHIELD);
}
void DamageTaken(Unit* /* doneBy */, uint32& /* damage */, DamageEffectType /* damagetype */, SpellSchoolMask damageSchoolMask) override
{
if ((damageSchoolMask & SPELL_SCHOOL_MASK_MAGIC) && SpellShieldReady)
{
DoCast(SPELL_SHIELD);
SpellShieldReady = false;
events.ScheduleEvent(SPELL_SHIELD, TIMER_SHIELD);
}
}
void UpdateAI(uint32 diff) override
{
//Return since we have no target
if (!UpdateVictim())
{
return;
}
events.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING))
{
return;
}
while (uint32 eventId = events.ExecuteEvent())
{
switch (eventId)
{
case SPELL_SHADOWBOLT_VOLLEY:
DoCastVictim(SPELL_SHADOWBOLT_VOLLEY);
events.ScheduleEvent(SPELL_SHADOWBOLT_VOLLEY, urand(TIMER_SHADOWBOLT_VOLLEY - 2000, TIMER_SHADOWBOLT_VOLLEY + 2000));
break;
case SPELL_REND:
DoCastVictim(SPELL_REND);
events.ScheduleEvent(SPELL_REND, urand(TIMER_REND - 2000, TIMER_REND + 2000));
break;
case SPELL_SHIELD:
SpellShieldReady = true;
break;
default:
break;
}
}
DoMeleeAttackIfReady();
}
};
};
void AddSC_boss_eviscerator()
{
new boss_eviscerator();
}

View File

@@ -21,8 +21,16 @@
enum Spells
{
SPELL_WHIRLWIND = 15589,
SPELL_MORTALSTRIKE = 24573
SPELL_WHIRLWIND = 15589,
SPELL_MORTALSTRIKE = 15708,
SPELL_BLOODLUST = 21049
};
enum Timers
{
TIMER_WHIRLWIND = 12000,
TIMER_MORTAL = 22000,
TIMER_BLOODLUST = 30000
};
class boss_gorosh_the_dervish : public CreatureScript
@@ -35,45 +43,62 @@ public:
return GetBlackrockDepthsAI<boss_gorosh_the_dervishAI>(creature);
}
struct boss_gorosh_the_dervishAI : public ScriptedAI
struct boss_gorosh_the_dervishAI : public BossAI
{
boss_gorosh_the_dervishAI(Creature* creature) : ScriptedAI(creature) { }
boss_gorosh_the_dervishAI(Creature* creature) : BossAI(creature, DATA_GOROSH) { }
uint32 WhirlWind_Timer;
uint32 MortalStrike_Timer;
void Reset() override
{
WhirlWind_Timer = 12000;
MortalStrike_Timer = 22000;
}
uint32 nextWhirlwindTime;
void EnterCombat(Unit* /*who*/) override
{
_EnterCombat();
events.ScheduleEvent(SPELL_WHIRLWIND, 0.2 * (int) TIMER_WHIRLWIND);
events.ScheduleEvent(SPELL_MORTALSTRIKE, 0.2 * (int) TIMER_MORTAL);
events.ScheduleEvent(SPELL_BLOODLUST, 0.2 * (int) TIMER_BLOODLUST);
}
void UpdateAI(uint32 diff) override
{
//Return since we have no target
// Return since we have no target
if (!UpdateVictim())
{
return;
//WhirlWind_Timer
if (WhirlWind_Timer <= diff)
{
DoCast(me, SPELL_WHIRLWIND);
WhirlWind_Timer = 15000;
}
else WhirlWind_Timer -= diff;
events.Update(diff);
//MortalStrike_Timer
if (MortalStrike_Timer <= diff)
if (me->HasUnitState(UNIT_STATE_CASTING))
{
DoCastVictim(SPELL_MORTALSTRIKE);
MortalStrike_Timer = 15000;
return;
}
while (uint32 eventId = events.ExecuteEvent())
{
switch (eventId)
{
case SPELL_WHIRLWIND:
if (me->GetDistance2d(me->GetVictim()) < 10.0f)
{
DoCastVictim(SPELL_WHIRLWIND);
nextWhirlwindTime = urand(TIMER_WHIRLWIND - 2000, TIMER_WHIRLWIND + 2000);
}
else
{
// reschedule sooner
nextWhirlwindTime = 0.3 * urand(TIMER_WHIRLWIND - 2000, TIMER_WHIRLWIND + 2000);
}
events.ScheduleEvent(SPELL_WHIRLWIND, nextWhirlwindTime);
break;
case SPELL_MORTALSTRIKE:
DoCastVictim(SPELL_MORTALSTRIKE);
events.ScheduleEvent(SPELL_MORTALSTRIKE, urand(TIMER_MORTAL - 2000, TIMER_MORTAL + 2000));
break;
case SPELL_BLOODLUST:
DoCastSelf(SPELL_BLOODLUST);
events.ScheduleEvent(SPELL_BLOODLUST, urand(TIMER_BLOODLUST - 2000, TIMER_BLOODLUST + 2000));
break;
default:
break;
}
}
else MortalStrike_Timer -= diff;
DoMeleeAttackIfReady();
}
};

View File

@@ -22,10 +22,16 @@
enum Grizzle
{
SPELL_GROUNDTREMOR = 6524,
SPELL_FRENZY = 28371,
SPELL_FRENZY = 8269,
EMOTE_FRENZY_KILL = 0
};
enum Timer
{
TIMER_GROUNDTREMOR = 10000,
TIMER_FRENZY = 15000
};
class boss_grizzle : public CreatureScript
{
public:
@@ -36,48 +42,58 @@ public:
return GetBlackrockDepthsAI<boss_grizzleAI>(creature);
}
struct boss_grizzleAI : public ScriptedAI
struct boss_grizzleAI : public BossAI
{
boss_grizzleAI(Creature* creature) : ScriptedAI(creature) { }
boss_grizzleAI(Creature* creature) : BossAI(creature, DATA_GRIZZLE) {}
uint32 GroundTremor_Timer;
uint32 Frenzy_Timer;
uint32 nextTremorTime;
void Reset() override
void EnterCombat(Unit* /*who*/) override
{
GroundTremor_Timer = 12000;
Frenzy_Timer = 0;
_EnterCombat();
events.ScheduleEvent(SPELL_GROUNDTREMOR, 0.2 * (int) TIMER_GROUNDTREMOR);
events.ScheduleEvent(SPELL_FRENZY, 0.2 * (int) TIMER_FRENZY);
}
void EnterCombat(Unit* /*who*/) override { }
void UpdateAI(uint32 diff) override
{
//Return since we have no target
if (!UpdateVictim())
{
return;
//GroundTremor_Timer
if (GroundTremor_Timer <= diff)
{
DoCastVictim(SPELL_GROUNDTREMOR);
GroundTremor_Timer = 8000;
}
else GroundTremor_Timer -= diff;
events.Update(diff);
//Frenzy_Timer
if (HealthBelowPct(51))
if (me->HasUnitState(UNIT_STATE_CASTING))
{
if (Frenzy_Timer <= diff)
return;
}
while (uint32 eventId = events.ExecuteEvent())
{
switch (eventId)
{
DoCast(me, SPELL_FRENZY);
case SPELL_GROUNDTREMOR:
if (me->GetDistance2d(me->GetVictim()) < 10.0f)
{
DoCastVictim(SPELL_GROUNDTREMOR);
nextTremorTime = urand(TIMER_GROUNDTREMOR - 2000, TIMER_GROUNDTREMOR + 2000);
}
else
{
nextTremorTime = 0.3*urand(TIMER_GROUNDTREMOR - 2000, TIMER_GROUNDTREMOR + 2000);
}
events.ScheduleEvent(SPELL_GROUNDTREMOR, nextTremorTime);
break;
case SPELL_FRENZY:
DoCastSelf(SPELL_FRENZY);
events.ScheduleEvent(SPELL_FRENZY, urand(TIMER_FRENZY - 2000, TIMER_FRENZY + 2000));
Talk(EMOTE_FRENZY_KILL);
Frenzy_Timer = 15000;
break;
default:
break;
}
else Frenzy_Timer -= diff;
}
DoMeleeAttackIfReady();
}
};

View File

@@ -0,0 +1,102 @@
/*
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by the
* Free Software Foundation; either version 3 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 Affero General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "blackrock_depths.h"
#include "ScriptedCreature.h"
#include "ScriptMgr.h"
enum Spells
{
SPELL_PARALYZING = 3609,
SPELL_BANEFUL = 15475,
SPELL_WEB_EXPLOSION = 15474
};
enum Timers
{
TIMER_PARALYZING = 20000,
TIMER_BANEFUL = 24000,
TIMER_WEB_EXPLOSION = 20000
};
class boss_hedrum : public CreatureScript
{
public:
boss_hedrum() : CreatureScript("boss_hedrum") {}
CreatureAI* GetAI(Creature* creature) const override
{
return GetBlackrockDepthsAI<boss_hedrumAI>(creature);
}
struct boss_hedrumAI : public BossAI
{
boss_hedrumAI(Creature* creature) : BossAI(creature, DATA_HEDRUM) {}
void EnterCombat(Unit* /*who*/) override
{
_EnterCombat();
events.ScheduleEvent(SPELL_PARALYZING, 0.2 * (int) TIMER_PARALYZING);
events.ScheduleEvent(SPELL_BANEFUL, 0.2 * (int) TIMER_BANEFUL);
events.ScheduleEvent(SPELL_WEB_EXPLOSION, 0.2 * (int) TIMER_WEB_EXPLOSION);
}
void UpdateAI(uint32 diff) override
{
// Return since we have no target
if (!UpdateVictim())
{
return;
}
events.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING))
{
return;
}
while (uint32 eventId = events.ExecuteEvent())
{
switch (eventId)
{
case SPELL_PARALYZING:
DoCastVictim(SPELL_PARALYZING);
events.ScheduleEvent(SPELL_PARALYZING, urand(TIMER_PARALYZING - 2000, TIMER_PARALYZING + 2000));
break;
case SPELL_BANEFUL:
DoCastVictim(SPELL_BANEFUL);
events.ScheduleEvent(SPELL_BANEFUL, urand(TIMER_BANEFUL - 2000, TIMER_BANEFUL + 2000));
break;
case SPELL_WEB_EXPLOSION:
if (me->GetDistance2d(me->GetVictim()) < 100.0f)
{
DoCast(SPELL_WEB_EXPLOSION);
}
events.ScheduleEvent(SPELL_WEB_EXPLOSION, urand(TIMER_WEB_EXPLOSION - 2000, TIMER_WEB_EXPLOSION + 2000));
break;
default:
break;
}
}
DoMeleeAttackIfReady();
}
};
};
void AddSC_boss_hedrum()
{
new boss_hedrum();
}

View File

@@ -25,6 +25,14 @@ enum Spells
SPELL_WARSTOMP = 24375
};
enum SpellTimers
{
SPELL_FIERYBURST_MIN = 4000,
SPELL_FIERYBURST_MAX = 8000,
SPELL_WARSTOMP_MIN = 8000,
SPELL_WARSTOMP_MAX = 12000
};
class boss_magmus : public CreatureScript
{
public:
@@ -35,54 +43,53 @@ public:
return GetBlackrockDepthsAI<boss_magmusAI>(creature);
}
struct boss_magmusAI : public ScriptedAI
struct boss_magmusAI : public BossAI
{
boss_magmusAI(Creature* creature) : ScriptedAI(creature) { }
uint32 FieryBurst_Timer;
uint32 WarStomp_Timer;
boss_magmusAI(Creature* creature) : BossAI(creature, TYPE_IRON_HALL) {}
void Reset() override
{
FieryBurst_Timer = 5000;
WarStomp_Timer = 0;
_Reset();
instance->SetData(TYPE_IRON_HALL, NOT_STARTED);
}
void EnterCombat(Unit* /*who*/) override { }
void EnterCombat(Unit* /*who*/) override
{
instance->SetData(TYPE_IRON_HALL, IN_PROGRESS);
_EnterCombat();
events.ScheduleEvent(SPELL_FIERYBURST, urand(SPELL_FIERYBURST_MIN, SPELL_FIERYBURST_MAX));
events.ScheduleEvent(SPELL_WARSTOMP, urand(SPELL_WARSTOMP_MIN, SPELL_WARSTOMP_MAX));
}
void UpdateAI(uint32 diff) override
{
//Return since we have no target
if (!UpdateVictim())
{
return;
//FieryBurst_Timer
if (FieryBurst_Timer <= diff)
{
DoCastVictim(SPELL_FIERYBURST);
FieryBurst_Timer = 6000;
}
else FieryBurst_Timer -= diff;
events.Update(diff);
//WarStomp_Timer
if (HealthBelowPct(51))
while (uint32 eventId = events.ExecuteEvent())
{
if (WarStomp_Timer <= diff)
switch (eventId)
{
case SPELL_WARSTOMP:
DoCastVictim(SPELL_WARSTOMP);
WarStomp_Timer = 8000;
events.ScheduleEvent(SPELL_WARSTOMP, urand(SPELL_WARSTOMP_MIN, SPELL_WARSTOMP_MAX));
break;
case SPELL_FIERYBURST:
DoCastVictim(SPELL_FIERYBURST);
events.ScheduleEvent(SPELL_FIERYBURST, urand(SPELL_FIERYBURST_MIN, SPELL_FIERYBURST_MAX));
break;
default:
break;
}
else WarStomp_Timer -= diff;
}
DoMeleeAttackIfReady();
}
// When he die open door to last chamber
void JustDied(Unit* killer) override
{
if (InstanceScript* instance = killer->GetInstanceScript())
instance->HandleGameObject(instance->GetGuidData(DATA_THRONE_DOOR), true);
}
};
};

View File

@@ -21,12 +21,134 @@
enum Spells
{
SPELL_HEAL = 10917,
SPELL_RENEW = 10929,
SPELL_SHIELD = 10901,
SPELL_MINDBLAST = 10947,
SPELL_SHADOWWORDPAIN = 10894,
SPELL_SMITE = 10934
SPELL_HEAL = 15586,
SPELL_RENEW = 8362,
SPELL_MINDBLAST = 15587,
SPELL_SHADOWBOLT = 15537,
SPELL_WORDPAIN = 15654,
};
enum SpellTimers
{
TIMER_HEAL = 12000,
TIMER_MINDBLAST = 16000,
TIMER_RENEW = 12000,
TIMER_SHADOWBOLT = 16000,
TIMER_WORDPAIN = 12000,
};
struct boss_moira_bronzebeardAI : public BossAI
{
// use a default value so we can inherit for priestess
boss_moira_bronzebeardAI(Creature* creature, uint32 data = DATA_MOIRA) : BossAI(creature, data) {}
void EnterCombat(Unit* /*who*/) override
{
_EnterCombat();
events.ScheduleEvent(SPELL_MINDBLAST, 0.5 * (int) TIMER_MINDBLAST);
events.ScheduleEvent(SPELL_HEAL, 0.5 * (int) TIMER_HEAL);
events.ScheduleEvent(SPELL_RENEW, 0.5 * (int) TIMER_RENEW);
}
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
{
return;
}
events.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING))
{
return;
}
while (uint32 eventId = events.ExecuteEvent())
{
switch (eventId)
{
case SPELL_MINDBLAST:
DoCastVictim(SPELL_MINDBLAST);
events.ScheduleEvent(SPELL_MINDBLAST, urand(TIMER_MINDBLAST - 2000, TIMER_MINDBLAST + 2000));
break;
case SPELL_HEAL:
CastOnEmperorIfPossible(SPELL_HEAL, TIMER_HEAL);
break;
case SPELL_RENEW:
CastOnEmperorIfPossible(SPELL_RENEW, TIMER_RENEW);
break;
default:
break;
}
}
DoMeleeAttackIfReady();
}
void CastOnEmperorIfPossible(uint32 spell, uint32 timer)
{
Creature* emperor = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_EMPEROR));
if (emperor && emperor->HealthBelowPct(90))
{
DoCast(emperor, spell);
}
else if (HealthBelowPct(90))
{
DoCastSelf(spell);
}
events.ScheduleEvent(spell, urand(timer - 2000, timer + 2000));
}
};
// high priestess should be fairly identical to Moira.
// Running away when emperor dies is handled through GUID from emperor, therefore not relevant here.
struct boss_high_priestess_thaurissanAI : public boss_moira_bronzebeardAI
{
boss_high_priestess_thaurissanAI(Creature* creature) : boss_moira_bronzebeardAI(creature, DATA_PRIESTESS) {}
void EnterCombat(Unit* /*who*/) override
{
_EnterCombat();
Talk(0);
events.ScheduleEvent(SPELL_WORDPAIN, 0.5 * (int)TIMER_WORDPAIN);
events.ScheduleEvent(SPELL_HEAL, 0.5 * (int) TIMER_HEAL);
events.ScheduleEvent(SPELL_RENEW, 0.5 * (int) TIMER_RENEW);
events.ScheduleEvent(SPELL_SHADOWBOLT, 0.5 * (int) TIMER_SHADOWBOLT);
}
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
{
return;
}
events.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING))
{
return;
}
while (uint32 eventId = events.ExecuteEvent())
{
switch (eventId)
{
case SPELL_WORDPAIN:
DoCastVictim(SPELL_WORDPAIN);
events.ScheduleEvent(SPELL_WORDPAIN, urand(TIMER_WORDPAIN - 2000, TIMER_WORDPAIN + 2000));
break;
case SPELL_HEAL:
CastOnEmperorIfPossible(SPELL_HEAL, TIMER_HEAL);
break;
case SPELL_RENEW:
CastOnEmperorIfPossible(SPELL_RENEW, TIMER_RENEW);
break;
case SPELL_SHADOWBOLT:
DoCastVictim(SPELL_SHADOWBOLT);
events.ScheduleEvent(SPELL_SHADOWBOLT, urand(TIMER_SHADOWBOLT - 2000, TIMER_SHADOWBOLT + 2000));
break;
default:
break;
}
}
DoMeleeAttackIfReady();
}
};
class boss_moira_bronzebeard : public CreatureScript
@@ -38,60 +160,25 @@ public:
{
return GetBlackrockDepthsAI<boss_moira_bronzebeardAI>(creature);
}
};
struct boss_moira_bronzebeardAI : public ScriptedAI
class boss_high_priestess_thaurissan : public CreatureScript
{
public:
boss_high_priestess_thaurissan() : CreatureScript("boss_high_priestess_thaurissan") {}
CreatureAI* GetAI(Creature* creature) const override
{
boss_moira_bronzebeardAI(Creature* creature) : ScriptedAI(creature) { }
uint32 Heal_Timer;
uint32 MindBlast_Timer;
uint32 ShadowWordPain_Timer;
uint32 Smite_Timer;
void Reset() override
{
Heal_Timer = 12000; //These times are probably wrong
MindBlast_Timer = 16000;
ShadowWordPain_Timer = 2000;
Smite_Timer = 8000;
}
void EnterCombat(Unit* /*who*/) override { }
void UpdateAI(uint32 diff) override
{
//Return since we have no target
if (!UpdateVictim())
return;
//MindBlast_Timer
if (MindBlast_Timer <= diff)
{
DoCastVictim(SPELL_MINDBLAST);
MindBlast_Timer = 14000;
}
else MindBlast_Timer -= diff;
//ShadowWordPain_Timer
if (ShadowWordPain_Timer <= diff)
{
DoCastVictim(SPELL_SHADOWWORDPAIN);
ShadowWordPain_Timer = 18000;
}
else ShadowWordPain_Timer -= diff;
//Smite_Timer
if (Smite_Timer <= diff)
{
DoCastVictim(SPELL_SMITE);
Smite_Timer = 10000;
}
else Smite_Timer -= diff;
}
};
return GetBlackrockDepthsAI<boss_high_priestess_thaurissanAI>(creature);
}
};
void AddSC_boss_moira_bronzebeard()
{
new boss_moira_bronzebeard();
}
void AddSC_boss_high_priestess_thaurissan()
{
new boss_high_priestess_thaurissan();
}

View File

@@ -0,0 +1,126 @@
/*
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by the
* Free Software Foundation; either version 3 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 Affero General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "blackrock_depths.h"
#include "ScriptedCreature.h"
#include "ScriptMgr.h"
enum Spells
{
SPELL_ARCANE_BOLT = 13748,
SPELL_ARCANE_EXPLOSION = 1467,
SPELL_POLYMORPH = 15534,
SPELL_SLOW = 19137
};
enum Timers
{
TIMER_ARCANE_BOLT = 7000,
TIMER_ARCANE_EXPLOSION = 24000,
TIMER_POLYMORPH = 12000,
TIMER_SLOW = 15000
};
class boss_okthor : public CreatureScript
{
public:
boss_okthor() : CreatureScript("boss_okthor") {}
CreatureAI* GetAI(Creature* creature) const override
{
return GetBlackrockDepthsAI<boss_okthorAI>(creature);
}
struct boss_okthorAI : public BossAI
{
boss_okthorAI(Creature* creature) : BossAI(creature, DATA_OKTHOR) {}
uint32 nextArcaneExplosionTime;
void EnterCombat(Unit* /*who*/) override
{
_EnterCombat();
events.ScheduleEvent(SPELL_ARCANE_BOLT, 0.2 * (int) TIMER_ARCANE_BOLT);
events.ScheduleEvent(SPELL_ARCANE_EXPLOSION, 0.2 * (int) TIMER_ARCANE_EXPLOSION);
events.ScheduleEvent(SPELL_POLYMORPH, 0.2 * (int) TIMER_POLYMORPH);
events.ScheduleEvent(SPELL_SLOW, 500);
}
void UpdateAI(uint32 diff) override
{
//Return since we have no target
if (!UpdateVictim())
{
return;
}
events.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING))
{
return;
}
while (uint32 eventId = events.ExecuteEvent())
{
switch (eventId)
{
case SPELL_ARCANE_BOLT:
if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true))
{
DoCast(target, SPELL_ARCANE_BOLT);
}
events.ScheduleEvent(SPELL_ARCANE_BOLT, urand(TIMER_ARCANE_BOLT - 2000, TIMER_ARCANE_BOLT + 2000));
break;
case SPELL_ARCANE_EXPLOSION:
if (me->GetDistance2d(me->GetVictim()) < 50.0f)
{
DoCast(SPELL_ARCANE_EXPLOSION);
nextArcaneExplosionTime = urand(TIMER_ARCANE_EXPLOSION - 2000, TIMER_ARCANE_EXPLOSION + 2000);
}
else
{
nextArcaneExplosionTime = 0.3*urand(TIMER_ARCANE_EXPLOSION - 2000, TIMER_ARCANE_EXPLOSION + 2000);
}
events.ScheduleEvent(SPELL_ARCANE_EXPLOSION, nextArcaneExplosionTime);
break;
case SPELL_POLYMORPH:
if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true))
{
DoCast(target, SPELL_POLYMORPH);
}
events.ScheduleEvent(SPELL_POLYMORPH, urand(TIMER_POLYMORPH - 2000, TIMER_POLYMORPH + 2000));
break;
case SPELL_SLOW:
if (me->GetDistance2d(me->GetVictim()) < 50.0f)
{
DoCast(SPELL_SLOW);
}
events.ScheduleEvent(SPELL_SLOW, TIMER_SLOW);
break;
default:
break;
}
}
DoMeleeAttackIfReady();
}
};
};
void AddSC_boss_okthor()
{
new boss_okthor();
}

View File

@@ -29,28 +29,16 @@ enum Timers
TIMER_TOMB_RESET = 15000
};
enum Creatures
enum Distances
{
NPC_EMPEROR = 9019,
NPC_PHALANX = 9502,
NPC_ANGERREL = 9035,
NPC_DOPEREL = 9040,
NPC_HATEREL = 9034,
NPC_VILEREL = 9036,
NPC_SEETHREL = 9038,
NPC_GLOOMREL = 9037,
NPC_DOOMREL = 9039,
NPC_MOIRA = 8929,
RADIUS_RING_OF_LAW = 80,
DISTANCE_EMPEROR_ROOM = 125
};
NPC_WATCHMAN_DOOMGRIP = 9476,
NPC_WEAPON_TECHNICIAN = 8920,
NPC_DOOMFORGE_ARCANASMITH = 8900,
NPC_RAGEREAVER_GOLEM = 8906,
NPC_WRATH_HAMMER_CONSTRUCT = 8907,
NPC_GOLEM_LORD_ARGELMACH = 8983,
NPC_COREN_DIREBREW = 23872
enum PrincessQuests
{
PRINCESS_QUEST_HORDE = 4004,
PRINCESS_QUEST_ALLIANCE = 4363
};
enum GameObjects
@@ -127,6 +115,8 @@ public:
ObjectGuid PhalanxGUID;
ObjectGuid MagmusGUID;
ObjectGuid MoiraGUID;
ObjectGuid PriestessGUID;
ObjectGuid IronhandGUID[6];
ObjectGuid CorenGUID;
ObjectGuid GoArena1GUID;
@@ -158,10 +148,68 @@ public:
uint32 TombTimer;
uint32 TombEventCounter;
uint32 OpenedCoofers;
uint32 IronhandCounter;
GuidList ArgelmachAdds;
ObjectGuid ArgelmachGUID;
TempSummon* TempSummonGrimstone = nullptr;
Position GrimstonePositon = Position(625.559f, -205.618f, -52.735f, 2.609f);
time_t timeRingFail = 0;
uint8 arenaMobsToSpawn;
uint8 arenaBossToSpawn;
std::vector<ObjectGuid> ArenaSpectators;
Position CenterOfRingOfLaw = Position(595.289, -186.56);
ObjectGuid EmperorSenators[5];
std::vector<ObjectGuid> EmperorSenatorsVector;
Position EmperorSpawnPos = Position(1380.52, -831, 115);
void OnPlayerEnter(Player* /* player */) override
{
ReplaceMoiraIfSaved(); // In case a player joins the party during the run
// SetData(TYPE_RING_OF_LAW, DONE);
}
void ReplaceMoiraIfSaved()
{
ObjectGuid* GUIDToReplace = &PriestessGUID; // default to having Moira
ObjectGuid* GUIDToSpawn = &MoiraGUID;
uint32 NPCEntry = NPC_MOIRA;
bool MoiraSaved = true;
// check if all players saved her.
Map::PlayerList const& lPlayers = instance->GetPlayers();
if (!lPlayers.isEmpty())
{
for (Map::PlayerList::const_iterator itr = lPlayers.begin(); itr != lPlayers.end(); ++itr)
{
if (Player* player = itr->GetSource())
{
// set to false if this player hasn't saved her. Another player can't put it to true.
MoiraSaved = MoiraSaved && ((player->GetQuestStatus(PRINCESS_QUEST_HORDE) == QUEST_STATUS_REWARDED)
|| (player->GetQuestStatus(PRINCESS_QUEST_ALLIANCE) == QUEST_STATUS_REWARDED));
}
}
}
// assign correct GUIDs and spawn targets
if (MoiraSaved)
{
GUIDToReplace = &MoiraGUID;
GUIDToSpawn = &PriestessGUID;
NPCEntry = NPC_PRIESTESS;
}
if (Creature* CreatureToReplace = instance->GetCreature(*GUIDToReplace))
{
Creature* NewSpawn = instance->SummonCreature(NPCEntry, CreatureToReplace->GetPosition());
CreatureToReplace->RemoveFromWorld();
*GUIDToSpawn = NewSpawn->GetGUID();
}
}
void Initialize() override
{
memset(&encounter, 0, sizeof(encounter));
@@ -170,8 +218,14 @@ public:
GhostKillCount = 0;
TombTimer = TIMER_TOMB_START;
TombEventCounter = 0;
OpenedCoofers = 0;
tombResetTimer = 0;
OpenedCoofers = 0;
IronhandCounter = 0;
ArenaSpectators.clear();
// these are linked to the dungeon and not how many times the arena started.
arenaMobsToSpawn = urand(0, 5);
arenaBossToSpawn = urand(0, 5);
}
void OnCreatureCreate(Creature* creature) override
@@ -214,7 +268,7 @@ public:
case NPC_MAGMUS:
MagmusGUID = creature->GetGUID();
if (!creature->IsAlive())
HandleGameObject(GetGuidData(DATA_THRONE_DOOR), true); // if Magmus is dead open door to last boss
HandleGameObject(GoThroneGUID, true); // if Magmus is dead open door to last boss
break;
case NPC_WEAPON_TECHNICIAN:
case NPC_DOOMFORGE_ARCANASMITH:
@@ -228,6 +282,38 @@ public:
case NPC_GOLEM_LORD_ARGELMACH:
ArgelmachGUID = creature->GetGUID();
break;
case NPC_IRONHAND_GUARDIAN:
IronhandGUID[IronhandCounter] = creature->GetGUID();
IronhandCounter++;
break;
case NPC_ARENA_SPECTATOR:
ArenaSpectators.push_back(creature->GetGUID());
if (encounter[TYPE_RING_OF_LAW] == DONE) // added for crashes
{
creature->SetFaction(FACTION_NEUTRAL);
creature->SetReactState(REACT_DEFENSIVE);
}
break;
case NPC_SHADOWFORGE_PEASANT:
case NPC_SHADOWFORCE_CITIZEN: // both do the same
if (creature->GetDistance2d(CenterOfRingOfLaw.GetPositionX(), CenterOfRingOfLaw.GetPositionY()) < (float)RADIUS_RING_OF_LAW)
{
ArenaSpectators.push_back(creature->GetGUID());
}
if (encounter[TYPE_RING_OF_LAW] == DONE) // added for crashes
{
creature->SetFaction(FACTION_NEUTRAL);
creature->SetReactState(REACT_DEFENSIVE);
}
break;
case NPC_SHADOWFORGE_SENATOR:
// keep track of Senators that are not too far from emperor. Can't really use emperor as creature due to him possibly not being spawned.
// some senators spawn at ring of law
if (creature->GetDistance2d(EmperorSpawnPos.GetPositionX(), EmperorSpawnPos.GetPositionY()) < (float)DISTANCE_EMPEROR_ROOM)
{
EmperorSenatorsVector.push_back(creature->GetGUID());
}
break;
default:
break;
}
@@ -309,6 +395,7 @@ public:
void OnUnitDeath(Unit* unit) override
{
uint32 deadSenators = 0;
switch (unit->GetEntry())
{
case NPC_WEAPON_TECHNICIAN:
@@ -317,6 +404,28 @@ public:
case NPC_WRATH_HAMMER_CONSTRUCT:
ArgelmachAdds.remove(unit->GetGUID());
break;
case NPC_MAGMUS:
SetData(TYPE_IRON_HALL, DONE);
break;
case NPC_SHADOWFORGE_SENATOR:
deadSenators = 1; //hacky, but we cannot count the unit that just died through its state because OnUnitDeath() is called before the state is set.
for (const auto &senatorGUID: EmperorSenatorsVector)
{
if (Creature* senator = instance->GetCreature(senatorGUID))
{
if (!senator->IsAlive() || senator->isDying())
{
deadSenators++;
}
}
}
if (Creature* emperor = instance->GetCreature(EmperorGUID))
{
// send % of senators that died
emperor->AI()->SetData(0, (100 * deadSenators) / EmperorSenatorsVector.size());
}
break;
case NPC_ANGERREL:
case NPC_DOPEREL:
case NPC_HATEREL:
@@ -343,6 +452,33 @@ public:
{
case TYPE_RING_OF_LAW:
encounter[0] = data;
switch(data)
{
case IN_PROGRESS:
TempSummonGrimstone = instance->SummonCreature(NPC_GRIMSTONE, GrimstonePositon);
break;
case FAIL:
if (TempSummonGrimstone)
{
TempSummonGrimstone->RemoveFromWorld();
TempSummonGrimstone = nullptr;
timeRingFail = time(nullptr);
}
SetData(TYPE_RING_OF_LAW, NOT_STARTED);
break;
case DONE:
for (const auto& itr : ArenaSpectators)
{
if (Creature* spectator = instance->GetCreature(itr))
{
spectator->SetFaction(FACTION_NEUTRAL);
spectator->SetReactState(REACT_DEFENSIVE);
}
}
break;
default:
break;
}
break;
case TYPE_VAULT:
encounter[1] = data;
@@ -370,9 +506,37 @@ public:
break;
case TYPE_LYCEUM:
encounter[4] = data;
if (data == DONE)
{
HandleGameObject(GetGuidData(DATA_GOLEM_DOOR_N), true);
HandleGameObject(GetGuidData(DATA_GOLEM_DOOR_S), true);
if (Creature* magmus = instance->GetCreature(MagmusGUID))
{
magmus->AI()->Talk(0);
}
ReplaceMoiraIfSaved(); // Need to place the correct final boss, but we need her to be spawned first.
}
break;
case TYPE_IRON_HALL:
encounter[5] = data;
switch (data)
{
case NOT_STARTED:
case IN_PROGRESS:
for (int i = 0; i < 6; i++)
{
if (Creature* ironhand = instance->GetCreature(IronhandGUID[i]))
{
ironhand->AI()->SetData(0, data == IN_PROGRESS);
}
}
break;
case DONE:
HandleGameObject(GetGuidData(DATA_THRONE_DOOR), true);
break;
default:
break;
}
break;
case DATA_OPEN_COFFER_DOORS:
OpenedCoofers += 1;
@@ -492,6 +656,12 @@ public:
return encounter[4];
case TYPE_IRON_HALL:
return encounter[5];
case DATA_TIME_RING_FAIL:
return timeRingFail;
case DATA_ARENA_MOBS:
return arenaMobsToSpawn;
case DATA_ARENA_BOSS:
return arenaBossToSpawn;
}
return 0;
}

View File

@@ -28,9 +28,13 @@ void AddSC_boss_draganthaurissan();
void AddSC_boss_general_angerforge();
void AddSC_boss_gorosh_the_dervish();
void AddSC_boss_grizzle();
void AddSC_boss_eviscerator();
void AddSC_boss_okthor();
void AddSC_boss_hedrum();
void AddSC_boss_high_interrogator_gerstahn();
void AddSC_boss_magmus();
void AddSC_boss_moira_bronzebeard();
void AddSC_boss_high_priestess_thaurissan();
void AddSC_boss_tomb_of_seven();
void AddSC_instance_blackrock_depths();
void AddSC_boss_drakkisath(); //Blackrock Spire
@@ -172,9 +176,13 @@ void AddEasternKingdomsScripts()
AddSC_boss_general_angerforge();
AddSC_boss_gorosh_the_dervish();
AddSC_boss_grizzle();
AddSC_boss_okthor();
AddSC_boss_eviscerator();
AddSC_boss_hedrum();
AddSC_boss_high_interrogator_gerstahn();
AddSC_boss_magmus();
AddSC_boss_moira_bronzebeard();
AddSC_boss_high_priestess_thaurissan();
AddSC_boss_tomb_of_seven();
AddSC_instance_blackrock_depths();
AddSC_boss_drakkisath(); //Blackrock Spire